feat(task): 添加复合材料铺贴任务功能
- 实现复合材料铺贴任务的完整业务流程 - 集成 OCR 识别功能用于逐层铺贴验证 - 添加任务详情查询和状态管理 - 实现拍照识别和结果处理逻辑 - 优化任务路由逻辑支持多种任务类型匹配 - 添加语音控制命令支持 - 设计专用 UI 界面和视觉反馈 - 配置网络请求接口和服务端通信 - 添加数据模型定义和状态枚举 - 实现离线命令监听和回调处理 - 完善错误处理和用户提示信息
这个提交包含在:
父节点
75e9fca5a4
当前提交
3f97ff01f4
@ -0,0 +1,56 @@
|
||||
package com.nova.brain.glass.model.data
|
||||
|
||||
data class CompositeLayupDetailItem(
|
||||
val id: Long = 0,
|
||||
val taskId: Long = 0,
|
||||
val taskNo: String = "",
|
||||
val stepSeq: Int = 0,
|
||||
val detailInfo: String = "",
|
||||
val detailResult: String = "",
|
||||
val detailStatus: Int = 0,
|
||||
val createdAt: String = "",
|
||||
val updatedAt: String = "",
|
||||
val createdBy: String = "",
|
||||
val updatedBy: String = "",
|
||||
val isDeleted: Long = 0
|
||||
)
|
||||
|
||||
data class CompositeLayupTaskDetail(
|
||||
val id: Long = 0,
|
||||
val taskNo: String = "",
|
||||
val taskName: String = "",
|
||||
val taskType: Int = 0,
|
||||
val taskStatus: Int = 0,
|
||||
val taskSource: String = "",
|
||||
val taskSteps: Int = 0,
|
||||
val taskCurrentStep: Int = 0,
|
||||
val taskFilePaths: String = "",
|
||||
val centralTaskId: String = "",
|
||||
val centralTaskResult: String = "",
|
||||
val createdAt: String = "",
|
||||
val updatedAt: String = "",
|
||||
val createdBy: String = "",
|
||||
val updatedBy: String = "",
|
||||
val isDeleted: Long = 0,
|
||||
val detailList: List<CompositeLayupDetailItem>? = null
|
||||
)
|
||||
|
||||
data class CompositeLayupTaskDetailResponse(
|
||||
val code: Int = 0,
|
||||
val message: String = "",
|
||||
val data: CompositeLayupTaskDetail? = null,
|
||||
val success: Boolean = false
|
||||
)
|
||||
|
||||
data class CompositeLayupRecognizeResult(
|
||||
val finished: Boolean = false,
|
||||
val success: Boolean = false,
|
||||
val errorMessage: String = ""
|
||||
)
|
||||
|
||||
data class CompositeLayupRecognizeResponse(
|
||||
val code: Int = 0,
|
||||
val message: String = "",
|
||||
val data: CompositeLayupRecognizeResult? = null,
|
||||
val success: Boolean = false
|
||||
)
|
||||
@ -0,0 +1,26 @@
|
||||
package com.nova.brain.glass.repository
|
||||
|
||||
import com.nova.brain.glass.model.data.CompositeLayupRecognizeResponse
|
||||
import com.nova.brain.glass.model.data.CompositeLayupTaskDetailResponse
|
||||
import io.reactivex.Observable
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface Service4 {
|
||||
|
||||
@GET("/api/glass/workTask/queryTask")
|
||||
fun queryTask(@Query("taskNo") taskNo: String): Observable<CompositeLayupTaskDetailResponse>
|
||||
|
||||
@Multipart
|
||||
@POST("/api/glass/workTask/ocrRecognize")
|
||||
fun ocrRecognize(
|
||||
@Part("taskNo") taskNo: RequestBody,
|
||||
@Part("stepSeq") stepSeq: RequestBody,
|
||||
@Part file: MultipartBody.Part
|
||||
): Observable<CompositeLayupRecognizeResponse>
|
||||
}
|
||||
@ -0,0 +1,256 @@
|
||||
package com.nova.brain.glass.ui
|
||||
|
||||
import android.os.Environment
|
||||
import android.view.View
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.nova.brain.glass.R
|
||||
import com.nova.brain.glass.databinding.ActivityCompositeLayupTaskBinding
|
||||
import com.nova.brain.glass.helper.GlassMediaServiceHelper
|
||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||
import com.nova.brain.glass.viewmodel.CompositeLayupRecognizeState
|
||||
import com.nova.brain.glass.viewmodel.CompositeLayupTaskVM
|
||||
import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
|
||||
import com.rokid.security.system.server.media.callback.PhotoFileCallback
|
||||
import com.xuqm.base.common.LogHelper
|
||||
import com.xuqm.base.extensions.showMessage
|
||||
import com.xuqm.base.ui.BaseActivity
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
class CompositeLayupTaskActivity : BaseActivity<ActivityCompositeLayupTaskBinding>() {
|
||||
override fun getLayoutId(): Int = R.layout.activity_composite_layup_task
|
||||
override fun fullscreen(): Boolean = true
|
||||
|
||||
private enum class ScreenMode {
|
||||
START,
|
||||
STEP_SUCCESS,
|
||||
FAILED,
|
||||
FINISHED
|
||||
}
|
||||
|
||||
private val viewModel: CompositeLayupTaskVM by lazy {
|
||||
ViewModelProvider(this)[CompositeLayupTaskVM::class.java]
|
||||
}
|
||||
private val taskNoFromIntent: String by lazy {
|
||||
intent.getStringExtra(EXTRA_TASK_NO).orEmpty()
|
||||
}
|
||||
|
||||
private var isPhotoFallback = false
|
||||
private var isCaptureInFlight = false
|
||||
private var screenMode = ScreenMode.START
|
||||
|
||||
private val listener = object : OfflineCmdListener {
|
||||
override fun onOfflineCmd(cmd: String) {
|
||||
runOnUiThread {
|
||||
when (cmd) {
|
||||
"退出", "返回", "退回" -> finish()
|
||||
"开始", "开始任务" -> if (screenMode == ScreenMode.START) triggerCapture()
|
||||
"下一步", "继续识别", "继续任务" -> {
|
||||
if (screenMode == ScreenMode.STEP_SUCCESS) triggerCapture()
|
||||
}
|
||||
"重拍", "重新拍照", "重新拍摄" -> {
|
||||
if (screenMode == ScreenMode.FAILED) triggerCapture()
|
||||
}
|
||||
"完成任务" -> if (screenMode == ScreenMode.FINISHED) finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val photoCallbackId = UUID.randomUUID().toString()
|
||||
private val photoCallback = object : PhotoFileCallback.Stub() {
|
||||
override fun onTakePhoto(path: String) {
|
||||
LogHelper.d("CompositeLayupTask onTakePhoto: $path")
|
||||
}
|
||||
|
||||
override fun getCallbackId(): String = photoCallbackId
|
||||
|
||||
override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
|
||||
LogHelper.d("CompositeLayupTask onTakePhotoV2 width=$width height=$height path=$path")
|
||||
if (path == null) {
|
||||
if (isPhotoFallback) {
|
||||
isPhotoFallback = false
|
||||
takePhoto()
|
||||
} else {
|
||||
isCaptureInFlight = false
|
||||
runOnUiThread {
|
||||
updateHint("相机异常,请重试")
|
||||
}
|
||||
"相机异常".showMessage()
|
||||
}
|
||||
return
|
||||
}
|
||||
isCaptureInFlight = false
|
||||
runOnUiThread {
|
||||
updateHint("OCR识别中,请稍后...")
|
||||
viewModel.recognize(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initData() {
|
||||
super.initData()
|
||||
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
bindClicks()
|
||||
applyScreenMode(ScreenMode.START)
|
||||
observeViewModel()
|
||||
if (taskNoFromIntent.isBlank()) {
|
||||
updateHint("任务编号缺失")
|
||||
"任务编号缺失".showMessage()
|
||||
} else {
|
||||
viewModel.loadTaskDetail(taskNoFromIntent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindClicks() {
|
||||
binding.btnAction.setOnClickListener {
|
||||
when (screenMode) {
|
||||
ScreenMode.START, ScreenMode.STEP_SUCCESS, ScreenMode.FAILED -> triggerCapture()
|
||||
ScreenMode.FINISHED -> finish()
|
||||
}
|
||||
}
|
||||
binding.btnSecondary.setOnClickListener {
|
||||
if (screenMode == ScreenMode.FINISHED) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeViewModel() {
|
||||
viewModel.taskDetail.observe(this) { detail ->
|
||||
if (detail != null) {
|
||||
binding.tvTaskNo.text = "工号:${detail.taskNo.ifBlank { taskNoFromIntent }}"
|
||||
binding.tvTaskName.text = detail.taskName.ifBlank { "铺贴任务列表" }
|
||||
updateProgressText()
|
||||
}
|
||||
}
|
||||
viewModel.taskDetailError.observe(this) { msg ->
|
||||
if (msg.isNotBlank()) {
|
||||
updateHint(msg)
|
||||
msg.showMessage()
|
||||
}
|
||||
}
|
||||
viewModel.recognizeState.observe(this) { state ->
|
||||
when (state) {
|
||||
CompositeLayupRecognizeState.LOADING -> {
|
||||
binding.btnAction.isClickable = false
|
||||
updateHint("OCR识别中,请稍后...")
|
||||
}
|
||||
CompositeLayupRecognizeState.SUCCESS -> {
|
||||
binding.btnAction.isClickable = true
|
||||
handleRecognizeResult()
|
||||
}
|
||||
CompositeLayupRecognizeState.FAILED -> {
|
||||
binding.btnAction.isClickable = true
|
||||
val error = viewModel.recognizeError.value?.ifBlank { "OCR识别失败" } ?: "OCR识别失败"
|
||||
applyScreenMode(ScreenMode.FAILED, error)
|
||||
}
|
||||
else -> binding.btnAction.isClickable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRecognizeResult() {
|
||||
val result = viewModel.recognizeResult.value ?: return
|
||||
when {
|
||||
result.success && result.finished -> applyScreenMode(ScreenMode.FINISHED)
|
||||
result.success -> applyScreenMode(ScreenMode.STEP_SUCCESS)
|
||||
else -> applyScreenMode(ScreenMode.FAILED, result.errorMessage.ifBlank { "识别铺贴错误,请重新拍取" })
|
||||
}
|
||||
viewModel.resetRecognizeState()
|
||||
}
|
||||
|
||||
private fun triggerCapture() {
|
||||
if (isCaptureInFlight || taskNoFromIntent.isBlank()) {
|
||||
return
|
||||
}
|
||||
isCaptureInFlight = true
|
||||
binding.btnAction.isClickable = false
|
||||
updateHint("拍照中,请稍后...")
|
||||
takePhoto()
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
isPhotoFallback = true
|
||||
val fileName = "composite_layup_${System.currentTimeMillis()}.png"
|
||||
val file = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
||||
fileName
|
||||
)
|
||||
GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_720P, file.absolutePath)
|
||||
}
|
||||
|
||||
private fun updateProgressText() {
|
||||
binding.tvProgress.text = "任务进度:${viewModel.currentStepSeq}/${viewModel.totalSteps}"
|
||||
binding.tvStepHint.text = "识别到当前层第${viewModel.currentStepSeq}层 / 共${viewModel.totalSteps}层"
|
||||
}
|
||||
|
||||
private fun applyScreenMode(mode: ScreenMode, errorMessage: String = "") {
|
||||
screenMode = mode
|
||||
updateProgressText()
|
||||
binding.groupStart.visibility = if (mode == ScreenMode.START) View.VISIBLE else View.GONE
|
||||
binding.groupResult.visibility = if (mode == ScreenMode.START) View.GONE else View.VISIBLE
|
||||
binding.btnSecondary.visibility = if (mode == ScreenMode.FINISHED) View.VISIBLE else View.GONE
|
||||
when (mode) {
|
||||
ScreenMode.START -> {
|
||||
binding.resultIcon.setImageResource(R.mipmap.ocr_photo)
|
||||
binding.resultTitle.text = "请开始本层铺贴工作"
|
||||
binding.resultSubtitle.text = "语音输入“开始任务”或点击按钮后拍照识别"
|
||||
binding.btnAction.text = "开工"
|
||||
updateHint("左滑右滑选择任务,单击开工,开始该任务。")
|
||||
}
|
||||
ScreenMode.STEP_SUCCESS -> {
|
||||
binding.resultIcon.setImageResource(R.mipmap.ocr_true)
|
||||
binding.resultTitle.text = "识别铺贴层与料号信息正确"
|
||||
binding.resultSubtitle.text = "请开始下一层铺贴工作"
|
||||
binding.btnAction.text = "下一步"
|
||||
updateHint("当前层识别通过,可进入下一层识别。")
|
||||
}
|
||||
ScreenMode.FAILED -> {
|
||||
binding.resultIcon.setImageResource(R.mipmap.ocr_false)
|
||||
binding.resultTitle.text = errorMessage.ifBlank { "识别铺贴错误,请重新拍取" }
|
||||
binding.resultSubtitle.text = "请重新拍照识别"
|
||||
binding.btnAction.text = "重拍"
|
||||
updateHint(errorMessage.ifBlank { "识别失败,请重试" })
|
||||
}
|
||||
ScreenMode.FINISHED -> {
|
||||
binding.resultIcon.setImageResource(R.mipmap.ocr_true)
|
||||
binding.resultTitle.text = "恭喜完成全部铺贴逐层任务!"
|
||||
binding.resultSubtitle.text = "请点击返回,回到铺贴任务列表开启下一任务"
|
||||
binding.btnAction.text = "返回"
|
||||
binding.btnSecondary.text = "完成任务"
|
||||
updateHint("当前任务已全部完成。")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHint(text: String) {
|
||||
binding.hint.text = text
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
isCaptureInFlight = false
|
||||
binding.btnAction.isClickable = true
|
||||
GlassMediaServiceHelper.addPhotoCallback(photoCallback)
|
||||
OfflineCmdServiceHelper.addListenerCompositeLayup()
|
||||
OfflineCmdServiceHelper.addOnLineListener(listener)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
GlassMediaServiceHelper.removePhotoCallback(photoCallback)
|
||||
OfflineCmdServiceHelper.removeListenerCompositeLayup()
|
||||
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_TASK_NO = "extra_task_no"
|
||||
}
|
||||
}
|
||||
@ -124,13 +124,13 @@ class TaskListActivity :
|
||||
}
|
||||
|
||||
private fun routeToTask(item: TaskItem) {
|
||||
when (item.taskType) {
|
||||
"复材MES任务" -> startActivity(
|
||||
when {
|
||||
item.taskType == "复材MES任务" -> startActivity(
|
||||
Intent(this, FoActivity::class.java)
|
||||
.putExtra("aiDescription", item.displayDesc())
|
||||
.putExtra("taskType", item.taskType)
|
||||
)
|
||||
"审核任务" -> startActivity(
|
||||
item.taskType == "审核任务" -> startActivity(
|
||||
Intent(this, ReviewActivity::class.java)
|
||||
.putExtra("taskId", item.id)
|
||||
.putExtra("taskType", item.taskType)
|
||||
@ -149,19 +149,19 @@ class TaskListActivity :
|
||||
)
|
||||
)
|
||||
)
|
||||
"天镜检验任务" -> startActivity(
|
||||
item.taskType == "天镜检验任务" -> startActivity(
|
||||
Intent(this, SprayingActivity::class.java)
|
||||
.putExtra("taskId", item.params.firstNotBlank("taskId", "task_id", "id"))
|
||||
.putExtra("aiDescription", item.displayDesc())
|
||||
.putExtra("taskType", item.taskType)
|
||||
)
|
||||
"检验任务", "产业大脑检验任务" -> startActivity(
|
||||
item.taskType == "检验任务" || item.taskType == "产业大脑检验任务" -> startActivity(
|
||||
Intent(this, InspectionActivity::class.java)
|
||||
.putExtra("glassTaskId", item.params.firstNotBlank("taskId", "task_id", "id"))
|
||||
.putExtra("taskName", item.params?.get("taskName").orEmpty())
|
||||
.putExtra("taskNumber", item.params?.get("taskNumber").orEmpty())
|
||||
)
|
||||
"复材铺贴任务" -> startActivity(
|
||||
item.taskType.contains("复材铺贴任务") -> startActivity(
|
||||
Intent(this, CompositeLayupTaskActivity::class.java)
|
||||
.putExtra(
|
||||
CompositeLayupTaskActivity.EXTRA_TASK_NO,
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
package com.nova.brain.glass.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.nova.brain.glass.MyApplication
|
||||
import com.nova.brain.glass.model.data.CompositeLayupRecognizeResult
|
||||
import com.nova.brain.glass.model.data.CompositeLayupTaskDetail
|
||||
import com.nova.brain.glass.repository.Service4
|
||||
import com.xuqm.base.di.manager.HttpManager
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
|
||||
enum class CompositeLayupRecognizeState { IDLE, LOADING, SUCCESS, FAILED }
|
||||
|
||||
class CompositeLayupTaskVM : ViewModel() {
|
||||
|
||||
val taskDetail = MutableLiveData<CompositeLayupTaskDetail?>()
|
||||
val taskDetailError = MutableLiveData<String>()
|
||||
val recognizeState = MutableLiveData(CompositeLayupRecognizeState.IDLE)
|
||||
val recognizeResult = MutableLiveData<CompositeLayupRecognizeResult?>()
|
||||
val recognizeError = MutableLiveData<String>()
|
||||
|
||||
private val disposables = CompositeDisposable()
|
||||
var taskNo: String = ""
|
||||
var currentStepSeq: Int = 1
|
||||
private set
|
||||
var totalSteps: Int = 1
|
||||
private set
|
||||
|
||||
fun loadTaskDetail(taskNo: String) {
|
||||
this.taskNo = taskNo
|
||||
val disposable = HttpManager.getApi(MyApplication.appComponent4, Service4::class.java)
|
||||
.queryTask(taskNo)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ response ->
|
||||
if (response.success && response.data != null) {
|
||||
bindTaskDetail(response.data)
|
||||
} else {
|
||||
taskDetailError.value = response.message.ifBlank { "获取任务详情失败" }
|
||||
}
|
||||
}, { e ->
|
||||
taskDetailError.value = e.message ?: "获取任务详情失败"
|
||||
})
|
||||
disposables.add(disposable)
|
||||
}
|
||||
|
||||
fun recognize(photoPath: String) {
|
||||
val file = File(photoPath)
|
||||
if (!file.exists()) {
|
||||
recognizeState.value = CompositeLayupRecognizeState.FAILED
|
||||
recognizeError.value = "图片不存在"
|
||||
return
|
||||
}
|
||||
if (taskNo.isBlank()) {
|
||||
recognizeState.value = CompositeLayupRecognizeState.FAILED
|
||||
recognizeError.value = "任务编号为空"
|
||||
return
|
||||
}
|
||||
recognizeState.value = CompositeLayupRecognizeState.LOADING
|
||||
val taskNoBody = taskNo.toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val stepSeqBody = currentStepSeq.toString().toRequestBody("text/plain".toMediaTypeOrNull())
|
||||
val requestFile = file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
|
||||
val filePart = MultipartBody.Part.createFormData("file", file.name, requestFile)
|
||||
val disposable = HttpManager.getApi(MyApplication.appComponent4, Service4::class.java)
|
||||
.ocrRecognize(taskNoBody, stepSeqBody, filePart)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ response ->
|
||||
val result = response.data
|
||||
if (response.success && result != null) {
|
||||
recognizeResult.value = result
|
||||
recognizeState.value = CompositeLayupRecognizeState.SUCCESS
|
||||
if (result.success && !result.finished) {
|
||||
currentStepSeq = (currentStepSeq + 1).coerceAtMost(totalSteps.coerceAtLeast(1))
|
||||
}
|
||||
} else {
|
||||
recognizeState.value = CompositeLayupRecognizeState.FAILED
|
||||
recognizeError.value = response.message.ifBlank { "OCR识别失败" }
|
||||
}
|
||||
}, { e ->
|
||||
recognizeState.value = CompositeLayupRecognizeState.FAILED
|
||||
recognizeError.value = e.message ?: "OCR识别失败"
|
||||
})
|
||||
disposables.add(disposable)
|
||||
}
|
||||
|
||||
fun resetRecognizeState() {
|
||||
recognizeState.value = CompositeLayupRecognizeState.IDLE
|
||||
recognizeResult.value = null
|
||||
recognizeError.value = ""
|
||||
}
|
||||
|
||||
private fun bindTaskDetail(detail: CompositeLayupTaskDetail) {
|
||||
taskDetail.value = detail
|
||||
this.taskNo = detail.taskNo.ifBlank { taskNo }
|
||||
totalSteps = detail.taskSteps.coerceAtLeast(detail.detailList?.size ?: 1).coerceAtLeast(1)
|
||||
currentStepSeq = when {
|
||||
detail.taskCurrentStep > 0 -> detail.taskCurrentStep
|
||||
!detail.detailList.isNullOrEmpty() -> {
|
||||
detail.detailList.firstOrNull { it.detailStatus != 9 }?.stepSeq
|
||||
?: detail.detailList.last().stepSeq.coerceAtLeast(1)
|
||||
}
|
||||
else -> 1
|
||||
}.coerceIn(1, totalSteps)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
disposables.clear()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#00000000" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#40FF5E" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#4B7F5A" />
|
||||
<corners android:radius="10dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#00000000" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#40FF5E" />
|
||||
</shape>
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#050505" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#16A5FF" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#4B7F5A" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,194 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/app_color_black">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTaskHeader"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/bg_item"
|
||||
android:gravity="center"
|
||||
android:text="复材铺贴任务:逐层识别作业"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@drawable/bg_task_title_selected"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvTaskHeader">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTaskName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginVertical="3dp"
|
||||
android:gravity="center"
|
||||
android:text="铺贴任务1"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#ff40FF5E" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTaskNo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="任务编号:PT20260422001"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvProgress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="任务进度:1/12"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvStepHint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginVertical="4dp"
|
||||
android:text="当前识别层:第1层 / 共12层"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/baseRecyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="88dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/hint"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center"
|
||||
android:text="单击或语音输入"开始",进入下一步"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/groupStart"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnAction"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/hint">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="150dp"
|
||||
android:src="@mipmap/ocr_photo" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/groupResult"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnAction"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/hint">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/resultIcon"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="150dp"
|
||||
android:src="@mipmap/ocr_true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resultTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center"
|
||||
android:text="识别铺贴层与料号信息正确"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/resultSubtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:text="请开始下一层铺贴工作"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnSecondary"
|
||||
android:layout_width="138dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@drawable/bg_composite_button_solid"
|
||||
android:backgroundTint="@null"
|
||||
android:text="完成任务"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="20sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnAction"
|
||||
android:layout_width="148dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:background="@drawable/bg_composite_button_outline"
|
||||
android:backgroundTint="@null"
|
||||
android:text="开工"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="#ff40FF5E"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
正在加载...
在新工单中引用
屏蔽一个用户