Browse Source

feat(inspection): 添加成品件接收检验功能模块

- 在OfflineCmdServiceHelper中增加Inspect页面关键词监听功能
- 实现InspectionActivity页面重构,添加拍照功能和界面交互
- 创建InspectionResultActivity用于展示检验结果和操作选项
- 新增InspectionMissingActivity和InspectionCompleteActivity页面
- 集成GlassMediaServiceHelper拍照功能和照片回调处理
- 添加SprayingPhotoManager照片管理功能
- 更新界面布局文件activity_inspection.xml优化UI结构
- 在AndroidManifest.xml中注册新增的检验相关Activity
- 实现检验结果的随机生成和状态显示逻辑
徐勤民 1 day ago
parent
commit
d7b14b2bce

BIN
.gradle-home/daemon/7.3.3/registry.bin


BIN
.gradle-home/daemon/7.3.3/registry.bin.lock


+ 9 - 0
app/src/main/AndroidManifest.xml

@@ -78,6 +78,15 @@
         <activity
             android:name=".ui.InspectionActivity"
             android:exported="false" />
+        <activity
+            android:name=".ui.InspectionResultActivity"
+            android:exported="false" />
+        <activity
+            android:name=".ui.InspectionMissingActivity"
+            android:exported="false" />
+        <activity
+            android:name=".ui.InspectionCompleteActivity"
+            android:exported="false" />
         <activity
             android:name=".ui.SprayingActivity"
             android:exported="false" />

+ 44 - 0
app/src/main/java/com/nova/brain/glass/helper/OfflineCmdServiceHelper.kt

@@ -277,4 +277,48 @@ object OfflineCmdServiceHelper {
         ))
     }
 
+    // ---- Inspection 页面关键词 ----
+
+    fun addListenerInspectionResult(){
+        registerBeans(listOf(
+            OfflineCmdBean("重拍照", "chong pai zhao"),
+            OfflineCmdBean("结束任务", "jie shu ren wu"),
+            OfflineCmdBean("继续任务", "ji xu ren wu")
+        ))
+    }
+
+    fun removeListenerInspectionResult(){
+        removeBeans(listOf(
+            OfflineCmdBean("重拍照", "chong pai zhao"),
+            OfflineCmdBean("结束任务", "jie shu ren wu"),
+            OfflineCmdBean("继续任务", "ji xu ren wu")
+        ))
+    }
+
+    fun addListenerInspectionMissing(){
+        registerBeans(listOf(
+            OfflineCmdBean("补充单证", "bu chong dan zheng"),
+            OfflineCmdBean("继续提交", "ji xu ti jiao")
+        ))
+    }
+
+    fun removeListenerInspectionMissing(){
+        removeBeans(listOf(
+            OfflineCmdBean("补充单证", "bu chong dan zheng"),
+            OfflineCmdBean("继续提交", "ji xu ti jiao")
+        ))
+    }
+
+    fun addListenerInspectionComplete(){
+        registerBeans(listOf(
+            OfflineCmdBean("完成任务", "wan cheng ren wu")
+        ))
+    }
+
+    fun removeListenerInspectionComplete(){
+        removeBeans(listOf(
+            OfflineCmdBean("完成任务", "wan cheng ren wu")
+        ))
+    }
+
 }

+ 69 - 40
app/src/main/java/com/nova/brain/glass/ui/InspectionActivity.kt

@@ -1,73 +1,102 @@
 package com.nova.brain.glass.ui
 
-import androidx.recyclerview.widget.RecyclerView
+import android.content.Intent
+import android.os.Environment
+import android.view.WindowManager
 import com.nova.brain.glass.R
 import com.nova.brain.glass.databinding.ActivityInspectionBinding
+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.model.ItemItem
-import com.nova.brain.glass.viewmodel.ItemListVM
-import com.xuqm.base.adapter.BasePagedAdapter
-import com.xuqm.base.adapter.CommonPagedAdapter
-import com.xuqm.base.adapter.ViewHolder
-import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
+import com.nova.brain.glass.helper.SprayingPhotoManager
+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
+import kotlin.jvm.java
 
