diff --git a/OCH/bus/driver/src/main/res/layout/bus_base_fragment.xml b/OCH/bus/driver/src/main/res/layout/bus_base_fragment.xml index 6735e53e8c..ece99da0cc 100644 --- a/OCH/bus/driver/src/main/res/layout/bus_base_fragment.xml +++ b/OCH/bus/driver/src/main/res/layout/bus_base_fragment.xml @@ -117,6 +117,17 @@ app:layout_goneMarginEnd="40dp" app:layout_goneMarginTop="@dimen/dp_236" /> + + + + + + + + + + app:layout_constraintTop_toTopOf="parent" + android:visibility="gone"/> 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/v2n/RoadV2NEventWindowView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt index 63694ef4cf..6e3572c52a 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt @@ -206,7 +206,7 @@ class RoadV2NEventWindowView @JvmOverloads constructor( } else { val layoutParam = roundRoadV2NEventContainer.layoutParams as ConstraintLayout.LayoutParams - layoutParam.width = AutoSizeUtils.dp2px(context, (600 + 0 + 0).toFloat()) + layoutParam.width = AutoSizeUtils.dp2px(context, (654 + 0 + 0).toFloat()) layoutParam.height = ConstraintLayout.LayoutParams.WRAP_CONTENT roundRoadV2NEventContainer.layoutParams = layoutParam roundRoadV2NEventContainer.background = @@ -219,23 +219,23 @@ class RoadV2NEventWindowView @JvmOverloads constructor( containerIconHintLayoutParams.width = LayoutParams.MATCH_PARENT containerIconHintLayoutParams.height = LayoutParams.WRAP_CONTENT containerIconHintLayoutParams.setMargins( - AutoSizeUtils.dp2px(context, 30f - 22f), - AutoSizeUtils.dp2px(context, 31f - 15f), - AutoSizeUtils.dp2px(context, 30f - 22f), + AutoSizeUtils.dp2px(context, 30f - 16f), + AutoSizeUtils.dp2px(context, 30f - 14f), + AutoSizeUtils.dp2px(context, 30f - 16f), 0 ) containerIconHint.layoutParams = containerIconHintLayoutParams val ivV2XImageLayoutParams = ivV2XImage.layoutParams as RelativeLayout.LayoutParams - ivV2XImageLayoutParams.width = AutoSizeUtils.dp2px(context, 84f + 22f + 22f) - ivV2XImageLayoutParams.height = AutoSizeUtils.dp2px(context, 84f + 15f + 29f) + ivV2XImageLayoutParams.width = AutoSizeUtils.dp2px(context, 120f + 16f + 16f) + ivV2XImageLayoutParams.height = AutoSizeUtils.dp2px(context, 120f + 16f + 16f) ivV2XImage.layoutParams = ivV2XImageLayoutParams val tvV2XHintContentLayoutParams = tvV2XHintContent.layoutParams as RelativeLayout.LayoutParams tvV2XHintContentLayoutParams.setMargins( - AutoSizeUtils.dp2px(context, 20f - 22f), - AutoSizeUtils.dp2px(context, (42f + 15f) - (46f / 2f)), + AutoSizeUtils.dp2px(context, 30f - 14f), + AutoSizeUtils.dp2px(context, (60f + 16f) - (50f / 2f)), AutoSizeUtils.dp2px(context, 5f), 0 ) @@ -249,11 +249,11 @@ class RoadV2NEventWindowView @JvmOverloads constructor( val containerImageAndLiveVideoLayoutParams = containerImageAndLiveVideo.layoutParams as ConstraintLayout.LayoutParams - containerImageAndLiveVideoLayoutParams.width = AutoSizeUtils.dp2px(context, 540f) - containerImageAndLiveVideoLayoutParams.height = AutoSizeUtils.dp2px(context, 300f) + containerImageAndLiveVideoLayoutParams.width = AutoSizeUtils.dp2px(context, 593f) + containerImageAndLiveVideoLayoutParams.height = AutoSizeUtils.dp2px(context, 330f) containerImageAndLiveVideoLayoutParams.setMargins( AutoSizeUtils.dp2px(context, 30f), - AutoSizeUtils.dp2px(context, 30f - 29f), + AutoSizeUtils.dp2px(context, 20f - 16f), AutoSizeUtils.dp2px(context, 30f), 0 ) @@ -266,16 +266,16 @@ class RoadV2NEventWindowView @JvmOverloads constructor( tvV2XTimeStrLayoutParams.width = LayoutParams.MATCH_PARENT tvV2XTimeStrLayoutParams.height = LayoutParams.WRAP_CONTENT tvV2XTimeStrLayoutParams.setMargins( - AutoSizeUtils.dp2px(context, 29f), - AutoSizeUtils.dp2px(context, 25f), - AutoSizeUtils.dp2px(context, 29f), - AutoSizeUtils.dp2px(context, 30f) + AutoSizeUtils.dp2px(context, 30f), + AutoSizeUtils.dp2px(context, 12f), + AutoSizeUtils.dp2px(context, 30f), + AutoSizeUtils.dp2px(context, 24f) ) tvV2XTimeStr.layoutParams = tvV2XTimeStrLayoutParams - tvV2XTimeStr.setTextColor(Color.parseColor("#66FFFFFF")) + tvV2XTimeStr.setTextColor(Color.parseColor("#999999")) tvV2XTimeStr.setTextSize( TypedValue.COMPLEX_UNIT_PX, - AutoSizeUtils.dp2px(context, 22f).toFloat() + AutoSizeUtils.dp2px(context, 26f).toFloat() ) ivClose.setImageResource(R.drawable.hmi_v2n_event_icon_close_driver) @@ -285,6 +285,8 @@ class RoadV2NEventWindowView @JvmOverloads constructor( ivCloseLayoutParams.height = AutoSizeUtils.dp2px(context, 50f) ivCloseLayoutParams.setMargins(0, 0, 0, 0) ivClose.layoutParams = ivCloseLayoutParams + // 6.7.0 UI 没设计关闭按钮 + ivClose.visibility = View.GONE containerEventContent.requestLayout() roundRoadV2NEventContainer.requestLayout() 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/hmi_v2n_event_bg_driver.9.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/hmi_v2n_event_bg_driver.9.png new file mode 100644 index 0000000000..b74233c31f Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/hmi_v2n_event_bg_driver.9.png differ diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/hmi_v2n_event_bg_driver.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/hmi_v2n_event_bg_driver.png deleted file mode 100644 index 32d41221e1..0000000000 Binary files a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xhdpi/hmi_v2n_event_bg_driver.png and /dev/null 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图标 + 故障发生时间减少 + 故障发生时间增加 + diff --git a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigong_driver.png b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigong_driver.png index 0d49df45b7..85f5c25486 100644 Binary files a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigong_driver.png and b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigong_driver.png differ diff --git a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigu_driver.png b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigu_driver.png index 37e3993814..b3c122482a 100644 Binary files a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigu_driver.png and b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_shigu_driver.png differ diff --git a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_bus_station_driver.png b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_bus_station_driver.png index 79ea2f61d9..0512a36df7 100644 Binary files a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_bus_station_driver.png and b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_bus_station_driver.png differ diff --git a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_other_retrograde_vehicle_driver.png b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_other_retrograde_vehicle_driver.png index b1dfaea874..bd6c0c8489 100644 Binary files a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_other_retrograde_vehicle_driver.png and b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_v2x_other_retrograde_vehicle_driver.png differ diff --git a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_xingren_hengchuan_driver.png b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_xingren_hengchuan_driver.png index 126550b8f3..8a714c85a5 100644 Binary files a/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_xingren_hengchuan_driver.png and b/core/mogo-core-res/src/main/function-hmi-res/drawable-xhdpi/icon_xingren_hengchuan_driver.png differ