diff --git a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/bg_fault_type.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/bg_fault_type.xml
index cb1fa5e3d6..49cdb10ffd 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/bg_fault_type.xml
+++ b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/bg_fault_type.xml
@@ -5,11 +5,11 @@
>
-
+
diff --git a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_select.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_select.xml
index a97b69d909..e086586d69 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_select.xml
+++ b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_select.xml
@@ -1,5 +1,10 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_unselect.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_unselect.xml
index cb1fa5e3d6..a286173cf9 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_unselect.xml
+++ b/core/function-impl/mogo-core-function-devatools/src/main/res/drawable/type_radio_button_unselect.xml
@@ -5,13 +5,8 @@
>
-
+
-
-
-
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-devatools/src/main/res/values/strings.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/values/strings.xml
index 0df48d8bae..5e8778d45d 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/res/values/strings.xml
+++ b/core/function-impl/mogo-core-function-devatools/src/main/res/values/strings.xml
@@ -4,7 +4,7 @@
问题上报
问题类型
发生时间
- 问题描述
+ 补充描述
手动输入
上报
取消
diff --git a/core/function-impl/mogo-core-function-devatools/src/main/res/values/styles.xml b/core/function-impl/mogo-core-function-devatools/src/main/res/values/styles.xml
index a64bbda71e..57c57a86d2 100644
--- a/core/function-impl/mogo-core-function-devatools/src/main/res/values/styles.xml
+++ b/core/function-impl/mogo-core-function-devatools/src/main/res/values/styles.xml
@@ -23,7 +23,6 @@
- @dimen/sp_30
- @drawable/work_order_type_radio_button
- 1
- - @dimen/dp_8
diff --git a/core/function-impl/mogo-core-function-hmi/build.gradle b/core/function-impl/mogo-core-function-hmi/build.gradle
index 2fdc51ba08..8cd10480ce 100644
--- a/core/function-impl/mogo-core-function-hmi/build.gradle
+++ b/core/function-impl/mogo-core-function-hmi/build.gradle
@@ -79,6 +79,7 @@ dependencies {
implementation rootProject.ext.dependencies.koomxhook
implementation rootProject.ext.dependencies.preference
implementation rootProject.ext.dependencies.preference_ktx
+ implementation rootProject.ext.dependencies.amapsearch
implementation rootProject.ext.dependencies.thread_opt
api project(':test:crashreport-apmbyte')
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/BoneTabLayout.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/BoneTabLayout.kt
index be956276d5..2bb25033ac 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/BoneTabLayout.kt
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/BoneTabLayout.kt
@@ -8,16 +8,20 @@ import com.mogo.eagle.core.data.enums.Carmodel
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxEventListener
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxEventListenerManager
import com.mogo.eagle.core.function.hmi.R
+import com.mogo.eagle.core.function.hmi.bone.tab.ReportTypeView
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import kotlinx.android.synthetic.main.view_bone_tab.view.carInfoTabView
+import kotlinx.android.synthetic.main.view_bone_tab.view.faultReasonView
import kotlinx.android.synthetic.main.view_bone_tab.view.msgBoxTabView
+import kotlinx.android.synthetic.main.view_bone_tab.view.reportTypeView
import kotlinx.android.synthetic.main.view_bone_tab.view.tabSwitchCarInfo
import kotlinx.android.synthetic.main.view_bone_tab.view.tabSwitchMore
import kotlinx.android.synthetic.main.view_bone_tab.view.tabSwitchMsgBox
import kotlinx.android.synthetic.main.view_bone_tab.view.tabSwitchReport
import kotlinx.android.synthetic.main.view_bone_tab.view.toolKitTabView
+import kotlinx.android.synthetic.main.view_bone_tab.view.workOrderView
import kotlin.properties.Delegates
class BoneTabLayout @JvmOverloads constructor(
@@ -83,6 +87,15 @@ class BoneTabLayout @JvmOverloads constructor(
logOut?.invoke()
}
+ reportTypeView.setClickListener(object: ReportTypeView.ClickListener{
+ override fun openFaultReasonView() {
+ faultReasonView.visibility = VISIBLE
+ }
+ override fun openWorkOrderView() {
+ workOrderView.visibility = VISIBLE
+ }
+ })
+
}
fun setCarNo(carNo: String?) {
@@ -132,9 +145,10 @@ class BoneTabLayout @JvmOverloads constructor(
TabType.REPORT_INFO -> {
tabSwitchReport.switchTab(check)
if (check) {
-
+ reportTypeView.visibility = VISIBLE
+ reportTypeView.showTypeSelectView()
} else {
-
+ reportTypeView.visibility = GONE
}
}
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/FaultReasonView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/FaultReasonView.kt
new file mode 100644
index 0000000000..9b5ca28692
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/FaultReasonView.kt
@@ -0,0 +1,497 @@
+package com.mogo.eagle.core.function.hmi.bone.tab
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.text.Editable
+import android.text.TextWatcher
+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 android.util.AttributeSet
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.animation.Animation
+import android.view.animation.ScaleAnimation
+import android.widget.EditText
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.amap.api.services.core.LatLonPoint
+import com.amap.api.services.geocoder.GeocodeResult
+import com.amap.api.services.geocoder.GeocodeSearch
+import com.amap.api.services.geocoder.RegeocodeQuery
+import com.amap.api.services.geocoder.RegeocodeResult
+import com.mogo.commons.storage.SharedPrefsMgr
+import com.mogo.eagle.core.data.app.AppConfigInfo
+import com.mogo.eagle.core.data.deva.report.CategoryInfo
+import com.mogo.eagle.core.data.deva.report.PadAddProblemReq
+import com.mogo.eagle.core.data.deva.report.PadProblemInfo
+import com.mogo.eagle.core.function.api.devatools.IMoGoDevaToolsListener
+import com.mogo.eagle.core.function.api.order.IOrderListener
+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.order.CallerOrderListenerManager
+import com.mogo.eagle.core.function.hmi.R
+import com.mogo.eagle.core.utilcode.util.JsonParser
+import com.mogo.eagle.core.utilcode.util.ThreadUtils
+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.badcase.consts.BadCaseConfig
+import com.zhjt.mogo_core_function_devatools.workorder.adapter.OrderReasonAdapter
+import kotlinx.android.synthetic.main.view_fault_reason.view.etNoteInput
+import kotlinx.android.synthetic.main.view_fault_reason.view.faultReasonGroup
+import kotlinx.android.synthetic.main.view_fault_reason.view.ivNoteAudio
+import kotlinx.android.synthetic.main.view_fault_reason.view.ivTimeAdd
+import kotlinx.android.synthetic.main.view_fault_reason.view.ivTimeReduce
+import kotlinx.android.synthetic.main.view_fault_reason.view.rvFaultList
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvFaultCancel
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvFaultReason
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvFaultReport
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvFaultTime
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvFaultType
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvOccurrenceTime
+import kotlinx.android.synthetic.main.view_fault_reason.view.tvUploadSuccess
+
+/**
+ * 故障原因编辑视图
+ */
+class FaultReasonView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoDevaToolsListener, IOrderListener {
+
+ private val TAG = "FaultReasonView"
+
+ // 语音听写对象
+ private var mIat: SpeechRecognizer? = null
+ // 用HashMap存储听写结果
+ private val mIatResults: HashMap = LinkedHashMap()
+
+ var ret = 0 // 函数调用返回值
+ private var audioStatus = false
+
+ private var workOrderOccurrenceTime = System.currentTimeMillis() //故障发生时间
+
+ private var clickListener: ClickListener? = null
+
+ private lateinit var orderReasonAdapter: OrderReasonAdapter
+
+ private var address: String = "" //故障地点
+ private var faultCodeList = ArrayList() //故障码列表
+ private var level1Id: Int = 0 //一级分类ID
+ private var level2Id: Int = 0 //二级分类ID
+ private var level3Id: Int = 0 //三级分类ID
+ private var level1Name: String = ""
+ private var level2Name: String = ""
+ private var level3Name: String = ""
+ private var reportNote: String = "" //上报描述
+ private val reportType: Int = 1 //上报方式:0:小程序 1:司机屏 2:云端上报
+
+ private var source: Int = 0 //操作源,0:默认,一级分类 1:类型,二级分类;2:原因,三级分类
+ private var hasLevel2: Boolean = false //是否有二级分类
+ private var hasLevel3: Boolean = false //是否有三级分类
+
+ private var typeList: List ?= null //故障类型列表
+ private var reasonList: List ?= null //故障原因列表
+
+ private var faultTypeSelectStatus: Boolean = false //故障类型选择状态
+ private var faultReasonSelectStatus: Boolean = false //故障原因选择状态
+
+ private val type = 1 //故障类接口请求Type值为1
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.view_fault_reason, this, true)
+ initView()
+ initEvent()
+ }
+
+ private fun initView(){
+ // 初始化识别无UI识别对象
+ // 使用SpeechRecognizer对象,可根据回调消息自定义界面;
+ mIat = SpeechRecognizer.createRecognizer(context, mInitListener)
+ val linearLayoutManager = LinearLayoutManager(context)
+ linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
+ rvFaultList.layoutManager = linearLayoutManager
+ orderReasonAdapter = OrderReasonAdapter()
+ orderReasonAdapter.setListener(object: OrderReasonAdapter.ReasonSelectListener{
+ override fun onSelectReason(reason: CategoryInfo, mSource: Int) {
+ if(mSource == 1){
+ //类型
+ tvFaultType.text = reason.name
+ //选择了故障类型
+ tvFaultType.performClick()
+ if(level2Id != 0 && level2Id == reason.id){
+ //故障类型选择没有变化
+ reasonList?.let { orderReasonAdapter.setData(it,2) }
+ }else{
+ //故障类型发生了变化
+ level2Id = reason.id
+ level2Name = reason.name
+ source = 2
+ //获取故障三级分类即故障原因
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,3,level2Id,type,0)
+ tvFaultReason.text = ""
+ level3Id = 0
+ level3Name = ""
+ }
+ }else{
+ //原因
+ tvFaultReason.text = reason.name
+ tvFaultReason.performClick()
+ level3Id = reason.id
+ level3Name = reason.name
+ }
+ }
+ })
+ rvFaultList.adapter = orderReasonAdapter
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun initEvent(){
+ CallerDevaToolsListenerManager.addListener(TAG, this)
+ CallerOrderListenerManager.addListener(TAG,this)
+ val iconDown = ContextCompat.getDrawable(context, R.drawable.icon_fault_expand)
+ iconDown?.setBounds(0, 0, iconDown.minimumWidth, iconDown.minimumHeight)
+ val iconUp = ContextCompat.getDrawable(context, R.drawable.icon_fault_retract)
+ iconUp?.setBounds(0, 0, iconUp.minimumWidth, iconUp.minimumHeight)
+ //获取一级分类
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,1,0,type,0)
+ //弹窗展示时间
+ tvFaultTime.text = millis2String(System.currentTimeMillis(), TimeUtils.getHourMinSecondFormat())
+ //故障类型选择
+ tvFaultType.setOnClickListener {
+ if(!hasLevel2){
+ ToastUtils.showShort("运营后台没有配置故障类型")
+ return@setOnClickListener
+ }
+ if(faultTypeSelectStatus){
+ //关闭
+ faultTypeSelectStatus = false
+ tvFaultType.setCompoundDrawables(null, null, iconDown, null)
+ //隐藏列表
+ rvFaultList.visibility = View.GONE
+ }else{
+ //如果故障原因此时为打开状态,则关闭
+ if(faultReasonSelectStatus){
+ tvFaultReason.performClick()
+ }
+ //打开
+ faultTypeSelectStatus = true
+ tvFaultType.setCompoundDrawables(null, null, iconUp, null)
+ //展示列表
+ rvFaultList.visibility = View.VISIBLE
+ (rvFaultList.layoutParams as ConstraintLayout.LayoutParams).topToBottom = R.id.tvFaultType
+ source = 1
+ if(typeList.isNullOrEmpty()){
+ //获取故障二级分类即故障类型
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,2,level1Id,type,0)
+ }else{
+ orderReasonAdapter.setData(typeList!!,source)
+ }
+
+ }
+ }
+ //故障原因选择
+ tvFaultReason.setOnClickListener {
+ if(tvFaultType.text.isEmpty()){
+ ToastUtils.showShort("请先选择故障类型")
+ return@setOnClickListener
+ }
+ if(faultReasonSelectStatus){
+ //关闭
+ faultReasonSelectStatus = false
+ tvFaultReason.setCompoundDrawables(null, null, iconDown, null)
+ //隐藏列表
+ rvFaultList.visibility = View.GONE
+ }else{
+ //打开
+ faultReasonSelectStatus = true
+ tvFaultReason.setCompoundDrawables(null, null, iconUp, null)
+ //展示列表
+ rvFaultList.visibility = View.VISIBLE
+ (rvFaultList.layoutParams as ConstraintLayout.LayoutParams).topToBottom = R.id.tvFaultReason
+ }
+ }
+
+ //发生时间
+ 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())
+ }
+
+ //补充描述
+ etNoteInput.onFocusChangeListener = OnFocusChangeListener { v, hasFocus ->
+ val edit = v as EditText
+ if(hasFocus){
+ edit.hint = ""
+ }else{
+ edit.hint = "手动输入"
+ }
+ }
+ etNoteInput.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?) {
+
+ }
+
+ })
+ //问题描述录音
+ ivNoteAudio.setOnClickListener {
+ audioStatus = !audioStatus
+ if(audioStatus){
+ ivNoteAudio.setImageDrawable(ContextCompat.getDrawable(
+ context,
+ R.drawable.icon_reason_audio_pressed
+ ))
+ }else{
+ ivNoteAudio.setImageDrawable(ContextCompat.getDrawable(
+ context,
+ R.drawable.icon_reason_audio_normal
+ ))
+ }
+ setAudio(audioStatus)
+ }
+ //上报
+ tvFaultReport.setOnClickListener{
+ if(level2Name.isEmpty()){
+ ToastUtils.showShort("请完整填写再上报")
+ return@setOnClickListener
+ }
+ if(hasLevel3 && level3Name.isEmpty()){
+ ToastUtils.showShort("请完整填写再上报")
+ return@setOnClickListener
+ }
+ reportNote = etNoteInput.text.toString()
+ //故障码列表赋值
+ BadCaseConfig.newFMInfoMsg?.fmInfoList?.forEach {
+ faultCodeList.add(it.faultId)
+ }
+ val geocodeSearch = GeocodeSearch(context)
+ geocodeSearch.setOnGeocodeSearchListener(object: GeocodeSearch.OnGeocodeSearchListener {
+ override fun onRegeocodeSearched(regeocodeResult: RegeocodeResult?, p1: Int) {
+ regeocodeResult?.regeocodeAddress?.formatAddress?.let {
+ address = it
+ }
+ val padProblemList= ArrayList()
+ val note = if(reportNote.isEmpty()){
+ "$level1Name-$level2Name-$level3Name"
+ }else{
+ "$level1Name-$level2Name-$level3Name($reportNote)"
+ }
+ val padProblemInfo = PadProblemInfo(address,faultCodeList,millis2String(workOrderOccurrenceTime),level1Id,
+ level2Id,level3Id,BadCaseConfig.lineName,note,reportType,
+ SharedPrefsMgr.getInstance().getString("och_account",""))
+ padProblemList.add(padProblemInfo)
+ val padAddProblemReq = PadAddProblemReq(padProblemList, AppConfigInfo.plateNumber)
+ CallerDevaToolsManager.problemPadAdd(padAddProblemReq)
+ }
+
+ override fun onGeocodeSearched(p0: GeocodeResult?, p1: Int) {
+
+ }
+ })
+ val latLon = LatLonPoint(CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().latitude, CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().longitude)
+ val q = RegeocodeQuery(latLon,200f,GeocodeSearch.AMAP)
+ geocodeSearch.getFromLocationAsyn(q)
+ }
+
+ //取消
+ tvFaultCancel.setOnClickListener {
+ this@FaultReasonView.visibility = View.GONE
+ }
+ }
+
+ 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.5f,
+ Animation.RELATIVE_TO_SELF, 0.5f)
+ scaleAnimation.duration = 1000
+ scaleAnimation.repeatCount = -1
+ ivNoteAudio.startAnimation(scaleAnimation)
+ }else{
+ //停止语音听写
+ mIat?.stopListening()
+ //结束动画
+ ivNoteAudio.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);
+ // }
+ }
+
+ }
+
+ /**
+ * 显示结果
+ */
+ @SuppressLint("SetTextI18n")
+ private fun printResult(results: RecognizerResult) {
+ val text: String = JsonParser.parseIatResult(results.resultString)
+ Log.i(TAG, "语音内容=$text")
+ if(text.isNotEmpty()){
+ if(etNoteInput.text.toString().isEmpty()){
+ etNoteInput.setText(text)
+ etNoteInput.setSelection(text.length)
+ }else{
+ val startStr = etNoteInput.text.toString().substring(0,etNoteInput.selectionStart)
+ val endStr = etNoteInput.text.toString().substring(etNoteInput.selectionEnd,etNoteInput.text.toString().length)
+ etNoteInput.setText(startStr+text+endStr)
+ etNoteInput.setSelection(startStr.length+text.length)
+ }
+
+ }
+ }
+
+ fun setClickListener(clickListener: ClickListener) {
+ this.clickListener = clickListener
+ }
+
+ interface ClickListener {
+ fun closeWindow()
+ }
+
+ /**
+ * 故障上报成功
+ */
+ override fun problemPadAddSuccess() {
+ super.problemPadAddSuccess()
+ //显示上报成功页面,短暂停留关闭弹窗
+ ThreadUtils.runOnUiThread {
+ //结束动画
+ ivNoteAudio.clearAnimation()
+ rvFaultList.visibility = View.GONE
+ tvUploadSuccess.visibility = View.VISIBLE
+ faultReasonGroup.visibility = View.GONE
+ val successHandler = Handler(Looper.getMainLooper())
+ successHandler.postDelayed({
+ this@FaultReasonView.visibility = View.GONE
+ },1500)
+ }
+ }
+
+ override fun problemPadAddError(msg: String) {
+ super.problemPadAddError(msg)
+ ToastUtils.showShort("故障原因上报失败$msg")
+ }
+
+ override fun getCategoriesSuccess(list: List) {
+ super.getCategoriesSuccess(list)
+ ThreadUtils.runOnUiThread {
+ if(list.isNotEmpty()){
+ if(source == 0){
+ level1Id = list[0].id
+ level1Name = list[0].name
+
+ source = 1
+ //获取故障二级分类即故障类型
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,2,level1Id,type,0)
+ }else{
+ if(source == 1){
+ typeList = list
+ hasLevel2 = true
+ }else{
+ reasonList = list
+ hasLevel3 = true
+ }
+ orderReasonAdapter.setData(list,source)
+ }
+ }else{
+ if(source == 2){
+ hasLevel3 = false
+ }else{
+ hasLevel2 = false
+ ToastUtils.showShort("故障类型列表为空")
+ }
+ }
+ }
+ }
+
+ override fun getCategoriesError(msg: String) {
+ super.getCategoriesError(msg)
+ ToastUtils.showShort("故障列表获取失败:$msg")
+ }
+
+}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/ReportTypeView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/ReportTypeView.kt
new file mode 100644
index 0000000000..430fc72531
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/ReportTypeView.kt
@@ -0,0 +1,261 @@
+package com.mogo.eagle.core.function.hmi.bone.tab
+
+import android.content.Context
+import android.os.CountDownTimer
+import android.os.Handler
+import android.os.Looper
+import android.os.SystemClock
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.amap.api.services.core.LatLonPoint
+import com.amap.api.services.geocoder.GeocodeResult
+import com.amap.api.services.geocoder.GeocodeSearch
+import com.amap.api.services.geocoder.RegeocodeQuery
+import com.amap.api.services.geocoder.RegeocodeResult
+import com.mogo.commons.env.ProjectUtils
+import com.mogo.commons.storage.SharedPrefsMgr
+import com.mogo.eagle.core.data.app.AppConfigInfo
+import com.mogo.eagle.core.data.deva.report.CategoryInfo
+import com.mogo.eagle.core.data.deva.report.PadAddProblemReq
+import com.mogo.eagle.core.data.deva.report.PadProblemInfo
+import com.mogo.eagle.core.function.api.devatools.IMoGoDevaToolsListener
+import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
+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.hmi.R
+import com.mogo.eagle.core.utilcode.util.ThreadUtils
+import com.mogo.eagle.core.utilcode.util.TimeUtils.millis2String
+import com.mogo.eagle.core.utilcode.util.ToastUtils
+import com.zhjt.mogo_core_function_devatools.badcase.consts.BadCaseConfig
+import kotlinx.android.synthetic.main.view_report_type.view.ivOneClickReport
+import kotlinx.android.synthetic.main.view_report_type.view.oneClickGroup
+import kotlinx.android.synthetic.main.view_report_type.view.reportTypeGroup
+import kotlinx.android.synthetic.main.view_report_type.view.tvOneClickReportTitle
+import kotlinx.android.synthetic.main.view_report_type.view.tvReportSuccess
+import kotlinx.android.synthetic.main.view_report_type.view.tvReportTypeFault
+import kotlinx.android.synthetic.main.view_report_type.view.tvReportTypeTakeOver
+import kotlin.math.absoluteValue
+import kotlin.math.round
+import kotlin.random.Random
+
+/**
+ * 上报类型选择,包括一键上报及上报类型选择:故障类、接管类
+ * 一键上报和类型选择互斥,当点击弹出上报类型选择时,一键上报隐藏
+ */
+class ReportTypeView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoDevaToolsListener {
+
+ private val TAG = "ReportTypeView"
+
+ private var isOneClickType: Boolean = false //是否是一键上报类型
+ private var hasReportOperate: Boolean = false //是否点击了一键上报按钮
+
+ private var oneClickTimer: CountDownTimer?= null
+ private var clickListener: ClickListener? = null
+
+ private var address: String = "" //故障地点
+ private var faultCodeList = ArrayList() //故障码列表
+ private var level1Id: Int = 0 //一级分类ID
+ private var level2Id: Int = 0 //二级分类ID
+ private var level3Id: Int = 0 //三级分类ID
+ private var level1Name: String = ""
+ private var level2Name: String = ""
+ private var level3Name: String = ""
+ private val reportType: Int = 1 //上报方式:0:小程序 1:司机屏 2:云端上报
+ private var level: Int = 1
+
+ private var canOneReport: Boolean = false //是否可以一键上报
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.view_report_type, this, true)
+ initView()
+ }
+
+ private fun initView(){
+ CallerDevaToolsListenerManager.addListener(TAG, this)
+ if(isOneClickType){
+ showOneCLickReportView()
+ }else{
+ showTypeSelectView()
+ }
+ //一键上报
+ ivOneClickReport.setOnClickListener {
+ if(!canOneReport){
+ ToastUtils.showShort("故障描述获取失败不能上报")
+ return@setOnClickListener
+ }
+ hasReportOperate = true
+ BadCaseConfig.newFMInfoMsg?.fmInfoList?.forEach {
+ faultCodeList.add(it.faultId)
+ }
+ val geocodeSearch = GeocodeSearch(context)
+ geocodeSearch.setOnGeocodeSearchListener(object: GeocodeSearch.OnGeocodeSearchListener {
+ override fun onRegeocodeSearched(regeocodeResult: RegeocodeResult?, p1: Int) {
+ regeocodeResult?.regeocodeAddress?.formatAddress?.let {
+ address = it
+ }
+ val padProblemList= ArrayList()
+ val padProblemInfo = PadProblemInfo(address,faultCodeList,millis2String(System.currentTimeMillis()),level1Id,
+ level2Id,level3Id,BadCaseConfig.lineName,"${level1Name}-${level2Name}-${level3Name}",reportType,
+ SharedPrefsMgr.getInstance().getString("och_account",""))
+ padProblemList.add(padProblemInfo)
+ val padAddProblemReq = PadAddProblemReq(padProblemList, AppConfigInfo.plateNumber)
+ CallerDevaToolsManager.problemPadAdd(padAddProblemReq)
+ }
+
+ override fun onGeocodeSearched(p0: GeocodeResult?, p1: Int) {
+
+ }
+ })
+ val latLon = LatLonPoint(CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().latitude, CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().longitude)
+ val q = RegeocodeQuery(latLon,200f, GeocodeSearch.AMAP)
+ geocodeSearch.getFromLocationAsyn(q)
+ }
+
+ //故障类
+ tvReportTypeFault.setOnClickListener {
+ //TODO 更改!
+ if(!ProjectUtils.isSaas()){
+ clickListener?.openFaultReasonView()
+ }else{
+ //展示工单上报弹窗
+ clickListener?.openWorkOrderView()
+ }
+ this@ReportTypeView.visibility = View.GONE
+ }
+
+ //主动录包
+ tvReportTypeTakeOver.setOnClickListener {
+ val response = CallerAutoPilotControlManager.recordPackage(
+ BadCaseConfig.type, Random(SystemClock.elapsedRealtime()).nextInt().absoluteValue,
+ BadCaseConfig.totalDuration, BadCaseConfig.previousDuration)
+ if(response){
+ //已发起录包
+ oneClickGroup.visibility = View.GONE
+ reportTypeGroup.visibility = View.GONE
+ tvReportSuccess.visibility = View.VISIBLE
+ tvReportSuccess.text = resources.getString(R.string.record_success)
+ val successHandler = Handler(Looper.getMainLooper())
+ successHandler.postDelayed({
+ this@ReportTypeView.visibility = View.GONE
+ },1500)
+ }else{
+ ToastUtils.showShort("主动录包命令下发失败")
+ this@ReportTypeView.visibility = View.GONE
+ }
+ }
+ }
+
+ /**
+ * 展示一键上报视图
+ */
+ private fun showOneCLickReportView(){
+ oneClickGroup.visibility = View.VISIBLE
+ reportTypeGroup.visibility = View.GONE
+ tvReportSuccess.visibility = View.GONE
+ tvOneClickReportTitle.text = String.format(resources.getString(R.string.identified_vehicle_malfunction),5)
+ oneClickTimer = object : CountDownTimer(5000, 1000) {
+ override fun onTick(count: Long) {
+ ThreadUtils.runOnUiThread {
+ tvOneClickReportTitle.text = String.format(resources.getString(R.string.identified_vehicle_malfunction),round((count.toDouble()/1000)).toInt())
+ }
+ }
+
+ override fun onFinish() {
+ //如果有页面操作,则不自动关闭窗口
+ if(!hasReportOperate){
+ ThreadUtils.runOnUiThread {
+ this@ReportTypeView.visibility = View.GONE
+ }
+ }
+ }
+ }
+ oneClickTimer?.start()
+ }
+
+ /**
+ * 展示类型选择视图
+ */
+ fun showTypeSelectView(){
+ oneClickGroup.visibility = View.GONE
+ reportTypeGroup.visibility = View.VISIBLE
+ tvReportSuccess.visibility = View.GONE
+ }
+
+ /**
+ * 故障上报成功
+ */
+ override fun problemPadAddSuccess() {
+ //显示上报成功页面,短暂停留关闭弹窗
+ ThreadUtils.runOnUiThread {
+ oneClickGroup.visibility = View.GONE
+ reportTypeGroup.visibility = View.GONE
+ tvReportSuccess.visibility = View.VISIBLE
+ tvReportSuccess.text = resources.getString(R.string.report_success)
+ val successHandler = Handler(Looper.getMainLooper())
+ successHandler.postDelayed({
+ this.visibility = View.GONE
+ },1500)
+ }
+ }
+
+ override fun problemPadAddError(msg: String) {
+ super.problemPadAddError(msg)
+ ToastUtils.showShort("故障原因上报失败$msg")
+ ThreadUtils.runOnUiThread {
+ this.visibility = View.GONE
+ }
+ }
+
+ override fun getCategoriesSuccess(list: List) {
+ super.getCategoriesSuccess(list)
+ if(list.isEmpty()){
+ ToastUtils.showShort("一键上报故障描述后台未配置")
+ canOneReport = false
+ }else{
+ when (level) {
+ 1 -> {
+ level1Id = list[0].id
+ level1Name = list[0].name
+ level = 2
+ //请求二级一键上报配置
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,level,level1Id,4,1)
+ }
+ 2 -> {
+ level2Id = list[0].id
+ level2Name = list[0].name
+ level = 3
+ //请求三级一键上报配置
+ CallerDevaToolsManager.getCategories(BadCaseConfig.tenantId,level,level2Id,4,1)
+ }
+ else -> {
+ level3Id = list[0].id
+ level3Name = list[0].name
+ canOneReport = true
+ }
+ }
+ }
+ }
+
+ override fun getCategoriesError(msg: String) {
+ super.getCategoriesError(msg)
+ ToastUtils.showShort("一键上报故障描述获取失败$msg")
+ canOneReport = false
+ }
+
+ interface ClickListener {
+ fun openFaultReasonView()
+ fun openWorkOrderView()
+ }
+
+ fun setClickListener(clickListener: ClickListener) {
+ this.clickListener = clickListener
+ }
+
+}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/WorkOrderView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/WorkOrderView.kt
new file mode 100644
index 0000000000..25fb89a38b
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/bone/tab/WorkOrderView.kt
@@ -0,0 +1,312 @@
+package com.mogo.eagle.core.function.hmi.bone.tab
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.AttributeSet
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.animation.Animation
+import android.view.animation.ScaleAnimation
+import android.widget.EditText
+import androidx.constraintlayout.widget.ConstraintLayout
+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.function.hmi.R
+import com.mogo.eagle.core.utilcode.util.JsonParser
+import com.mogo.eagle.core.utilcode.util.ThreadUtils
+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.badcase.consts.BadCaseConfig
+import kotlinx.android.synthetic.main.view_work_order.view.et_describe_input
+import kotlinx.android.synthetic.main.view_work_order.view.iv_describe_audio
+import kotlinx.android.synthetic.main.view_work_order.view.iv_time_add
+import kotlinx.android.synthetic.main.view_work_order.view.iv_time_reduce
+import kotlinx.android.synthetic.main.view_work_order.view.tv_occurrence_time
+import kotlinx.android.synthetic.main.view_work_order.view.tv_work_order_cancel
+import kotlinx.android.synthetic.main.view_work_order.view.tv_work_order_report
+import kotlinx.android.synthetic.main.view_work_order.view.tv_work_order_time
+import kotlinx.android.synthetic.main.view_work_order.view.wrap_radio_group
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+
+/**
+ * 工单上报视图
+ */
+class WorkOrderView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoDevaToolsListener {
+
+ private val TAG = "WorkOrderView"
+
+ // 语音听写对象
+ private var mIat: SpeechRecognizer? = null
+ // 用HashMap存储听写结果
+ private val mIatResults: HashMap = LinkedHashMap()
+
+ private var workOrderType = "" //工单问题类型
+ private var workOrderOccurrenceTime = System.currentTimeMillis() //故障发生时间
+ var ret = 0 // 函数调用返回值
+ private var audioStatus = false
+
+ init {
+ LayoutInflater.from(context).inflate(R.layout.view_work_order, this, true)
+ initView()
+ initEvent()
+ }
+
+ private fun initView(){
+ // 初始化识别无UI识别对象
+ // 使用SpeechRecognizer对象,可根据回调消息自定义界面;
+ mIat = SpeechRecognizer.createRecognizer(context, mInitListener)
+ }
+
+ @OptIn(DelicateCoroutinesApi::class)
+ @SuppressLint("SetTextI18n")
+ private fun initEvent(){
+ CallerDevaToolsListenerManager.addListener(TAG, this)
+ //弹窗展示时间
+ tv_work_order_time.text = resources.getString(R.string.work_order_time) +
+ millis2String(System.currentTimeMillis(), TimeUtils.getHourMinSecondFormat())
+
+ wrap_radio_group.setOnCheckedChangeListener{_, checkedId ->
+ when(checkedId){
+ R.id.rb_type_software->{
+ workOrderType = "软件"
+ }
+ R.id.rb_type_kit->{
+ workOrderType = "套件"
+ }
+ R.id.rb_type_vehicle->{
+ workOrderType = "车辆"
+ }
+ R.id.rb_type_capacity->{
+ workOrderType = "运力"
+ }
+ R.id.rb_type_environment->{
+ workOrderType = "环境"
+ }
+ R.id.rb_type_other->{
+ workOrderType = "其他"
+ }
+ }
+ }
+
+ //发生时间
+ tv_occurrence_time.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
+ iv_time_reduce.setOnClickListener {
+ workOrderOccurrenceTime -= 60000
+ tv_occurrence_time.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
+ }
+ iv_time_add.setOnClickListener {
+ if(workOrderOccurrenceTime + 60000 > System.currentTimeMillis()){
+ ToastUtils.showShort("发生时间应在当前时间之前")
+ return@setOnClickListener
+ }
+ workOrderOccurrenceTime += 60000
+ tv_occurrence_time.text = millis2String(workOrderOccurrenceTime, TimeUtils.getHourMinFormat())
+ }
+
+ et_describe_input.onFocusChangeListener = OnFocusChangeListener { v, hasFocus ->
+ val edit = v as EditText
+ if(hasFocus){
+ edit.hint = ""
+ }else{
+ edit.hint = "手动输入"
+ }
+ }
+ et_describe_input.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?) {
+
+ }
+
+ })
+
+ //问题描述录音
+ iv_describe_audio.setOnClickListener {
+ audioStatus = !audioStatus
+ setAudio(audioStatus)
+ }
+
+ //上报
+ tv_work_order_report.setOnClickListener {
+ //工单问题类型必选,没有选择,进行提示
+ if(workOrderType.isEmpty()){
+ ToastUtils.showShort("请选择问题类型")
+ return@setOnClickListener
+ }
+ if(et_describe_input.text.toString().isEmpty()){
+ ToastUtils.showShort("请填写问题描述")
+ return@setOnClickListener
+ }
+ GlobalScope.launch(Dispatchers.IO){
+ val msgBoxList = CallerMsgBoxManager.queryFMInfoList(context,
+ workOrderOccurrenceTime-120000,workOrderOccurrenceTime+120000)
+ val faultList = ArrayList()
+ 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(),
+ et_describe_input.text.toString(), CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().longitude.toString(),
+ CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().latitude.toString(),
+ AppConfigInfo.plateNumber, SharedPrefsMgr.getInstance().getString("och_account","") ,
+ BadCaseConfig.dockerVersion ?:"",faultList)
+ CallerDevaToolsManager.workOrderReport(workOrderReportInfo)
+ }
+
+ }
+
+ //取消
+ tv_work_order_cancel.setOnClickListener {
+ this@WorkOrderView.visibility = View.GONE
+ }
+
+ }
+
+ 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.5f, Animation.RELATIVE_TO_SELF, 0.5f
+ )
+ scaleAnimation.duration = 1000
+ scaleAnimation.repeatCount = -1
+ iv_describe_audio.startAnimation(scaleAnimation)
+ }else{
+ //停止语音听写
+ mIat?.stopListening()
+ //结束动画
+ iv_describe_audio.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);
+ // }
+ }
+
+ }
+
+ /**
+ * 显示结果
+ */
+ @SuppressLint("SetTextI18n")
+ private fun printResult(results: RecognizerResult) {
+ val text: String = JsonParser.parseIatResult(results.resultString)
+ Log.i(TAG, "语音内容=$text")
+ if(text.isNotEmpty()){
+ if(et_describe_input.text.toString().isEmpty()){
+ et_describe_input.setText(text)
+ et_describe_input.setSelection(text.length)
+ }else{
+ val startStr = et_describe_input.text.toString().substring(0,et_describe_input.selectionStart)
+ val endStr = et_describe_input.text.toString().substring(et_describe_input.selectionEnd,et_describe_input.text.toString().length)
+ et_describe_input.setText(startStr+text+endStr)
+ et_describe_input.setSelection(startStr.length+text.length)
+ }
+
+ }
+ }
+
+ override fun workOrderReportSuccess() {
+ ToastUtils.showShort("工单上报成功")
+ ThreadUtils.runOnUiThread {
+ this@WorkOrderView.visibility = View.GONE
+ }
+ }
+
+ override fun workOrderReportError() {
+ ToastUtils.showShort("工单上报失败")
+ }
+
+}
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/WrapRadioGroup.java b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/WrapRadioGroup.java
new file mode 100644
index 0000000000..e35630455f
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/WrapRadioGroup.java
@@ -0,0 +1,120 @@
+package com.mogo.eagle.core.function.hmi.ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RadioGroup;
+
+public class WrapRadioGroup extends RadioGroup {
+
+ public WrapRadioGroup(Context context) {
+ super(context);
+ }
+
+ public WrapRadioGroup(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ //调用ViewGroup的方法,测量子view
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
+
+ //最大的宽
+ int maxWidth = 0;
+ //累计的高
+ int totalHeight = 0;
+
+ //当前这一行的累计行宽
+ int lineWidth = 0;
+ //当前这行的最大行高
+ int maxLineHeight = 0;
+ //用于记录换行前的行宽和行高
+ int oldHeight;
+ int oldWidth;
+
+ int count = getChildCount();
+ //假设 widthMode和heightMode都是AT_MOST
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
+ //得到这一行的最高
+ oldHeight = maxLineHeight;
+ //当前最大宽度
+ oldWidth = maxWidth;
+
+ int deltaX = child.getMeasuredWidth() + params.leftMargin + params.rightMargin;
+ if (lineWidth + deltaX + getPaddingLeft() + getPaddingRight() > widthSize) {//如果折行,height增加
+ //和目前最大的宽度比较,得到最宽。不能加上当前的child的宽,所以用的是oldWidth
+ maxWidth = Math.max(lineWidth, oldWidth);
+ //重置宽度
+ lineWidth = deltaX;
+ //累加高度
+ totalHeight += oldHeight;
+ //重置行高,当前这个View,属于下一行,因此当前最大行高为这个child的高度加上margin
+ maxLineHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin;
+// Log.v(TAG, "maxHeight:" + totalHeight + "---" + "maxWidth:" + maxWidth);
+
+ } else {
+ //不换行,累加宽度
+ lineWidth += deltaX;
+ //不换行,计算行最高
+ int deltaY = child.getMeasuredHeight() + params.topMargin + params.bottomMargin;
+ maxLineHeight = Math.max(maxLineHeight, deltaY);
+ }
+ if (i == count - 1) {
+ //前面没有加上下一行的搞,如果是最后一行,还要再叠加上最后一行的最高的值
+ totalHeight += maxLineHeight;
+ //计算最后一行和前面的最宽的一行比较
+ maxWidth = Math.max(lineWidth, oldWidth);
+ }
+ }
+
+ //加上当前容器的padding值
+ maxWidth += getPaddingLeft() + getPaddingRight();
+ totalHeight += getPaddingTop() + getPaddingBottom();
+ setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : maxWidth,
+ heightMode == MeasureSpec.EXACTLY ? heightSize : totalHeight);
+
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int count = getChildCount();
+ //pre为前面所有的child的相加后的位置
+ int preLeft = getPaddingLeft();
+ int preTop = getPaddingTop();
+ //记录每一行的最高值
+ int maxHeight = 0;
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
+ //r-l为当前容器的宽度。如果子view的累积宽度大于容器宽度,就换行。
+ if (preLeft + params.leftMargin + child.getMeasuredWidth() + params.rightMargin + getPaddingRight() > (r - l)) {
+ //重置
+ preLeft = getPaddingLeft();
+ //要选择child的height最大的作为设置
+ preTop = preTop + maxHeight;
+ maxHeight = getChildAt(i).getMeasuredHeight() + params.topMargin + params.bottomMargin;
+ } else { //不换行,计算最大高度
+ maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + params.topMargin + params.bottomMargin);
+ }
+ //left坐标
+ int left = preLeft + params.leftMargin;
+ //top坐标
+ int top = preTop + params.topMargin;
+ int right = left + child.getMeasuredWidth();
+ int bottom = top + child.getMeasuredHeight();
+ //为子view布局
+ child.layout(left, top, right, bottom);
+ //计算布局结束后,preLeft的值
+ preLeft += params.leftMargin + child.getMeasuredWidth() + params.rightMargin;
+ }
+ }
+
+}
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_fault_des_input.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_fault_des_input.png
new file mode 100644
index 0000000000..49264822a1
Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_fault_des_input.png differ
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_tab_report_type.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_tab_report_type.png
new file mode 100644
index 0000000000..4c380fa3b6
Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/bg_tab_report_type.png differ
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_add.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_add.png
new file mode 100644
index 0000000000..a51b2fc152
Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_add.png differ
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_reduce.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_reduce.png
new file mode 100644
index 0000000000..0ca15baef2
Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/icon_fault_time_reduce.png differ
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_cancel.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_cancel.xml
new file mode 100644
index 0000000000..37cc7acefc
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_cancel.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_reason_title_label.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_reason_title_label.xml
new file mode 100644
index 0000000000..e086586d69
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_reason_title_label.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_report.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_report.xml
new file mode 100644
index 0000000000..aed5a20c8a
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable/bg_fault_report.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_bone_tab.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_bone_tab.xml
index ea6b300b70..af1410dfa0 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_bone_tab.xml
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_bone_tab.xml
@@ -33,6 +33,40 @@
app:layout_constraintTop_toTopOf="parent"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_type.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_type.xml
new file mode 100644
index 0000000000..6ec21e72d0
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_type.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_work_order.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_work_order.xml
new file mode 100644
index 0000000000..26da1b011e
--- /dev/null
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_work_order.xml
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml
index 8971ad44f0..ff6dcd2dfa 100644
--- a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml
+++ b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml
@@ -206,4 +206,7 @@
FSM图标
V2X图标
+ 故障发生时间减少
+ 故障发生时间增加
+