-class InspectionActivity : BaseListFormLayoutNormalActivity<ItemItem, ItemListVM, ActivityInspectionBinding>() {
-    override fun getLayoutId(): Int =R.layout.activity_inspection
+class InspectionActivity : BaseActivity<ActivityInspectionBinding>() {
+    override fun getLayoutId(): Int = R.layout.activity_inspection
     override fun fullscreen(): Boolean = true
 
-    override fun getRecyclerOrientation(): Int = RecyclerView.HORIZONTAL
-
     private val listener = object : OfflineCmdListener {
         override fun onOfflineCmd(cmd: String) {
             runOnUiThread {
-                when( cmd){
-                    "退出","返回","退回"->{
-                        finish()
-                    }
-                    "驳回","拒绝","不同意"->{
-                        finish()
-                    }
-                    "同意","通过"->{
-                        finish()
-                    }
+                when (cmd) {
+                    "退出", "返回", "退回" -> finish()
+                    "开始", "开始任务", "拍照" -> startCapture()
                 }
             }
         }
     }
+
     override fun initData() {
         super.initData()
-        window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+        SprayingPhotoManager.clear()
+        binding.btnCamera.setOnClickListener { startCapture() }
+        binding.btnPrev.setOnClickListener { /* 切换上一任务(待实现) */ }
+        binding.btnNext.setOnClickListener { /* 切换下一任务(待实现) */ }
+    }
+
+    private fun startCapture() {
+        binding.hint.text = "拍照中,请稍后..."
+        SprayingPhotoManager.clear()
+        takePhoto()
+    }
+
+    private fun takePhoto() {
+        val fileName = "inspection_${System.currentTimeMillis()}.png"
+        val file = File(
+            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
+            fileName
+        )
+        GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_480P, file.absolutePath)
+    }
+
+    private val photoCallbackId = UUID.randomUUID().toString()
+
+    private val mPhotoFileCallback = object : PhotoFileCallback.Stub() {
+        override fun onTakePhoto(path: String) {
+            LogHelper.d("onTakePhoto: $path")
+        }
+
+        override fun getCallbackId(): String = photoCallbackId
+
+        override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
+            if (path == null) {
+                runOnUiThread {
+                    binding.hint.text = "单击或语音输入\u201C开始\u201D,进入下一步\n滑动切换上/下一个任务"
+                }
+                "相机异常".showMessage()
+                return
+            }
+            SprayingPhotoManager.addPhoto(path)
+            runOnUiThread {
+                startActivity(Intent(this@InspectionActivity, InspectionResultActivity::class.java).apply {
+                    putExtra(InspectionResultActivity.EXTRA_PHOTO_PATH, path)
+                })
+            }
+        }
     }
 
     override fun onResume() {
         super.onResume()
-        OfflineCmdServiceHelper.addListenerInspection()
+        GlassMediaServiceHelper.addPhotoCallback(mPhotoFileCallback)
         OfflineCmdServiceHelper.addOnLineListener(listener)
     }
 
     override fun onPause() {
         super.onPause()
-        OfflineCmdServiceHelper.removeListenerInspection()
+        GlassMediaServiceHelper.removePhotoCallback(mPhotoFileCallback)
         OfflineCmdServiceHelper.removeOnLineListener(listener)
     }
 
     override fun onDestroy() {
         super.onDestroy()
-        window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
     }
-    private val adapter = object : CommonPagedAdapter<ItemItem>(R.layout.item_item) {
-        override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
-            holder
-                .setText(R.id.text, item.text)
-                .setClickListener(R.id.text) {
-                    when (item.text) {
-                        "同意" -> finish()
-                        "驳回" -> finish()
-                    }
-                }
-        }
-    }
-
-    override fun adapter(): BasePagedAdapter<ItemItem> = adapter
-}
+}

+ 53 - 0
app/src/main/java/com/nova/brain/glass/ui/InspectionCompleteActivity.kt

