[6.4.0]工单上报

This commit is contained in:
xuxinchao
2024-04-18 19:52:43 +08:00
parent a376785fa7
commit a98bb6e5b9
26 changed files with 998 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.data.deva.bindingcar.ModifyBindingcarInfo
import com.mogo.eagle.core.data.deva.chain.ChainConstant
import com.mogo.eagle.core.data.deva.chain.ChainLogParam
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.data.deva.scene.SceneModule
import com.mogo.eagle.core.data.deva.scene.SceneTAG
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
@@ -275,6 +276,10 @@ class DevaToolsProvider : IDevaToolsProvider {
sceneManager.updateSceneTAG(sceneTag)
}
override fun reportWorkOrder(view: View) {
BadCaseManager.reportWorkOrder(view)
}
override fun initBadCase(view: View) {
BadCaseManager.initBadCase(view)
}
@@ -443,6 +448,13 @@ class DevaToolsProvider : IDevaToolsProvider {
BindingCarManager.queryContainers(padSn, dockerVersion)
}
/**
* 工单上报接口
*/
override fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo) {
BindingCarManager.workOrderReport(workOrderReportInfo)
}
override fun queryAppUpgrade() {
BindingCarManager.queryAppUpgrade()
}

View File

@@ -53,6 +53,7 @@ import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
import com.zhjt.mogo_core_function_devatools.badcase.util.RecordBitmapUtils
import com.zhjt.mogo_core_function_devatools.ext.enqueuePop
import com.zhjt.mogo_core_function_devatools.workorder.WorkOrderWindow
import me.jessyan.autosize.utils.AutoSizeUtils
import record_cache.RecordPanelOuterClass
import java.io.File
@@ -179,6 +180,36 @@ internal object BadCaseManager : LifecycleEventObserver, IMoGoAutopilotRecordLis
}
}
/**
* 开启工单上报弹窗
*/
fun reportWorkOrder(view: View){
val activity = view.context as? FragmentActivity
?: throw IllegalStateException("please ensure context is FragmentActivity.")
view.setOnClickListener{
if (ClickUtils.isFastClick()){
if (NetworkUtils.isConnected()){
if (BadCaseConfig.dockerVersion != null){
//展示工单上报弹窗
val workOrderWindow = WorkOrderWindow(activity)
workOrderWindow.setClickListener(object: WorkOrderWindow.ClickListener{
override fun closeWindow() {
workOrderWindow.hideFloatWindow()
}
})
workOrderWindow.showFloatWindow()
}else{
ToastUtils.showShort("工控机连接状态异常")
}
}else{
ToastUtils.showShort("网络异常,请检查网络")
}
}else{
ToastUtils.showShort("请勿连续点击,稍后再试")
}
}
}
/**
* 主动采集BadCase
*/

View File

