fix/feat: 修复数据不稳定弹窗重复弹出 & 新增切换环境功能

fix: FoodRecognizeActivity 数据不稳定时弹窗会重复弹出
- 持有 unstableDialog 引用,通过 isShowing 防止重复弹出

feat: 新增切换环境功能(测试/UAT/生产)
- GlobalData 新增 KEY_BASE_URL,修正 UAT 端口为 8083
- SettingActivity 开发模式下显示「切换环境」入口
- 新增 EnvSwitchDialog 及其布局文件

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 17:18:30 +08:00
co-authored by Claude Sonnet 4.6
parent 301f470274
commit 61d11c6a78
7 changed files with 143 additions and 52 deletions
@@ -14,7 +14,7 @@ object GlobalData {
* 具体业务 BaseUrl
*/
const val TEST_BASE_URL = "http://192.168.1.201:14801"
const val UAT_BASE_URL = "https://dev.yixiong-tech.com:8081"
const val UAT_BASE_URL = "https://dev.yixiong-tech.com:8083"
const val PROD_BASE_URL = "https://api.dm.yixiong-tech.com:8443"
/**
* 设备id
@@ -37,4 +37,5 @@ object GlobalKey {
const val KEY_TOKEN = "tokenKey"
const val KEY_USER_INFO = "userInfoKey"
const val KEY_USER_NAME = "userNameKey"
const val KEY_BASE_URL = "baseUrl"
}
@@ -48,6 +48,16 @@ class DbViewModel : ViewModel() {
}
}
/**
* 直接返回本地烹饪中数据,供需要串行等待结果的场景使用(如先查库再发网络请求)
*/
suspend fun getCookFoodListDirect(
cookMode: Int,
dinnerType: String = "0"
): MutableList<CookFoodEntity>? {
return rep.getCookFoodList(cookMode, dinnerType)
}
suspend fun countCookFood(cookMode: Int): Int {
return rep.countCookFood(cookMode)
}
@@ -1,70 +1,69 @@
package com.sw.inbound.dialog
package com.shuwei.dish.match.dialog
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import com.sw.inbound.GlobalData
import com.sw.inbound.GlobalKey
import com.sw.inbound.databinding.DialogEnvSwitchBinding
import com.sw.inbound.utils.SPUtil
import com.sw.inbound.utils.ext.dp
import com.sw.inbound.utils.ext.toast
import com.shuwei.dish.match.base.GlobalData
import com.shuwei.dish.match.base.GlobalKey
import com.shuwei.dish.match.databinding.DialogEnvSwitchContentBinding
import com.shuwei.dish.match.utils.SpTool
import com.shuwei.dish.match.utils.ext.toast
/**
* 环境切换弹窗
*
* 提供 TEST / UAT / PROD 三套环境的切换功能,
* 初始化时自动根据 [GlobalData.appBaseUrl] 选中当前环境,
* 确认后更新 [GlobalData.appBaseUrl] 并通过 [onEnvChanged] 回调通知外部。
* 基于 [CommonDialog] 实现,通过 addContentView 注入 RadioGroup 内容区。
* 提供 TEST / UAT / PROD 三套环境的切换功能,初始化时自动根据
* [GlobalData.appBaseUrl] 选中当前环境,确认后更新 [GlobalData.appBaseUrl]
* 并通过 [onEnvChanged] 回调通知外部。
*
* @param context 上下文
* @param onEnvChanged 确认切换后的回调,参数为新的 baseUrl
* @param context 上下文
* @param onEnvChanged 确认切换后的回调,参数为新的 baseUrl
*/
class EnvSwitchDialog(
context: Context,
private val onEnvChanged: (newBaseUrl: String) -> Unit = {}
) : BaseDialog(
context,
defWidth = 600.dp,
defHeight = WindowManager.LayoutParams.WRAP_CONTENT
) {
private lateinit var binding: DialogEnvSwitchBinding
private val contentBinding = DialogEnvSwitchContentBinding.inflate(LayoutInflater.from(context))
override fun getRootView(): View {
binding = DialogEnvSwitchBinding.inflate(LayoutInflater.from(context))
return binding.root
}
override fun initView() {
// 根据当前 appBaseUrl 预选对应 RadioButton,不匹配则不选
when (GlobalData.appBaseUrl) {
GlobalData.TEST_BASE_URL -> binding.rbTest.isChecked = true
GlobalData.UAT_BASE_URL -> binding.rbUat.isChecked = true
GlobalData.PROD_BASE_URL -> binding.rbProd.isChecked = true
private val dialog = CommonDialog(context)
.setTitle("切换环境")
.addContentView(contentBinding.root) { tvContent ->
// 内容区已由 RadioGroup 承载,隐藏默认文本
tvContent.visibility = View.GONE
}
// 取消按钮
binding.btnCancel.setOnClickListener { dismiss() }
// 确认按钮
binding.btnConfirm.setOnClickListener {
// 未选中任何选项时提示用户
if (binding.rgEnv.checkedRadioButtonId == -1) {
.setNegativeButton("取消")
.setPositiveButtonInterceptable("确认") {
// 未选中任何选项时提示并阻止关闭
if (contentBinding.rgEnv.checkedRadioButtonId == -1) {
context.toast("请选择环境")
return@setOnClickListener
return@setPositiveButtonInterceptable false
}
val newUrl = when (binding.rgEnv.checkedRadioButtonId) {
binding.rbTest.id -> GlobalData.TEST_BASE_URL
binding.rbUat.id -> GlobalData.UAT_BASE_URL
binding.rbProd.id -> GlobalData.PROD_BASE_URL
else -> return@setOnClickListener
val newUrl = when (contentBinding.rgEnv.checkedRadioButtonId) {
contentBinding.rbTest.id -> GlobalData.TEST_BASE_URL
contentBinding.rbUat.id -> GlobalData.UAT_BASE_URL
contentBinding.rbProd.id -> GlobalData.PROD_BASE_URL
else -> return@setPositiveButtonInterceptable false
}
GlobalData.appBaseUrl = newUrl
SPUtil.getInstance().put(GlobalKey.KEY_BASE_URL, newUrl)
SpTool.put(GlobalKey.KEY_BASE_URL, newUrl)
onEnvChanged(newUrl)
dismiss()
true
}
init {
// 根据当前 appBaseUrl 预选对应 RadioButton
when (GlobalData.appBaseUrl) {
GlobalData.TEST_BASE_URL -> contentBinding.rbTest.isChecked = true
GlobalData.UAT_BASE_URL -> contentBinding.rbUat.isChecked = true
GlobalData.PROD_BASE_URL -> contentBinding.rbProd.isChecked = true
}
}
/** 显示弹窗 */
fun show() = dialog.show()
/** 关闭弹窗 */
fun dismiss() = dialog.dismiss()
}
@@ -117,6 +117,9 @@ class FoodRecognizeActivity : BaseActivity() {
/** 食材搜索弹窗,持有引用防止重复打开 */
private var foodSearchDialog: FoodSearchDialog? = null
/** 数据不稳定提示弹窗,持有引用通过 isShowing 防止重复弹出 */
private var unstableDialog: CommonDialog? = null
/** 通过name查询IdNameScore */
private val nameScoreMap = mutableMapOf<String, FoodModule.IdNameScore>()
@@ -506,12 +509,15 @@ class FoodRecognizeActivity : BaseActivity() {
// 被动关闭:从窗口取稳定值
val stableWeight = getStableWeightFromWindow()
if (stableWeight == null) {
// 数据不稳定,不关闭页面,弹窗提示
CommonDialog(this)
.setTitle("提示")
.setContent("数据不稳定,请重新放置食材后再取走")
.setPositiveButton("确认")
.show()
// 数据不稳定,不关闭页面,弹窗提示(通过 isShowing 防止重复弹出)
if (unstableDialog?.isShowing == true) return
if (unstableDialog == null) {
unstableDialog = CommonDialog(this)
.setTitle("提示")
.setContent("数据不稳定,请重新放置食材后再取走")
.setPositiveButton("确认")
}
unstableDialog?.show()
return
}
item.useWeight = stableWeight
@@ -12,6 +12,7 @@ import androidx.core.content.ContextCompat
import com.shuwei.dish.match.base.BaseActivity
import com.shuwei.dish.match.databinding.ActivitySettingBinding
import com.shuwei.dish.match.dialog.CommonDialog
import com.shuwei.dish.match.dialog.EnvSwitchDialog
import com.shuwei.dish.match.scale.ScaleServiceManager
import com.shuwei.dish.match.utils.SpTool
import com.shuwei.dish.match.utils.ext.clickWithDebounce
@@ -50,6 +51,7 @@ class SettingActivity : BaseActivity() {
binding.llDbInspect.visible()
binding.llScaleObserve.visible()
binding.llClearData.visible()
binding.llEnvSwitch.visible()
}
})
@@ -88,6 +90,9 @@ class SettingActivity : BaseActivity() {
binding.llClearData.clickWithDebounce {
showClearDataDialog()
}
binding.llEnvSwitch.clickWithDebounce {
EnvSwitchDialog(this).show()
}
}
/**
@@ -173,6 +173,38 @@
tools:ignore="ContentDescription" />
</LinearLayout>
<LinearLayout
android:id="@+id/llEnvSwitch"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="50dp"
android:background="@drawable/shape_white_dc_15_corners"
android:clipToOutline="true"
android:foreground="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_weight="1"
android:text="切换环境"
android:textColor="@color/black333"
android:textSize="32sp"
android:textStyle="bold" />
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="20dp"
android:adjustViewBounds="true"
android:src="@drawable/ic_arrow_right3"
tools:ignore="ContentDescription" />
</LinearLayout>
<LinearLayout
android:id="@+id/llClearData"
android:layout_width="match_parent"
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 环境切换弹窗内容区:RadioGroup 包含 TEST / UAT / PROD 三个选项 -->
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rgEnv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="8dp">
<RadioButton
android:id="@+id/rbTest"
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingHorizontal="30dp"
android:text="本地环境"
android:textColor="@color/black333"
android:textSize="26sp" />
<RadioButton
android:id="@+id/rbUat"
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingHorizontal="30dp"
android:text="测试环境"
android:textColor="@color/black333"
android:textSize="26sp" />
<RadioButton
android:id="@+id/rbProd"
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingHorizontal="30dp"
android:text="生产环境"
android:textColor="@color/black333"
android:textSize="26sp" />
</RadioGroup>