@@ -0,0 +1,53 @@
+package com.nova.brain.glass.ui
+
+import android.content.Intent
+import com.nova.brain.glass.R
+import com.nova.brain.glass.databinding.ActivityInspectionCompleteBinding
+import com.nova.brain.glass.helper.OfflineCmdListener
+import com.nova.brain.glass.helper.OfflineCmdServiceHelper
+import com.xuqm.base.ui.BaseActivity
+
+class InspectionCompleteActivity : BaseActivity<ActivityInspectionCompleteBinding>() {
+    override fun getLayoutId(): Int = R.layout.activity_inspection_complete
+    override fun fullscreen(): Boolean = true
+
+    companion object {
+        const val EXTRA_PHOTO_COUNT = "extra_photo_count"
+    }
+
+    private val listener = object : OfflineCmdListener {
+        override fun onOfflineCmd(cmd: String) {
+            runOnUiThread {
+                when (cmd) {
+                    "退出", "返回", "退回", "完成任务" -> finishTask()
+                }
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        val count = intent.getIntExtra(EXTRA_PHOTO_COUNT, 0)
+        binding.subtitle.text = "本次成功提交并归档${count}张单证!"
+        binding.btnFinish.setOnClickListener { finishTask() }
+    }
+
+    private fun finishTask() {
+        startActivity(Intent(this, TaskListActivity::class.java).apply {
+            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
+        })
+        finish()
+    }
+
+    override fun onResume() {
+        super.onResume()
+        OfflineCmdServiceHelper.addListenerInspectionComplete()
+        OfflineCmdServiceHelper.addOnLineListener(listener)
+    }
+
+    override fun onPause() {
+        super.onPause()
+        OfflineCmdServiceHelper.removeListenerInspectionComplete()
+        OfflineCmdServiceHelper.removeOnLineListener(listener)
+    }
+}

+ 77 - 0
app/src/main/java/com/nova/brain/glass/ui/InspectionMissingActivity.kt

@@ -0,0 +1,77 @@
+package com.nova.brain.glass.ui
+
+import android.app.Activity
+import android.content.Intent
+import androidx.recyclerview.widget.RecyclerView
+import com.nova.brain.glass.R
+import com.nova.brain.glass.databinding.ActivityInspectionMissingBinding
+import com.nova.brain.glass.helper.OfflineCmdListener
+import com.nova.brain.glass.helper.OfflineCmdServiceHelper
+import com.nova.brain.glass.model.ItemItem
+import com.nova.brain.glass.viewmodel.InspectionMissingVM
+import com.xuqm.base.adapter.BasePagedAdapter
+import com.xuqm.base.adapter.CommonPagedAdapter
+import com.xuqm.base.adapter.ViewHolder
+import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
+
+class InspectionMissingActivity :
+    BaseListFormLayoutNormalActivity<ItemItem, InspectionMissingVM, ActivityInspectionMissingBinding>() {
+
+    override fun getLayoutId(): Int = R.layout.activity_inspection_missing
+    override fun fullscreen(): Boolean = true
+    override fun getRecyclerOrientation(): Int = RecyclerView.VERTICAL
+
+    companion object {
+        const val EXTRA_ACTION = "extra_action"
+        const val ACTION_SUPPLEMENT = "supplement"
+        const val ACTION_SUBMIT = "submit"
+    }
+
+    private val listener = object : OfflineCmdListener {
+        override fun onOfflineCmd(cmd: String) {
+            runOnUiThread {
+                when (cmd) {
+                    "退出", "返回", "退回" -> finish()
+                    "补充单证" -> supplement()
+                    "继续提交" -> submit()
+                }
+            }
+        }
+    }
+
+    private fun supplement() {
+        setResult(Activity.RESULT_OK, Intent().putExtra(EXTRA_ACTION, ACTION_SUPPLEMENT))
+        finish()
+    }
+
+    private fun submit() {
+        setResult(Activity.RESULT_OK, Intent().putExtra(EXTRA_ACTION, ACTION_SUBMIT))
+        finish()
+    }
+
+    override fun onResume() {
+        super.onResume()
+        OfflineCmdServiceHelper.addListenerInspectionMissing()
+        OfflineCmdServiceHelper.addOnLineListener(listener)
+    }
+
+    override fun onPause() {
+        super.onPause()
+        OfflineCmdServiceHelper.removeListenerInspectionMissing()
+        OfflineCmdServiceHelper.removeOnLineListener(listener)
+    }
+
+    private val adapter = object : CommonPagedAdapter<ItemItem>(R.layout.item_manual_result_action) {
+        override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
+            holder.setText(R.id.text, item.text)
+                .setClickListener(R.id.actionRoot) {
+                    when (item.text) {
+                        "补充单证" -> supplement()
+                        "继续提交" -> submit()
+                    }
+                }
+        }
+    }
+
+    override fun adapter(): BasePagedAdapter<ItemItem> = adapter
+}

+ 224 - 0
app/src/main/java/com/nova/brain/glass/ui/InspectionResultActivity.kt

@@ -0,0 +1,224 @@
+package com.nova.brain.glass.ui
+
+import android.app.Activity
+import android.content.Intent
+import android.os.CountDownTimer
+import android.os.Environment
+import android.view.WindowManager
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.view.doOnLayout
+import androidx.recyclerview.widget.RecyclerView
+import com.nova.brain.glass.R
+import com.nova.brain.glass.databinding.ActivityInspectionResultBinding
+import com.nova.brain.glass.helper.BitmapDecodeHelper
+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.helper.SprayingPhotoManager
+import com.nova.brain.glass.model.ItemItem
+import com.nova.brain.glass.viewmodel.InspectionResultVM
+import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
+import com.rokid.security.system.server.media.callback.PhotoFileCallback
+import com.xuqm.base.adapter.BasePagedAdapter
+import com.xuqm.base.adapter.CommonPagedAdapter
+import com.xuqm.base.adapter.ViewHolder
+import com.xuqm.base.common.LogHelper
+import com.xuqm.base.extensions.showMessage
+import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
+import java.io.File
+import java.util.UUID
+import java.util.concurrent.Executors
+import kotlin.random.Random
+
+class InspectionResultActivity :
+    BaseListFormLayoutNormalActivity<ItemItem, InspectionResultVM, ActivityInspectionResultBinding>() {
+
+    override fun getLayoutId(): Int = R.layout.activity_inspection_result
+    override fun fullscreen(): Boolean = true
+    override fun getRecyclerOrientation(): Int = RecyclerView.HORIZONTAL
+
+    private val imageDecodeExecutor = Executors.newSingleThreadExecutor()
+    private var status = true  // true=合格, false=不合格
+    private var resultCountdown: CountDownTimer? = null
+
+    companion object {
+        const val EXTRA_PHOTO_PATH = "extra_photo_path"
+    }
+
+    private val missingLauncher =
+        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+            if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult
+            when (result.data?.getStringExtra(InspectionMissingActivity.EXTRA_ACTION)) {
+                InspectionMissingActivity.ACTION_SUPPLEMENT -> {
+                    // 补充单证:重新拍照
+                    binding.tvTaskHeader.text = "拍照中,请稍后..."
+                    takePhoto()
+                }
+                InspectionMissingActivity.ACTION_SUBMIT -> {
+                    goComplete()
+                }
+            }
+        }
+
+    private val listener = object : OfflineCmdListener {
+        override fun onOfflineCmd(cmd: String) {
+            runOnUiThread {
+                when (cmd) {
+                    "退出", "返回", "退回" -> finish()
+                    "重拍照" -> retake()
+                    "继续任务" -> continueTask()
+                    "结束任务" -> endTask()
+                }
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+        val path = intent.getStringExtra(EXTRA_PHOTO_PATH)
+        if (path != null) {
+            showPhoto(path)
+        }
+        // 拍完照等待5秒后显示结果
+        startResultCountdown()
+    }
+
+    /** 等待 5 秒后随机显示合格/不合格结果 */
+    private fun startResultCountdown(seconds: Long = 5) {
+        binding.tvTaskHeader.text = "识别中,请稍后..."
+        resultCountdown?.cancel()
+        resultCountdown = object : CountDownTimer(seconds * 1000, 1000) {
+            override fun onTick(millisUntilFinished: Long) {}
+            override fun onFinish() {
+                status = Random.nextBoolean()
+                runOnUiThread { updateResultDisplay() }
+            }
+        }.start()
+    }
+
+    private fun updateResultDisplay() {
+        binding.tvTaskHeader.text = if (status) "检验结果:合格!" else "检验结果:不合格!"
+        binding.status.setImageResource(if (status) R.mipmap.ocr_true else R.mipmap.ocr_false)
+    }
+
+    private fun retake() {
+        binding.tvTaskHeader.text = "重新拍照中,请稍后..."
+        takePhoto()
+    }
+
+    private fun continueTask() {
+        binding.tvTaskHeader.text = "拍照中,请稍后..."
+        takePhoto()
+    }
+
+    private fun endTask() {
+        // 随机进入单证缺失或单证齐全
+        if (Random.nextBoolean()) {
+            missingLauncher.launch(Intent(this, InspectionMissingActivity::class.java))
+        } else {
+            goComplete()
+        }
+    }
+
+    private fun goComplete() {
+        val photoCount = SprayingPhotoManager.getPhotoCount()
+        SprayingPhotoManager.clear()
+        startActivity(Intent(this, InspectionCompleteActivity::class.java).apply {
+            putExtra(InspectionCompleteActivity.EXTRA_PHOTO_COUNT, photoCount)
+        })
+        finish()
+    }
+
+    // ---- 拍照 ----
+
+    private fun takePhoto() {
+        val fileName = "inspection_${System.currentTimeMillis()}.png"
+        val file = File(
+            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
+            fileName
+        )
+        GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_480P, file.absolutePath)
+    }
+
+    private val photoCallbackId = UUID.randomUUID().toString()
+
+    private val mPhotoFileCallback = object : PhotoFileCallback.Stub() {
+        override fun onTakePhoto(path: String) {
+            LogHelper.d("onTakePhoto: $path")
+        }
+
+        override fun getCallbackId(): String = photoCallbackId
+
+        override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
+            if (path == null) {
+                runOnUiThread {
+                    binding.tvTaskHeader.text = "相机异常,请重试"
+                }
+                "相机异常".showMessage()
+                return
+            }
+            SprayingPhotoManager.addPhoto(path)
+            runOnUiThread {
+                showPhoto(path)
+                // 重拍/继续任务:等待3秒后刷新结果
+                startResultCountdown(3)
+            }
+        }
+    }
+
+    private fun showPhoto(path: String) {
+        binding.iv.doOnLayout {
+            val w = it.width.coerceAtLeast(1)
+            val h = it.height.coerceAtLeast(1)
+            imageDecodeExecutor.execute {
+                val bitmap = BitmapDecodeHelper.decodeSampledBitmap(path, w, h)
+                runOnUiThread {
+                    if (!isFinishing && !isDestroyed) {
+                        binding.iv.setImageBitmap(bitmap)
+                    }
+                }
+            }
+        }
+    }
+
+    // ---- 生命周期 ----
+
+    override fun onResume() {
+        super.onResume()
+        OfflineCmdServiceHelper.addListenerInspectionResult()
+        OfflineCmdServiceHelper.addOnLineListener(listener)
+        GlassMediaServiceHelper.addPhotoCallback(mPhotoFileCallback)
+    }
+
+    override fun onPause() {
+        super.onPause()
+        resultCountdown?.cancel()
+        OfflineCmdServiceHelper.removeListenerInspectionResult()
+        OfflineCmdServiceHelper.removeOnLineListener(listener)
+        GlassMediaServiceHelper.removePhotoCallback(mPhotoFileCallback)
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        binding.iv.setImageDrawable(null)
+        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+    }
+
+    // ---- Adapter ----
+
+    private val adapter = object : CommonPagedAdapter<ItemItem>(R.layout.item_manual_result_action) {
+        override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
+            holder.setText(R.id.text, item.text)
+                .setClickListener(R.id.actionRoot) {
+                    when (item.text) {
+                        "重拍照" -> retake()
+                        "结束任务" -> endTask()
+                        "继续任务" -> continueTask()
+                    }
+                }
+        }
+    }
+
+    override fun adapter(): BasePagedAdapter<ItemItem> = adapter
+}