@@ -19,10 +19,12 @@ import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils.isPassenger
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.zhjt.mogo_core_function_devatools.trace.TraceManager
import com.zhjt.mogo_core_function_devatools.upgrade.IPCUpgradeManager.Companion.ipcUpgradeManager
import com.zhjt.mogo_core_function_devatools.upgrade.ObuUpgradeAppNetWorkManager
import com.zhjt.mogo_core_function_devatools.upgrade.UpgradeAppNetWorkManager
import com.zhjt.mogo_core_function_devatools.workorder.WorkOrderManager.Companion.workOrderManager
import mogo.telematics.pad.MessagePad
/**
@@ -58,11 +60,13 @@ object BindingCarManager : IMoGoAutopilotCarConfigListener, IMoGoCloudListener {
CallerAutopilotCarConfigListenerManager.addListener(TAG, this)
CallerCloudListenerManager.addListener(TraceManager.TAG, this)
ipcUpgradeManager.init(context)
workOrderManager.init(context)
}
fun onDestroy() {
CallerAutopilotCarConfigListenerManager.removeListener(TAG)
ipcUpgradeManager.destroy()
workOrderManager.destroy()
}
override fun onAutopilotCarConfig(carConfigResp: MessagePad.CarConfigResp) {
@@ -145,6 +149,13 @@ object BindingCarManager : IMoGoAutopilotCarConfigListener, IMoGoCloudListener {
ipcUpgradeManager.queryContainers(padSn, dockerVersion)
}
/**
* 工单上报接口
*/
fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo){
workOrderManager.workOrderReport(workOrderReportInfo)
}
fun modifyCarInfo(callBack: (ModifyBindingcarInfo) -> Unit) {
BindingCarNetWorkManager.instance.modifyBindingCar(
mAddress,

View File

@@ -0,0 +1,18 @@
package com.zhjt.mogo_core_function_devatools.workorder
import com.mogo.eagle.core.data.Response
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
/**
* 工单上报接口
*/
interface WorkOrderApiService {
@Headers("Content-Type:application/json;charset=UTF-8")
@POST("/api/v1/monitor/yk/manual/callback/?token=eapir6gqq6v9p2m82tzrnj")
suspend fun workOrderReport(@Body workOrderReportInfo: WorkOrderReportInfo): Response<Any>
}

View File

@@ -0,0 +1,26 @@
package com.zhjt.mogo_core_function_devatools.workorder
import com.mogo.commons.debug.DebugConfig
/**
* 工单上报域名管理
*/
class WorkOrderHostConst {
companion object{
private const val HOST_DEV = "http://yw-egateway.zhidaoauto.com"
private const val HOST_RELEASE = "http://yw-egateway.zhidaoauto.com"
fun getWorkOrderBaseUrl(): String{
return when (DebugConfig.getNetMode()){
DebugConfig.NET_MODE_DEV -> HOST_DEV
DebugConfig.NET_MODE_QA -> HOST_DEV
DebugConfig.NET_MODE_DEMO -> HOST_RELEASE
DebugConfig.NET_MODE_RELEASE -> HOST_RELEASE
else -> HOST_RELEASE
}
}
}
}

View File

@@ -0,0 +1,45 @@
package com.zhjt.mogo_core_function_devatools.workorder
import android.content.Context
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsListenerManager
/**
* @author XuXinChao
* @description 人工报障及工单建议呈现
* @since: 2024/4/11
*/
class WorkOrderManager{
companion object{
const val TAG = "WorkOrderManager"
val workOrderManager: WorkOrderManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED){
WorkOrderManager()
}
}
private var mContext: Context? = null
private val workOrderNetWorkModel = WorkOrderNetWorkModel()
fun init(context: Context){
mContext = context
}
/**
* 工单上报
*/
fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo,){
workOrderNetWorkModel.workOrderReport(workOrderReportInfo,
onSuccess = {
CallerDevaToolsListenerManager.invokeWorkOrderReportSuccess()
},
onError = {
CallerDevaToolsListenerManager.invokeWorkOrderReportError()
}
)
}
fun destroy(){
mContext = null
}
}

View File

@@ -0,0 +1,37 @@
package com.zhjt.mogo_core_function_devatools.workorder
import com.mogo.eagle.core.data.Response
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.network.MoGoRetrofitFactory
import com.mogo.eagle.core.network.apiResponseCall
import com.mogo.eagle.core.network.request
import com.zhjt.mogo_core_function_devatools.workorder.WorkOrderHostConst.Companion.getWorkOrderBaseUrl
/**
* 工单上报
*/
class WorkOrderNetWorkModel {
private fun getNetWorkApi(baseUrl: String =getWorkOrderBaseUrl()): WorkOrderApiService {
return MoGoRetrofitFactory.getInstanceNoCallAdapter(baseUrl)
.create(WorkOrderApiService::class.java)
}
fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo,
onSuccess: ((String) -> Unit), onError: ((String) -> Unit)){
request<Response<Any>>{
loader{
apiResponseCall{
getNetWorkApi(getWorkOrderBaseUrl()).workOrderReport(workOrderReportInfo)
}
}
onSuccess{
onSuccess.invoke("")
}
onError{
onError.invoke("")
}
}
}
}

View File

