feat: 搜索页支持JSON扫码直达,去掉前缀提示

- 搜索输入框内容若是JSON则解码,type为ops_sys时根据module跳转(workorder→工单详情,item→物品详情)
- JSON解码后无论type是否为ops_sys都清空输入框
- 非JSON内容走原有关键字搜索逻辑
- 去掉前缀快捷搜索提示文本
This commit is contained in:
2026-06-26 20:46:58 +08:00
parent a7d81d42ea
commit b7dab20751
3 changed files with 42 additions and 14 deletions
@@ -111,7 +111,13 @@ fun OPSNavGraph(isLoggedIn: Boolean) {
onWorkOrderClick = { id -> rootNavController.navigate(Routes.workOrderDetail(id)) }, onWorkOrderClick = { id -> rootNavController.navigate(Routes.workOrderDetail(id)) },
onItemClick = { id -> rootNavController.navigate(Routes.itemDetail(id)) }, onItemClick = { id -> rootNavController.navigate(Routes.itemDetail(id)) },
onContainerClick = { id -> rootNavController.navigate(Routes.MAIN) }, onContainerClick = { id -> rootNavController.navigate(Routes.MAIN) },
onBack = { rootNavController.popBackStack() } onBack = { rootNavController.popBackStack() },
onOpsSysNavigate = { module, id ->
when (module) {
"workorder" -> rootNavController.navigate(Routes.workOrderDetail(id))
"item" -> rootNavController.navigate(Routes.itemDetail(id))
}
}
) )
} }
composable(Routes.SCHEDULE) { composable(Routes.SCHEDULE) {
@@ -28,7 +28,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
@@ -51,7 +51,8 @@ fun SearchScreen(
onWorkOrderClick: (Int) -> Unit, onWorkOrderClick: (Int) -> Unit,
onItemClick: (Int) -> Unit, onItemClick: (Int) -> Unit,
onContainerClick: (Int) -> Unit, onContainerClick: (Int) -> Unit,
onBack: () -> Unit onBack: () -> Unit,
onOpsSysNavigate: (module: String, id: Int) -> Unit
) { ) {
val appContainer = LocalAppContainer.current val appContainer = LocalAppContainer.current
val viewModel: SearchViewModel = viewModel( val viewModel: SearchViewModel = viewModel(
@@ -67,6 +68,13 @@ fun SearchScreen(
if (granted) showScanner = true if (granted) showScanner = true
} }
LaunchedEffect(uiState.opsSysNavigation) {
uiState.opsSysNavigation?.let { navInfo ->
onOpsSysNavigate(navInfo.module, navInfo.id)
viewModel.clearOpsSysNavigation()
}
}
fun checkCameraAndScan() { fun checkCameraAndScan() {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
hasCameraPermission = true hasCameraPermission = true
@@ -128,14 +136,6 @@ fun SearchScreen(
} }
} }
// Prefix hints
Text(
"前缀快捷搜索: po:采购单 wo:工单 item:物品 warehouse:容器",
fontSize = 11.sp,
color = Color.Gray,
modifier = Modifier.padding(horizontal = 16.dp),
textAlign = TextAlign.Center
)
// Category tabs // Category tabs
PrimaryScrollableTabRow( PrimaryScrollableTabRow(
@@ -7,7 +7,6 @@ import com.example.ops_android.data.model.Container
import com.example.ops_android.data.model.Item import com.example.ops_android.data.model.Item
import com.example.ops_android.data.model.PurchaseOrder import com.example.ops_android.data.model.PurchaseOrder
import com.example.ops_android.data.model.WorkOrder import com.example.ops_android.data.model.WorkOrder
import com.example.ops_android.data.repository.CustomerRepository
import com.example.ops_android.data.repository.OrderRepository import com.example.ops_android.data.repository.OrderRepository
import com.example.ops_android.data.repository.WarehouseRepository import com.example.ops_android.data.repository.WarehouseRepository
import com.example.ops_android.data.repository.WorkOrderRepository import com.example.ops_android.data.repository.WorkOrderRepository
@@ -15,6 +14,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.json.JSONObject
enum class SearchCategory(val label: String) { enum class SearchCategory(val label: String) {
ALL("全部"), ALL("全部"),
@@ -24,6 +24,11 @@ enum class SearchCategory(val label: String) {
CONTAINER("容器") CONTAINER("容器")
} }
data class OpsSysNavInfo(
val module: String,
val id: Int
)
data class SearchUiState( data class SearchUiState(
val query: String = "", val query: String = "",
val category: SearchCategory = SearchCategory.ALL, val category: SearchCategory = SearchCategory.ALL,
@@ -32,7 +37,8 @@ data class SearchUiState(
val items: List<Item> = emptyList(), val items: List<Item> = emptyList(),
val containers: List<Container> = emptyList(), val containers: List<Container> = emptyList(),
val isSearching: Boolean = false, val isSearching: Boolean = false,
val errorMessage: String? = null val errorMessage: String? = null,
val opsSysNavigation: OpsSysNavInfo? = null
) )
class SearchViewModel( class SearchViewModel(
@@ -61,7 +67,19 @@ class SearchViewModel(
val query = _uiState.value.query.trim() val query = _uiState.value.query.trim()
if (query.isEmpty()) return if (query.isEmpty()) return
// Parse prefix shortcuts val jsonObj = try { JSONObject(query) } catch (e: Exception) { null }
if (jsonObj != null) {
_uiState.value = _uiState.value.copy(query = "")
if (jsonObj.optString("type") == "ops_sys") {
val module = jsonObj.optString("module")
val id = jsonObj.optInt("id")
if (module.isNotBlank() && id > 0) {
_uiState.value = _uiState.value.copy(opsSysNavigation = OpsSysNavInfo(module, id))
}
}
return
}
val (actualCategory, actualQuery) = parsePrefix(query) val (actualCategory, actualQuery) = parsePrefix(query)
_uiState.value = _uiState.value.copy(category = actualCategory) _uiState.value = _uiState.value.copy(category = actualCategory)
@@ -125,6 +143,10 @@ class SearchViewModel(
_uiState.value = SearchUiState(query = _uiState.value.query, category = _uiState.value.category) _uiState.value = SearchUiState(query = _uiState.value.query, category = _uiState.value.category)
} }
fun clearOpsSysNavigation() {
_uiState.value = _uiState.value.copy(opsSysNavigation = null)
}
private fun parsePrefix(query: String): Pair<SearchCategory, String> { private fun parsePrefix(query: String): Pair<SearchCategory, String> {
val prefixes = mapOf( val prefixes = mapOf(
"po:" to SearchCategory.ORDER, "po:" to SearchCategory.ORDER,