+ 14 - 0
app/src/main/java/com/nova/brain/glass/viewmodel/InspectionMissingVM.kt

@@ -0,0 +1,14 @@
+package com.nova.brain.glass.viewmodel
+
+import com.nova.brain.glass.model.ItemItem
+import com.xuqm.base.viewmodel.BaseListViewModel
+import com.xuqm.base.viewmodel.callback.Response
+
+class InspectionMissingVM : BaseListViewModel<ItemItem>() {
+    override fun loadData(page: Int, onResponse: Response<ItemItem>) {
+        onResponse.onResponse(arrayListOf<ItemItem>().apply {
+            add(ItemItem("补充单证"))
+            add(ItemItem("继续提交"))
+        })
+    }
+}

+ 15 - 0
app/src/main/java/com/nova/brain/glass/viewmodel/InspectionResultVM.kt

@@ -0,0 +1,15 @@
+package com.nova.brain.glass.viewmodel
+
+import com.nova.brain.glass.model.ItemItem
+import com.xuqm.base.viewmodel.BaseListViewModel
+import com.xuqm.base.viewmodel.callback.Response
+
+class InspectionResultVM : BaseListViewModel<ItemItem>() {
+    override fun loadData(page: Int, onResponse: Response<ItemItem>) {
+        onResponse.onResponse(arrayListOf<ItemItem>().apply {
+            add(ItemItem("重拍照"))
+            add(ItemItem("结束任务"))
+            add(ItemItem("继续任务"))
+        })
+    }
+}