@@ -0,0 +1,408 @@
package com.zhjt.mogo_core_function_devatools.workorder
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.PixelFormat
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.DisplayMetrics
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.ScaleAnimation
import android.widget.ImageView
import android.widget.RadioGroup
import android.widget.TextView
import androidx.appcompat.widget.AppCompatEditText
import com.iflytek.cloud.ErrorCode
import com.iflytek.cloud.InitListener
import com.iflytek.cloud.RecognizerListener
import com.iflytek.cloud.RecognizerResult
import com.iflytek.cloud.SpeechError
import com.iflytek.cloud.SpeechRecognizer
import com.mogo.commons.storage.SharedPrefsMgr
import com.mogo.eagle.core.data.app.AppConfigInfo
import com.mogo.eagle.core.data.deva.report.FaultDetailInfo
import com.mogo.eagle.core.data.deva.report.FaultInfo
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.data.msgbox.FMInfoMsg
import com.mogo.eagle.core.function.api.devatools.IMoGoDevaToolsListener
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsListenerManager
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
import com.mogo.eagle.core.utilcode.util.BarUtils
import com.mogo.eagle.core.utilcode.util.JsonParser
import com.mogo.eagle.core.utilcode.util.TimeUtils
import com.mogo.eagle.core.utilcode.util.TimeUtils.millis2String
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.tts.base.SpeechUtils
import com.zhjt.mogo_core_function_devatools.R
import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONException
import org.json.JSONObject
import kotlin.math.absoluteValue
/**
* 工单上报弹窗
*/
class WorkOrderWindow constructor(activity: Activity) : View.OnTouchListener,
IMoGoDevaToolsListener {
companion object{
const val TAG = "WorkOrderWindow"
}
private var mActivity: Activity = activity
private var mWindowParams: WindowManager.LayoutParams? = null
private var mWindowManager: WindowManager? = null
private lateinit var mFloatLayout: View
private var clickListener: ClickListener? = null
private var mInViewX = 0f
private var mInViewY = 0f
private var mInScreenX = 0f
private var mInScreenY = 0f
// 语音听写对象
private var mIat: SpeechRecognizer? = null
private var reasonDetail: String = "" //语音转写
// 用HashMap存储听写结果
private val mIatResults: HashMap<String, String> = LinkedHashMap()
private var workOrderType = "" //工单问题类型
private var workOrderOccurrenceTime = System.currentTimeMillis() //故障发生时间
var ret = 0 // 函数调用返回值
private var audioStatus = false
private lateinit var tvWorkOrderTime: TextView
private lateinit var rgType: RadioGroup
private lateinit var ivTimeReduce: ImageView
private lateinit var tvOccurrenceTime: TextView
private lateinit var ivTimeAdd: ImageView
private lateinit var etDescribeInput: AppCompatEditText
private lateinit var ivDescribeAudio: ImageView
private lateinit var tvWorkOrderReport: TextView
private lateinit var tvWorkOrderCancel: TextView
init {
initFloatWindow()
}
@SuppressLint("InflateParams")
private fun initFloatWindow(){
mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.view_work_order, null) as View
mFloatLayout.setOnTouchListener(this)
// 初始化识别无UI识别对象
// 使用SpeechRecognizer对象可根据回调消息自定义界面
mIat = SpeechRecognizer.createRecognizer(mActivity, mInitListener)
tvWorkOrderTime = mFloatLayout.findViewById(R.id.tv_work_order_time)
rgType = mFloatLayout.findViewById(R.id.rg_type)
ivTimeReduce = mFloatLayout.findViewById(R.id.iv_time_reduce)
tvOccurrenceTime = mFloatLayout.findViewById(R.id.tv_occurrence_time)
ivTimeAdd = mFloatLayout.findViewById(R.id.iv_time_add)
etDescribeInput = mFloatLayout.findViewById(R.id.et_describe_input)
ivDescribeAudio = mFloatLayout.findViewById(R.id.iv_describe_audio)
tvWorkOrderReport = mFloatLayout.findViewById(R.id.tv_work_order_report)
tvWorkOrderCancel = mFloatLayout.findViewById(R.id.tv_work_order_cancel)
initEvent()
mWindowParams = WindowManager.LayoutParams()
mWindowManager = mActivity.windowManager
mWindowParams?.let {
it.format = PixelFormat.RGBA_8888
// it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
it.gravity = Gravity.START or Gravity.TOP
it.width = 844
it.height = 808
it.alpha = 1.0f
}
}
@OptIn(DelicateCoroutinesApi::class)
@SuppressLint("SetTextI18n")
private fun initEvent(){
CallerDevaToolsListenerManager.addListener(TAG, this)
//弹窗展示时间
tvWorkOrderTime.text = mActivity.resources.getString(R.string.work_order_time) +
millis2String(System.currentTimeMillis(), TimeUtils.getHourMinSecondFormat())
rgType.setOnCheckedChangeListener{_, checkedId ->
when(checkedId){
R.id.rb_type_perception->{
workOrderType = "感知"
}
R.id.rb_type_hardware->{
workOrderType = "硬件"
}
R.id.rb_type_vehicle->{
workOrderType = "原车"
}
R.id.rb_type_service->{
workOrderType = "服务"
}
R.id.rb_type_other->{
workOrderType = "其他"
}
}
}
//发生时间
tvOccurrenceTime.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
ivTimeReduce.setOnClickListener {
workOrderOccurrenceTime -= 60000
tvOccurrenceTime.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
}
ivTimeAdd.setOnClickListener {
if(workOrderOccurrenceTime + 60000 > System.currentTimeMillis()){
ToastUtils.showShort("发生时间应在当前时间之前")
return@setOnClickListener
}
workOrderOccurrenceTime += 60000
tvOccurrenceTime.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
}
etDescribeInput.requestFocus()
// val inputMethodManager = mActivity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
// inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED,0)
etDescribeInput.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
}
})
//问题描述录音
ivDescribeAudio.setOnClickListener {
audioStatus = !audioStatus
setAudio(audioStatus)
}
//上报
tvWorkOrderReport.setOnClickListener {
//工单问题类型必选,没有选择,进行提示
if(workOrderType.isEmpty()){
ToastUtils.showShort("请选择问题类型")
return@setOnClickListener
}
if(etDescribeInput.text.toString().isEmpty()){
ToastUtils.showShort("请填写问题描述")
return@setOnClickListener
}
GlobalScope.launch(Dispatchers.IO){
val msgBoxList = CallerMsgBoxManager.queryFMInfoList(mActivity,
workOrderOccurrenceTime-120000,workOrderOccurrenceTime+120000)
val faultList = ArrayList<FaultInfo>()
msgBoxList?.forEach { msgBoxBean ->
val fmInfoMsg = msgBoxBean.bean as FMInfoMsg
fmInfoMsg.fmInfoList?.forEach { fault ->
val faultBean = FaultInfo(false,fault.faultId,fault.faultName,
fault.faultTime.toString(), FaultDetailInfo(fault.faultDesc))
faultList.add(faultBean)
}
}
val workOrderReportInfo = WorkOrderReportInfo(workOrderType,workOrderOccurrenceTime.toString(),
etDescribeInput.text.toString(),CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().longitude.toString(),
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().latitude.toString(),
AppConfigInfo.plateNumber, SharedPrefsMgr.getInstance().getString("och_account","") ,
BadCaseConfig.dockerVersion ?:"",faultList)
CallerDevaToolsManager.workOrderReport(workOrderReportInfo)
}
}
//取消
tvWorkOrderCancel.setOnClickListener {
clickListener?.closeWindow()
}
}
private fun setAudio(status: Boolean){
if(status){
//开始录音
mIat?.let {
//清空之前的内容
mIatResults.clear()
SpeechUtils.setParam(it)
// 不显示听写对话框
ret = it.startListening(mRecognizerListener)
if (ret != ErrorCode.SUCCESS) {
ToastUtils.showShort("听写失败,错误码:$ret,请点击网址https://www.xfyun.cn/document/error-code查询解决方案")
}
}
//开始录音,展示放大缩小动效
val scaleAnimation = ScaleAnimation(
1.0f, 0.8f, 1.0f, 0.8f,
Animation.RELATIVE_TO_SELF, 0.8f, Animation.RELATIVE_TO_SELF, 0.8f
)
scaleAnimation.duration = 1000
scaleAnimation.repeatCount = -1
ivDescribeAudio.startAnimation(scaleAnimation)
}else{
//停止语音听写
mIat?.stopListening()
//结束动画
ivDescribeAudio.clearAnimation()
}
}
/**
* 初始化监听器。
*/
private val mInitListener = InitListener { code ->
if (code != ErrorCode.SUCCESS) {
ToastUtils.showShort("讯飞语音听写初始化失败,错误码:$code")
}
}
/**
* 听写监听器。
*/
private val mRecognizerListener: RecognizerListener = object : RecognizerListener{
override fun onVolumeChanged(p0: Int, p1: ByteArray?) {
//showTip("当前正在说话,音量大小 = " + volume + " 返回音频数据 = " + data.length);
}
override fun onBeginOfSpeech() {
// 此回调表示sdk内部录音机已经准备好了用户可以开始语音输入
}
override fun onEndOfSpeech() {
// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入
}
override fun onResult(results: RecognizerResult?, isLast: Boolean) {
results?.let {
printResult(it)
}
}
override fun onError(p0: SpeechError?) {
// Tips
// 错误码10118(您没有说话),可能是录音机权限被禁,需要提示用户打开应用的录音权限。
}
override fun onEvent(p0: Int, p1: Int, p2: Int, p3: Bundle?) {
// 以下代码用于获取与云端的会话id当业务出错时将会话id提供给技术支持人员可用于查询会话日志定位出错原因
// 若使用本地能力会话id为null
// if (SpeechEvent.EVENT_SESSION_ID == eventType) {
// String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID);
// Log.d(TAG, "session id =" + sid);
// }
}
}
/**
* 显示结果
*/
private fun printResult(results: RecognizerResult) {
val text: String = JsonParser.parseIatResult(results.resultString)
var sn: String? = null
// 读取json结果中的sn字段
try {
val resultJson = JSONObject(results.resultString)
sn = resultJson.optString("sn")
} catch (e: JSONException) {
e.printStackTrace()
}
mIatResults[sn!!] = text
val resultBuffer = java.lang.StringBuilder()
for (key in mIatResults.keys) {
resultBuffer.append(mIatResults[key])
}
Log.i(TAG, "语音内容=$resultBuffer")
reasonDetail = resultBuffer.toString()
if(reasonDetail.isNotEmpty()){
etDescribeInput.setText(reasonDetail)
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean {
when (motionEvent?.action) {
MotionEvent.ACTION_DOWN -> {
// 获取相对View的坐标即以此View左上角为原点
mInViewX = motionEvent.x
mInViewY = motionEvent.y
// 获取相对屏幕的坐标,即以屏幕左上角为原点
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY
}
MotionEvent.ACTION_MOVE -> {
// 更新浮动窗口位置参数
mInScreenX = motionEvent.rawX
mInScreenY = motionEvent.rawY
if(((mInScreenX - mInViewX)-mWindowParams!!.x).absoluteValue>150 || ((mInScreenY - mInViewY)-mWindowParams!!.y).absoluteValue>150){
return true
}
mWindowParams!!.x = (mInScreenX - mInViewX).toInt()
mWindowParams!!.y = (mInScreenY - mInViewY).toInt()
// 手指移动的时候更新小悬浮窗的位置
mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams)
}
}
return true
}
fun showFloatWindow() {
if (mFloatLayout.parent == null) {
val metrics = DisplayMetrics()
// 默认固定位置,靠屏幕右边缘的中间
mWindowManager!!.defaultDisplay.getMetrics(metrics)
mWindowParams!!.x = metrics.widthPixels-890
mWindowParams!!.y = metrics.heightPixels - BarUtils.getStatusBarHeight()-1140
mWindowManager!!.addView(mFloatLayout, mWindowParams)
}
}
fun hideFloatWindow() {
if (mFloatLayout.parent != null){
mWindowManager!!.removeView(mFloatLayout)
}
CallerDevaToolsListenerManager.removeListener(TAG)
}
override fun workOrderReportSuccess() {
ToastUtils.showShort("工单上报成功")
hideFloatWindow()
}
override fun workOrderReportError() {
ToastUtils.showShort("工单上报失败")
}
fun setClickListener(clickListener: ClickListener) {
this.clickListener = clickListener
}
interface ClickListener {
fun closeWindow()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="@dimen/dp_2" android:bottom="@dimen/dp_2"
android:left="@dimen/dp_2" android:right="@dimen/dp_2">
<shape>
<solid android:color="#0056FF"/>
<corners android:radius="@dimen/dp_8"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:useLevel="false"
>
<!--内部填充-->
<solid android:color="#1AA7B6F0" />
<stroke
android:width="@dimen/dp_1"
android:color="#A7B6F0"
/>
<corners android:radius="@dimen/dp_8"/>
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/type_radio_button_unselect"
android:state_checked="false"/>
<item
android:drawable="@drawable/type_radio_button_select"
android:state_checked="true"/>
</selector>

View File

@@ -0,0 +1,269 @@
<?xml version="1.0" encoding="utf-8"?>
<com.mogo.eagle.core.widget.RoundConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/dp_844"
android:layout_height="@dimen/dp_808"
app:roundLayoutRadius="@dimen/dp_36"
android:background="#111825">
<View
android:id="@+id/view_title_bg"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_102"
android:background="@drawable/icon_work_order_title"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/tv_report_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/work_order_report_title"
android:textSize="@dimen/sp_34"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/view_title_bg"
app:layout_constraintBottom_toBottomOf="@id/view_title_bg"
app:layout_constraintStart_toStartOf="@id/view_title_bg"
android:layout_marginStart="@dimen/dp_33"
/>
<TextView
android:id="@+id/tv_work_order_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/work_order_time"
android:textColor="@color/white"
android:textSize="@dimen/sp_30"
app:layout_constraintTop_toTopOf="@id/view_title_bg"
app:layout_constraintBottom_toBottomOf="@id/view_title_bg"
app:layout_constraintEnd_toEndOf="@id/view_title_bg"
android:layout_marginEnd="@dimen/dp_31"
/>
<View
android:id="@+id/view_type_label"
android:layout_width="@dimen/dp_6"
android:layout_height="@dimen/dp_29"
android:background="#FF0176FF"
app:layout_constraintTop_toBottomOf="@id/view_title_bg"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="@dimen/dp_33"
android:layout_marginTop="@dimen/dp_32"
/>
<TextView
android:id="@+id/tv_type_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/work_order_type"
android:textSize="@dimen/sp_32"
android:textColor="@color/white"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/view_type_label"
app:layout_constraintBottom_toBottomOf="@id/view_type_label"
app:layout_constraintLeft_toRightOf="@id/view_type_label"
android:layout_marginStart="@dimen/dp_13"
/>
<RadioGroup
android:id="@+id/rg_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/view_type_label"
android:layout_marginTop="@dimen/dp_30"
android:layout_marginStart="@dimen/dp_33"
android:layout_marginEnd="@dimen/dp_33"
>
<RadioButton
android:id="@+id/rb_type_perception"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_70"
android:text="@string/work_order_type_perception"
style="@style/work_order_type_radio_style"
/>
<RadioButton
android:id="@+id/rb_type_hardware"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_70"
android:text="@string/work_order_type_hardware"
style="@style/work_order_type_radio_style"
/>
<RadioButton
android:id="@+id/rb_type_vehicle"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_70"
android:text="@string/work_order_type_vehicle"
style="@style/work_order_type_radio_style"
/>
<RadioButton
android:id="@+id/rb_type_service"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_70"
android:text="@string/work_order_type_service"
style="@style/work_order_type_radio_style"
/>
<RadioButton
android:id="@+id/rb_type_other"
android:layout_width="@dimen/dp_0"
android:layout_height="@dimen/dp_70"
android:text="@string/work_order_type_other"
style="@style/work_order_type_radio_style"
/>
</RadioGroup>
<View
android:id="@+id/view_time_label"
android:layout_width="@dimen/dp_6"
android:layout_height="@dimen/dp_29"
android:background="#FF0176FF"
app:layout_constraintTop_toBottomOf="@id/rg_type"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="@dimen/dp_33"
android:layout_marginTop="@dimen/dp_32"
/>
<TextView
android:id="@+id/tv_time_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/work_order_occurrence_time"
android:textColor="@color/white"
android:textSize="@dimen/sp_32"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/view_time_label"
app:layout_constraintBottom_toBottomOf="@id/view_time_label"
app:layout_constraintLeft_toRightOf="@id/view_time_label"
android:layout_marginStart="@dimen/dp_13"
/>
<ImageView
android:id="@+id/iv_time_reduce"
android:layout_width="@dimen/dp_72"
android:layout_height="@dimen/dp_72"
android:src="@drawable/icon_work_order_reduce"
app:layout_constraintLeft_toLeftOf="@id/view_time_label"
app:layout_constraintTop_toBottomOf="@id/view_time_label"
android:layout_marginTop="@dimen/dp_30"
/>
<TextView
android:id="@+id/tv_occurrence_time"
android:layout_width="@dimen/dp_150"
android:layout_height="@dimen/dp_72"
android:textSize="@dimen/sp_30"
android:textColor="@color/white"
android:gravity="center"
android:background="#1AA7B6F0"
app:layout_constraintTop_toTopOf="@id/iv_time_reduce"
app:layout_constraintBottom_toBottomOf="@id/iv_time_reduce"
app:layout_constraintStart_toEndOf="@id/iv_time_reduce"
/>
<ImageView
android:id="@+id/iv_time_add"
android:layout_width="@dimen/dp_72"
android:layout_height="@dimen/dp_72"
android:src="@drawable/icon_work_order_add"
app:layout_constraintTop_toTopOf="@id/tv_occurrence_time"
app:layout_constraintBottom_toBottomOf="@id/tv_occurrence_time"
app:layout_constraintStart_toEndOf="@id/tv_occurrence_time"
/>
<View
android:id="@+id/view_describe_label"
android:layout_width="@dimen/dp_6"
android:layout_height="@dimen/dp_29"
android:background="#FF0176FF"
app:layout_constraintTop_toBottomOf="@id/iv_time_reduce"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="@dimen/dp_33"
android:layout_marginTop="@dimen/dp_32"
/>
<TextView
android:id="@+id/tv_describe_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/work_order_describe"
android:textColor="@color/white"
android:textSize="@dimen/sp_32"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/view_describe_label"
app:layout_constraintBottom_toBottomOf="@id/view_describe_label"
app:layout_constraintStart_toEndOf="@id/view_describe_label"
android:layout_marginStart="@dimen/dp_13"
/>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/et_describe_input"
android:layout_width="@dimen/dp_779"
android:layout_height="@dimen/dp_115"
app:layout_constraintTop_toBottomOf="@id/view_describe_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:hint="@string/work_order_describe_input"
android:textColorHint="#A3ABC0"
android:textSize="@dimen/sp_27"
android:textColor="@color/white"
android:gravity="top|start"
android:paddingStart="@dimen/dp_28"
android:paddingTop="@dimen/dp_33"
android:layout_marginTop="@dimen/dp_30"
android:background="@drawable/bg_work_order_des_input"
android:inputType="text"
/>
<ImageView
android:id="@+id/iv_describe_audio"
android:layout_width="@dimen/dp_45"
android:layout_height="@dimen/dp_59"
android:src="@drawable/icon_work_order_audio"
app:layout_constraintTop_toTopOf="@id/et_describe_input"
app:layout_constraintBottom_toBottomOf="@id/et_describe_input"
app:layout_constraintEnd_toEndOf="@id/et_describe_input"
android:layout_marginEnd="@dimen/dp_30"
/>
<TextView
android:id="@+id/tv_work_order_report"
android:layout_width="@dimen/dp_370"
android:layout_height="@dimen/dp_80"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_work_order_cancel"
android:background="@drawable/report_button_bg"
android:text="@string/work_order_report"
android:textColor="#FFFFFF"
android:textSize="@dimen/sp_27"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="@dimen/dp_40"
/>
<TextView
android:id="@+id/tv_work_order_cancel"
android:layout_width="@dimen/dp_370"
android:layout_height="@dimen/dp_80"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv_work_order_report"
android:text="@string/work_order_cancel"
android:textColor="#FFFFFF"
android:textSize="@dimen/sp_27"
android:textStyle="bold"
android:gravity="center"
android:background="@drawable/icon_cancel_bg"
android:layout_marginBottom="@dimen/dp_40"
/>
</com.mogo.eagle.core.widget.RoundConstraintLayout>

View File

@@ -1,4 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="work_order_report_title">问题上报</string>
<string name="work_order_type">问题类型</string>
<string name="work_order_occurrence_time">发生时间</string>
<string name="work_order_describe">问题描述</string>
<string name="work_order_describe_input">手动输入</string>
<string name="work_order_report">上报</string>
<string name="work_order_cancel">取消</string>
<string name="work_order_time">时间:</string>
<string name="work_order_type_perception">感知</string>
<string name="work_order_type_hardware">硬件</string>
<string name="work_order_type_vehicle">原车</string>
<string name="work_order_type_service">服务</string>
<string name="work_order_type_other">其他</string>
</resources>

View File

@@ -16,5 +16,15 @@
<item name="android:scrollbarTrackVertical">@drawable/rv_scroll_bar_track</item>
</style>
<style name="work_order_type_radio_style">
<item name="android:button">@null</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@color/white</item>
<item name="android:textSize">@dimen/sp_30</item>
<item name="android:background">@drawable/work_order_type_radio_button</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_margin">@dimen/dp_8</item>
</style>
</resources>

View File

@@ -0,0 +1,18 @@
package com.mogo.eagle.core.data.deva.report
/**
* 故障内容实体类
* @param isRecover 恢复逻辑,标记这条报警是恢复还是报警条目
* @param faultId 故障Id
* @param faultName 故障名称
* @param startTime 报警时间
* @param detail 报警内容
*/
data class FaultInfo(var isRecover: Boolean = false,var faultId: String,var faultName: String,
var startTime:String,var detail: FaultDetailInfo)
/**
* 报警内容实体类
* @param info 故障描述
*/
data class FaultDetailInfo(var info: String)

View File

@@ -0,0 +1,17 @@
package com.mogo.eagle.core.data.deva.report
/**
* 人工报障上报实体类
* @param type 问题类型:感知、硬件、原车、服务、其他
* @param reportTime 上报时间
* @param describe 上报描述
* @param longitude 经度
* @param latitude 纬度
* @param plateNumber 车牌号实际上 就是cmdb中的sn
* @param phoneNumber 安全员联系方式
* @param map map版本
* @param faultList FM上报故障列表
*/
data class WorkOrderReportInfo(var type: String,var reportTime: String,var describe: String,
var longitude: String,var latitude: String,var plateNumber: String,
var phoneNumber: String,var map: String,var faultList: ArrayList<FaultInfo>)

View File

@@ -8,6 +8,7 @@ import com.alibaba.android.arouter.facade.template.IProvider
import com.mogo.eagle.core.data.EnvConfig
import com.mogo.eagle.core.data.deva.bindingcar.ModifyBindingcarInfo
import com.mogo.eagle.core.data.deva.chain.ChainLogParam
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.data.deva.scene.SceneModule
import com.mogo.eagle.core.data.deva.scene.SceneTAG
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
@@ -96,6 +97,8 @@ interface IDevaToolsProvider : IProvider {
*/
fun updateSceneTAG(sceneTag: MutableMap<String, SceneTAG>)
fun reportWorkOrder(view: View)
/**
* 初始化BadCase入口
* @param view: BadCase入口视图
@@ -232,6 +235,11 @@ interface IDevaToolsProvider : IProvider {
*/
fun queryContainers(padSn: String, dockerVersion: String)
/**
* 工单上报接口
*/
fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo)
/**
* 查询app是否有更新
*/

View File

@@ -51,6 +51,10 @@ interface IMoGoDevaToolsListener {
}
fun workOrderReportSuccess(){}
fun workOrderReportError(){}
fun mofangStatus(status:Boolean){
}

View File

@@ -64,6 +64,20 @@ object CallerDevaToolsListenerManager : CallerBase<IMoGoDevaToolsListener>() {
}
}
fun invokeWorkOrderReportSuccess(){
M_LISTENERS.forEach{
val listener = it.value
listener.workOrderReportSuccess()
}
}
fun invokeWorkOrderReportError(){
M_LISTENERS.forEach{
val listener = it.value
listener.workOrderReportError()
}
}
fun invokeMoFangStatus(status:Boolean){
M_LISTENERS.forEach {
val listener = it.value

View File

@@ -9,6 +9,7 @@ import com.mogo.eagle.core.data.deva.bindingcar.ModifyBindingcarInfo
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.constants.MogoServicePaths
import com.mogo.eagle.core.data.deva.chain.ChainLogParam
import com.mogo.eagle.core.data.deva.report.WorkOrderReportInfo
import com.mogo.eagle.core.data.deva.scene.SceneModule
import com.mogo.eagle.core.data.deva.scene.SceneTAG
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
@@ -128,6 +129,13 @@ object CallerDevaToolsManager {
devaToolsProviderApi?.updateSceneTAG(sceneTag)
}
/**
* 开启上报工单
*/
fun reportWorkOrder(view: View){
devaToolsProviderApi?.reportWorkOrder(view)
}
/**
* 初始化BadCase相关配置
*/
@@ -320,6 +328,13 @@ object CallerDevaToolsManager {
devaToolsProviderApi?.queryContainers(padSn, dockerVersion)
}
/**
* 工单上报接口
*/
fun workOrderReport(workOrderReportInfo: WorkOrderReportInfo){
devaToolsProviderApi?.workOrderReport(workOrderReportInfo)
}
fun dockerVersion(dockerVersion: String?){
devaToolsProviderApi?.dockerVersion(dockerVersion)
}

View File

@@ -1057,6 +1057,8 @@
<dimen name="sp_23">23dp</dimen>
<dimen name="sp_24">24dp</dimen>
<dimen name="sp_25">25dp</dimen>
<dimen name="sp_26">26dp</dimen>
<dimen name="sp_27">27dp</dimen>
<dimen name="sp_28">28dp</dimen>
<dimen name="sp_30">30dp</dimen>
<dimen name="sp_32">32dp</dimen>