+ 73 - 24
app/src/main/res/layout/activity_inspection.xml

@@ -1,6 +1,5 @@
 <?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:id="@+id/main"
@@ -12,9 +11,10 @@
             android:id="@+id/tvTaskHeader"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_marginTop="67dp"
+            android:layout_marginTop="16dp"
             android:background="@drawable/bg_item"
-            android:text="装配工序喷涂识别:您还有10项任务未完成!"
+            android:gravity="center"
+            android:text="成品件接收检验:您还有10项任务未完成!"
             android:textColor="#ff40FF5E"
             android:textSize="20sp"
             app:layout_constraintEnd_toEndOf="parent"
@@ -22,8 +22,8 @@
             app:layout_constraintTop_toTopOf="parent" />
 
         <LinearLayout
-            android:layout_width="match_parent"
             android:id="@+id/content"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_marginTop="10dp"
             android:background="@drawable/bg_task_title_selected"
@@ -39,7 +39,7 @@
                 android:layout_gravity="center"
                 android:layout_marginVertical="3dp"
                 android:gravity="center"
-                android:text="任务1:管线编号与机身喷码核对"
+                android:text="任务1"
                 android:textColor="#ff40FF5E"
                 android:textSize="18sp"
                 android:textStyle="bold" />
@@ -57,49 +57,98 @@
                 android:layout_marginTop="4dp"
                 android:text="任务编号:20293989-001"
                 android:textColor="#ff40FF5E"
-                android:textSize="14sp"/>
+                android:textSize="14sp" />
 
             <TextView
                 android:id="@+id/content2"
                 android:layout_width="match_parent"
-                android:layout_marginStart="15dp"
                 android:layout_height="wrap_content"
+                android:layout_marginStart="15dp"
                 android:layout_marginTop="4dp"
                 android:text="制造供应商:中航成飞民用飞机有限责任公司"
                 android:textColor="#ff40FF5E"
-                android:textSize="14sp"/>
+                android:textSize="14sp" />
 
             <TextView
                 android:id="@+id/content3"
                 android:layout_width="match_parent"
-                android:layout_marginStart="15dp"
                 android:layout_height="wrap_content"
+                android:layout_marginStart="15dp"
                 android:layout_marginVertical="4dp"
                 android:text="任务创建时间:2026-03-09 16:00:00"
                 android:textColor="#ff40FF5E"
-                android:textSize="14sp"/>
-
+                android:textSize="14sp" />
         </LinearLayout>
 
-        <androidx.recyclerview.widget.RecyclerView
-            android:id="@+id/baseRecyclerView"
+        <!-- 拍照区:左箭头 | 相机按钮 | 右箭头 -->
+        <LinearLayout
+            android:id="@+id/cameraRow"
             android:layout_width="0dp"
-            android:layout_height="88dp"
-            android:layout_marginTop="12dp"
-            android:overScrollMode="never"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toBottomOf="@id/content" />
+            app:layout_constraintTop_toBottomOf="@+id/content">
+
+            <TextView
+                android:id="@+id/btnPrev"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="◀"
+                android:textColor="#ff40FF5E"
+                android:textSize="32sp" />
+
+            <LinearLayout
+                android:id="@+id/btnCamera"
+                android:layout_width="88dp"
+                android:layout_height="88dp"
+                android:background="@drawable/bg_photo"
+                android:gravity="center"
+                android:orientation="vertical">
+
+                <ImageView
+                    android:layout_width="30dp"
+                    android:layout_height="24dp"
+                    android:src="@mipmap/paizhao" />
+
+                <TextView
+                    android:id="@+id/btnCameraText"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="6dp"
+                    android:gravity="center"
+                    android:text="开始任务"
+                    android:textColor="#ff40FF5E"
+                    android:textSize="14sp" />
+            </LinearLayout>
+
+            <TextView
+                android:id="@+id/btnNext"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="▶"
+                android:textColor="#ff40FF5E"
+                android:textSize="32sp" />
+        </LinearLayout>
+
         <TextView
-            android:layout_width="match_parent"
-            android:layout_marginStart="15dp"
+            android:id="@+id/hint"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView"
-            android:layout_marginVertical="4dp"
+            android:layout_marginTop="12dp"
             android:gravity="center"
-            android:text="单击或语音输入“开始”,进入下一步"
+            android:text='单击或语音输入"开始",进入下一步\n滑动切换上/下一个任务'
             android:textColor="#ff40FF5E"
-            android:textSize="14sp"/>
+            android:textSize="14sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/cameraRow" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
-</layout>
+</layout>

+ 80 - 0
app/src/main/res/layout/activity_inspection_complete.xml

@@ -0,0 +1,80 @@
+<?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">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="80dp"
+            android:layout_height="80dp"
+            android:layout_marginTop="60dp"
+            android:src="@mipmap/ocr_true"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:gravity="center"
+            android:text="本次任务:单证齐全"
+            android:textColor="#ff40FF5E"
+            android:textSize="22sp"
+            android:textStyle="bold"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/icon" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:gravity="center"
+            android:text="本次成功提交并归档3张单证!"
+            android:textColor="#ff40FF5E"
+            android:textSize="15sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/title" />
+
+        <FrameLayout
+            android:id="@+id/btnFinish"
+            android:layout_width="230dp"
+            android:layout_height="64dp"
+            android:layout_marginTop="40dp"
+            android:background="@drawable/bg_item"
+            android:foreground="?attr/selectableItemBackground"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/subtitle">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:text="完成任务"
+                android:textColor="#ff40FF5E"
+                android:textSize="20sp" />
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/hint"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:gravity="center"
+            android:text='单击或语音输入"完成任务",结束本次任务'
+            android:textColor="#ff40FF5E"
+            android:textSize="13sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/btnFinish" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 86 - 0
app/src/main/res/layout/activity_inspection_missing.xml

@@ -0,0 +1,86 @@
+<?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">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="80dp"
+            android:layout_height="80dp"
+            android:layout_marginTop="32dp"
+            android:src="@mipmap/ocr_false"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:gravity="center"
+            android:text="本次任务:单证缺失"
+            android:textColor="#ff40FF5E"
+            android:textSize="22sp"
+            android:textStyle="bold"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/icon" />
+
+        <TextView
+            android:id="@+id/subtitle"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="6dp"
+            android:gravity="center"
+            android:text="缺失2张单证,建议补充后提交!"
+            android:textColor="#ff40FF5E"
+            android:textSize="15sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/title" />
+
+        <TextView
+            android:id="@+id/missingList"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="32dp"
+            android:layout_marginTop="12dp"
+            android:lineSpacingExtra="6dp"
+            android:text="·XX件号XX序列号缺少「合格证」\n·XX件号XX序列号缺少「装箱单」"
+            android:textColor="#ff40FF5E"
+            android:textSize="14sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/subtitle" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/baseRecyclerView"
+            android:layout_width="230dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:overScrollMode="never"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/missingList" />
+
+        <TextView
+            android:id="@+id/hint"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="24dp"
+            android:layout_marginTop="16dp"
+            android:gravity="center"
+            android:lineSpacingExtra="6dp"
+            android:text='单击或语音输入"补充单证",继续拍摄单证\n单击或语音输入"继续提交",提交并结束该任务'
+            android:textColor="#ff40FF5E"
+            android:textSize="13sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>

+ 129 - 0
app/src/main/res/layout/activity_inspection_result.xml

@@ -0,0 +1,129 @@
+<?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:id="@+id/main"
+        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" />
+
+        <!-- 结果卡片 -->
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/cardResult"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/bg_task_title_selected"
+            android:padding="10dp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tvTaskHeader">
+
+            <ImageView
+                android:id="@+id/iv"
+                android:layout_width="100dp"
+                android:layout_height="130dp"
+                android:background="@drawable/bg_task_title_selected"
+                android:padding="2dp"
+                android:scaleType="centerCrop"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="10dp"
+                android:orientation="vertical"
+                app:layout_constraintBottom_toBottomOf="parent"
+                app:layout_constraintEnd_toStartOf="@+id/status"
+                app:layout_constraintStart_toEndOf="@+id/iv"
+                app:layout_constraintTop_toTopOf="parent">
+
+                <TextView
+                    android:id="@+id/value1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="单证类型:合格证"
+                    android:textColor="#ff40FF5E"
+                    android:textSize="14sp" />
+
+                <TextView
+                    android:id="@+id/value2"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp"
+                    android:text="件号:20293989-001"
+                    android:textColor="#ff40FF5E"
+                    android:textSize="14sp" />
+
+                <TextView
+                    android:id="@+id/value3"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp"
+                    android:text="序列号:20293989-001"
+                    android:textColor="#ff40FF5E"
+                    android:textSize="14sp" />
+
+                <TextView
+                    android:id="@+id/value4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="10dp"
+                    android:text="供应商:中航成飞民用飞机有限责任公司"
+                    android:textColor="#ff40FF5E"
+                    android:textSize="14sp" />
+            </LinearLayout>
+
+            <!-- 合格/不合格 角标 -->
+            <ImageView
+                android:id="@+id/status"
+                android:layout_width="70dp"
+                android:layout_height="70dp"
+                android:src="@mipmap/ocr_true"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toTopOf="parent" />
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/baseRecyclerView"
+            android:layout_width="0dp"
+            android:layout_height="88dp"
+            android:layout_marginTop="16dp"
+            android:overScrollMode="never"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/cardResult" />
+
+        <TextView
+            android:id="@+id/hint"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:gravity="center"
+            android:lineSpacingExtra="4dp"
+            android:text='单击或语音输入"重拍照",重新拍摄当前证件\n单击或语音输入"继续任务",继续拍摄下一张证件\n单击或语音输入"结束任务",结束全部拍摄并提交'
+            android:textColor="#ff40FF5E"
+            android:textSize="13sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</layout>