فهرست منبع

refactor(地图):
- 更新地图锚点编辑弹窗的UI和交互,移除"Remove"按钮
- 调整开关柜图层未知状态下的显示效果
- 新增地图锚点显隐控制
- 优化图标加载逻辑,提升性能和视觉效果
- 新增任务执行步骤状态颜色
- 修复其他相关UI问题

周文健 8 ماه پیش
والد
کامیت
b8ad2ab23b
23فایلهای تغییر یافته به همراه110 افزوده شده و 97 حذف شده
  1. 5 0
      app/src/main/assets/i18n/en-US.json
  2. 5 0
      app/src/main/assets/i18n/zh-CN.json
  3. BIN
      app/src/main/assets/themes/Default/icons/icon_settings.png
  4. 20 0
      app/src/main/java/com/grkj/iscs/ISCSApplication.kt
  5. 3 6
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdatePointToMapDialog.kt
  6. 2 6
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt
  7. 4 4
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateJobFragment.kt
  8. 4 4
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt
  9. 7 1
      app/src/main/res/drawable/bg_job_execute_step.xml
  10. 2 2
      app/src/main/res/layout/dialog_add_point_to_map.xml
  11. 3 21
      app/src/main/res/layout/dialog_update_point_to_map.xml
  12. 1 0
      app/src/main/res/layout/fragment_switch_layout.xml
  13. 3 6
      app/src/main/res/layout/item_my_todo.xml
  14. 1 0
      app/src/main/res/values/dimens.xml
  15. 1 0
      data/src/main/java/com/grkj/data/data/MMKVConstants.kt
  16. 2 0
      data/src/main/java/com/grkj/data/logic/impl/standard/HardwareLogic.kt
  17. 29 19
      ui-base/src/main/java/com/grkj/ui_base/skin/SkinIcons.kt
  18. 8 2
      ui-base/src/main/java/com/grkj/ui_base/widget/CustomSwitchStationLayer.kt
  19. 0 26
      ui-base/src/main/res/drawable/card_white_bg_core.xml
  20. 3 0
      ui-base/src/main/res/values/attrs.xml
  21. 3 0
      ui-base/src/main/res/values/colors_palette.xml
  22. 1 0
      ui-base/src/main/res/values/ids.xml
  23. 3 0
      ui-base/src/main/res/values/theme.xml

+ 5 - 0
app/src/main/assets/i18n/en-US.json

@@ -3987,5 +3987,10 @@
     "key": "set_default",
     "type": "text",
     "value": "Set as default"
+  },
+  "show_in_map": {
+    "key": "show_in_map",
+    "type": "text",
+    "value": "Show in Map"
   }
 }

+ 5 - 0
app/src/main/assets/i18n/zh-CN.json

@@ -3983,5 +3983,10 @@
     "key": "set_default",
     "type": "text",
     "value": "设为默认"
+  },
+  "show_in_map": {
+    "key": "show_in_map",
+    "type": "text",
+    "value": "在地图中显示:"
   }
 }

BIN
app/src/main/assets/themes/Default/icons/icon_settings.png


+ 20 - 0
app/src/main/java/com/grkj/iscs/ISCSApplication.kt

@@ -6,6 +6,10 @@ import android.app.PendingIntent
 import android.content.Context
 import android.content.Intent
 import ch.qos.logback.classic.Level
+import coil.Coil
+import coil.ImageLoader
+import coil.decode.SvgDecoder
+import coil.memory.MemoryCache
 import com.drake.statelayout.StateConfig
 import com.grkj.data.data.EventConstants
 import com.grkj.data.database.DbReadyGate
@@ -106,9 +110,25 @@ class ISCSApplication : Application() {
             DbReadyGate.await()
             ModbusBusinessManager.registerMainListener()
             LogicManager.init(this@ISCSApplication)
+            initImageLoader()
         }
     }
 
+    private fun initImageLoader(){
+        val loader = ImageLoader.Builder(this)
+            .components { add(SvgDecoder.Factory()) }  // 支持 SVG
+            .memoryCache {
+                MemoryCache.Builder(this)
+                    .maxSizePercent(0.25)             // 视项目情况调
+                    .build()
+            }
+            .respectCacheHeaders(false)
+            .crossfade(false)
+            .build()
+
+        Coil.setImageLoader(loader)
+    }
+
     @Subscribe(threadMode = ThreadMode.MAIN)
     open fun onEvent(event: EventBean<*>) {
         when (event.code) {

+ 3 - 6
app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdatePointToMapDialog.kt

@@ -18,8 +18,7 @@ import com.sik.sikcore.extension.setDebouncedClickListener
  */
 class UpdatePointToMapDialog(
     private val isMapPoint: MapInfoRespVO.IsMapPoint,
-    private val onConfirm: (PointToMapVo, CustomDialog) -> Unit,
-    private val onRemove: (Long, CustomDialog) -> Unit
+    private val onConfirm: (PointToMapVo, CustomDialog) -> Unit
 ) : OnBindView<CustomDialog>(R.layout.dialog_update_point_to_map) {
 
     private lateinit var binding: DialogUpdatePointToMapBinding
@@ -31,7 +30,6 @@ class UpdatePointToMapDialog(
         // 关闭
         binding.closeIv.setDebouncedClickListener { dialog.dismiss() }
         binding.cancel.setDebouncedClickListener { dialog.dismiss() }
-        binding.remove.setDebouncedClickListener { onRemove(isMapPoint.entityId ?: 0L, dialog) }
         binding.pointNameTv.text = isMapPoint.entityName
         binding.xEt.setText((isMapPoint.x)?.toInt()?.times(50).toString())
         binding.yEt.setText((isMapPoint.y)?.toInt()?.times(50).toString())
@@ -85,11 +83,10 @@ class UpdatePointToMapDialog(
         @JvmStatic
         fun show(
             isMapPoint: MapInfoRespVO.IsMapPoint,
-            onConfirm: (PointToMapVo, CustomDialog) -> Unit,
-            onRemove: (Long, CustomDialog) -> Unit
+            onConfirm: (PointToMapVo, CustomDialog) -> Unit
         ) {
             CustomDialog.show(
-                UpdatePointToMapDialog(isMapPoint, onConfirm, onRemove),
+                UpdatePointToMapDialog(isMapPoint, onConfirm),
                 CustomDialog.ALIGN.CENTER
             )
         }

+ 2 - 6
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt

@@ -196,17 +196,12 @@ class SwitchLayoutFragment : BaseFragment<FragmentSwitchLayoutBinding>() {
                     }
                 }
             } else {
-                UpdatePointToMapDialog.show(item, { data, dialog ->
+                UpdatePointToMapDialog.show(item) { data, dialog ->
                     viewModel.updateMapPoint(data).observe(this@SwitchLayoutFragment) {
                         dialog.dismiss()
                         getMap(currentWorkstationId)
                         binding.rvList.adapter?.notifyDataSetChanged()
                     }
-                }) { pointId, dialog ->
-                    viewModel.removePointFromMap(pointId).observe(this@SwitchLayoutFragment) {
-                        getMap(currentWorkstationId)
-                        binding.rvList.adapter?.notifyDataSetChanged()
-                    }
                 }
             }
         }
@@ -304,6 +299,7 @@ class SwitchLayoutFragment : BaseFragment<FragmentSwitchLayoutBinding>() {
                     ThreadUtils.runOnMainDelayed(500) {
                         if (positionPointId != null) {
                             stationLayer?.selectPoint(positionPointId)
+                            binding.mapview.refresh()
                         }
                     }
                 }

+ 4 - 4
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateJobFragment.kt

@@ -390,9 +390,12 @@ class CreateJobFragment : BaseFormFragment<FragmentCreateJobBinding>() {
                             viewModel.workstationData,
                             defaultWorkstationId
                         )?.workstationName
-                    selectedModeId = defaultWorkstationId
+                    selectedModeId = defaultWorkflowModeId
                     binding.lockModeTv.text =
                         viewModel.workflowModes.find { it.modeId == defaultWorkflowModeId }?.modeName
+                    if (selectedModeId != null) {
+                        refreshWorkflowMode()
+                    }
                 }
             }
         }
@@ -583,9 +586,6 @@ class CreateJobFragment : BaseFormFragment<FragmentCreateJobBinding>() {
 
     override fun onResume() {
         super.onResume()
-        if (selectedModeId != null) {
-            refreshWorkflowMode()
-        }
         if (GlobalDataTempStore.getInstance()
                 .hasData(DataTransferConstants.KEY_SELECTED_MEMBER_LOCKER_DATA)
         ) {

+ 4 - 4
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt

@@ -263,21 +263,21 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
     private fun BindingAdapter.BindingViewHolder.onStepRVListBinding(holder: BindingAdapter.BindingViewHolder) {
         val itemBinding = holder.getBinding<ItemJobExecuteStepBinding>()
         val item = holder.getModel<IsJobTicketStepDataVo>()
-        itemBinding.stepIconIv.loadSkinIcon(item.stepIcon?:"")
+        itemBinding.stepIconIv.loadSkinIcon(item.stepIcon ?: "")
         itemBinding.stepNameTv.text = item.stepTitleShort
         itemBinding.stepIndexTv.text = item.stepIndex.toString()
         itemBinding.dividerIv.isVisible = item.stepId != viewModel.ticketStep.last().stepId
         val bg = itemBinding.stepLayout.background
         when (item.stepStatus) {
             "1" -> {
-                itemBinding.stepLayout.changeBgTint(CommonUtils.getColor(com.grkj.ui_base.R.attr.colorConfirm))
+                itemBinding.stepLayout.changeBgTint(CommonUtils.getColor(com.grkj.ui_base.R.attr.colorJobExecuteStepDone))
             }
 
             "0" -> {
                 if (item.stepId == viewModel.currentStepData?.stepId) {
-                    itemBinding.stepLayout.changeBgTint(CommonUtils.getColor(com.grkj.ui_base.R.attr.colorHomeBlockOngoing))
+                    itemBinding.stepLayout.changeBgTint(CommonUtils.getColor(com.grkj.ui_base.R.attr.colorJobExecuteStepDoing))
                 } else {
-                    itemBinding.stepLayout.removeBgTint()
+                    itemBinding.stepLayout.changeBgTint(CommonUtils.getColor(com.grkj.ui_base.R.attr.colorJobExecuteStepPending))
                 }
             }
         }

+ 7 - 1
app/src/main/res/drawable/bg_job_execute_step.xml

@@ -1,5 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:color="?attr/rippleColor">
-    <item android:drawable="@drawable/bg_job_execute_step_core"/>
+    <item>
+        <shape>
+            <solid android:color="?attr/colorSurface"/>
+            <stroke android:width="@dimen/iscs_stroke_sm" android:color="?attr/colorStroke"/>
+            <corners android:radius="@dimen/iscs_radius_xl"/>
+        </shape>
+    </item>
 </ripple>

+ 2 - 2
app/src/main/res/layout/dialog_add_point_to_map.xml

@@ -170,9 +170,9 @@
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
-                app:i18nKey='@{"add_to_map_point_serial_number"}'
+                app:i18nKey='@{"show_in_map"}'
                 app:markPosition="start"
-                app:required="true" />
+                app:required="false" />
 
             <com.google.android.material.switchmaterial.SwitchMaterial
                 android:id="@+id/status"

+ 3 - 21
app/src/main/res/layout/dialog_update_point_to_map.xml

@@ -68,6 +68,7 @@
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:layout_marginRight="@dimen/dialog_content_normal_padding_horizontal"
+                android:minWidth="@dimen/add_to_map_input_min_width"
                 android:background="@drawable/bg_common_input"
                 android:enabled="false"
                 android:maxLines="1"
@@ -171,9 +172,9 @@
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
-                app:i18nKey='@{"add_to_map_point_serial_number"}'
+                app:i18nKey='@{"show_in_map"}'
                 app:markPosition="start"
-                app:required="true" />
+                app:required="false" />
 
             <com.google.android.material.switchmaterial.SwitchMaterial
                 android:id="@+id/status"
@@ -198,7 +199,6 @@
                 android:id="@+id/confirm"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
                 android:background="@drawable/common_btn_confirm"
                 android:drawableLeft="@mipmap/icon_confirm"
                 android:drawablePadding="@dimen/iscs_space_2"
@@ -210,29 +210,11 @@
                 app:i18nKey='@{"confirm"}'
                 tools:text="Confirm" />
 
-            <TextView
-                android:id="@+id/remove"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="@dimen/iscs_space_2"
-                android:layout_weight="1"
-                android:background="@drawable/common_btn_cancel"
-                android:drawableLeft="@mipmap/icon_cancel"
-                android:drawablePadding="@dimen/iscs_space_2"
-                android:gravity="center"
-                android:minHeight="@dimen/common_btn_height"
-                android:paddingHorizontal="@dimen/iscs_space_2"
-                android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md"
-                app:i18nKey='@{"remove"}'
-                tools:text="Remove" />
-
             <TextView
                 android:id="@+id/cancel"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
-                android:layout_weight="1"
                 android:background="@drawable/common_btn_cancel"
                 android:drawableLeft="@mipmap/icon_cancel"
                 android:drawablePadding="@dimen/iscs_space_2"

+ 1 - 0
app/src/main/res/layout/fragment_switch_layout.xml

@@ -49,6 +49,7 @@
                     android:id="@+id/map_rv"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
+                    android:paddingHorizontal="@dimen/iscs_space_2"
                     android:minWidth="300dp" />
             </LinearLayout>
 

+ 3 - 6
app/src/main/res/layout/item_my_todo.xml

@@ -2,17 +2,14 @@
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
-    <com.google.android.material.card.MaterialCardView
+    <FrameLayout
         android:id="@+id/cardRoot"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginHorizontal="16dp"
         android:layout_marginVertical="8dp"
         android:background="@drawable/home_card_bg"
-        app:cardCornerRadius="4dp"
-        app:cardElevation="2dp"
-        app:strokeColor="?attr/colorDivider"
-        app:strokeWidth="1dp">
+        android:elevation="2dp">
 
         <androidx.constraintlayout.widget.ConstraintLayout
             android:layout_width="match_parent"
@@ -191,7 +188,7 @@
                 app:layout_constraintTop_toTopOf="@+id/btn_handle"
                 app:rippleColor="?attr/colorPrimary" />
         </androidx.constraintlayout.widget.ConstraintLayout>
-    </com.google.android.material.card.MaterialCardView>
+    </FrameLayout>
 
 
 </layout>

+ 1 - 0
app/src/main/res/values/dimens.xml

@@ -53,6 +53,7 @@
     <dimen name="workflow_step_item_width">120dp</dimen>
     <dimen name="workflow_step_item_height">100dp</dimen>
     <dimen name="workflow_step_item_index_size">30dp</dimen>
+    <dimen name="add_to_map_input_min_width">200dp</dimen>
     <dimen name="step_item_width">120dp</dimen>
     <dimen name="step_item_height">180dp</dimen>
     <dimen name="step_item_icon_size">70dp</dimen>

+ 1 - 0
data/src/main/java/com/grkj/data/data/MMKVConstants.kt

@@ -54,4 +54,5 @@ object MMKVConstants {
      * 默认流程模式
      */
     val KEY_DEFAULT_WORKFLOW_ID get() = "${MainDomainData.userInfo?.userId ?: 0L}_key_default_workflow_id"
+
 }

+ 2 - 0
data/src/main/java/com/grkj/data/logic/impl/standard/HardwareLogic.kt

@@ -214,6 +214,7 @@ class HardwareLogic @Inject constructor(
         val isMapPoint = hardwareDao.getMapPointDataByEntityId(pointToMapVo.pointId)
         isMapPoint.x = (pointToMapVo.x?.toInt()?.div(50)).toString()
         isMapPoint.y = (pointToMapVo.y?.toInt()?.div(50)).toString()
+        isMapPoint.showInMap = pointToMapVo.showInMap
         hardwareDao.updateMapPoint(isMapPoint)
         val pointData = hardwareDao.getPointDataByPointId(pointToMapVo.pointId)
         pointData.pointSerialNumber = pointToMapVo.pointSerialNumber
@@ -233,6 +234,7 @@ class HardwareLogic @Inject constructor(
         isMapPoint.entityId = pointToMapVo.pointId
         isMapPoint.x = (pointToMapVo.x?.toInt()?.div(50)).toString()
         isMapPoint.y = (pointToMapVo.y?.toInt()?.div(50)).toString()
+        isMapPoint.showInMap = pointToMapVo.showInMap
         hardwareDao.insertMapPoint(isMapPoint)
         val pointData = hardwareDao.getPointDataByPointId(pointToMapVo.pointId)
         pointData.pointSerialNumber = pointToMapVo.pointSerialNumber

+ 29 - 19
ui-base/src/main/java/com/grkj/ui_base/skin/SkinIcons.kt

@@ -3,11 +3,14 @@ package com.grkj.ui_base.skin
 import android.app.Application
 import android.net.Uri
 import android.widget.ImageView
+import androidx.annotation.DrawableRes
 import androidx.documentfile.provider.DocumentFile
 import coil.ImageLoader
 import coil.decode.SvgDecoder
+import coil.imageLoader
 import coil.request.CachePolicy
 import coil.request.ImageRequest
+import com.grkj.ui_base.R
 import com.sik.sikcore.SIKCore
 import java.io.File
 
@@ -90,33 +93,40 @@ object SkinIcons {
         defaultAssetsBase: String,
         logicalPath: String,
         app: Application = SIKCore.getApplication(),
-        placeholderRes: Int? = null
+        @DrawableRes placeholderRes: Int? = null
     ) {
-        // 1) 决定使用哪个基准
+        // 1) 主题/路径
         val effectiveTheme = theme ?: ThemeSpec(
             name = "default",
-            base = IconBase.Assets(defaultAssetsBase) // e.g. "themes/Default/icons"
+            base = IconBase.Assets(defaultAssetsBase)
         )
-
-        // 2) 解析 Uri(assets 会直接得到 file:///android_asset/...)
         val uri = resolveIconUri(app, effectiveTheme, logicalPath)
 
-        // 3) Coil 加载(支持 SVG)
-        val req = ImageRequest.Builder(imageView.context)
-            .data(uri ?: placeholderRes)
-            .apply {
-                if (placeholderRes != null) placeholder(placeholderRes)
-                error(placeholderRes ?: 0) // 使用错误占位图
-                // 通过配置内存缓存,避免频繁加载相同的图像
-                memoryCachePolicy(CachePolicy.ENABLED)
-            }
-            .target(imageView)
-            .allowHardware(false) // 禁止硬件加速,防止闪烁
-            .build()
+        // 2) 去重(同一资源就别重复加载)
+        val key = "${effectiveTheme.name}::$logicalPath"
+        if (imageView.getTag(R.id.tag_icon_key) == key) return
+        imageView.setTag(R.id.tag_icon_key, key)
 
-        svgLoader(imageView).enqueue(req)
-    }
+        // 3) 仅 SVG 关闭硬件位图,其他走硬件位图减轻 Java 堆压力(更抗 OOM)
+        val isSvg = uri?.toString()?.endsWith(".svg", ignoreCase = true) == true
 
+        // 4) 构建请求:占位=当前图(无视觉闪烁);使用 ViewTarget 以便自动取消旧请求
+        val builder = ImageRequest.Builder(imageView.context)
+            .data(uri ?: placeholderRes)                   // 没资源就用占位
+            .memoryCacheKey(key)                           // 跨列表项复用结果
+            .crossfade(false)                              // 彻底关过渡
+            .allowHardware(!isSvg)                         // 只有 SVG 才禁硬件
+            .diskCachePolicy(CachePolicy.DISABLED)         // assets 本地文件,不需要磁盘缓存
+            .placeholder(
+                placeholderRes?.let { imageView.context.getDrawable(it) }
+                    ?: imageView.drawable                  // 无占位 -> 保持现图,不清空 => 不闪
+            )
+            .target(imageView)                             // 关键:回到 ViewTarget,自动取消上一个请求
+
+        if (placeholderRes != null) builder.error(placeholderRes)
+
+        imageView.context.imageLoader.enqueue(builder.build())
+    }
 }
 
 /**

+ 8 - 2
ui-base/src/main/java/com/grkj/ui_base/widget/CustomSwitchStationLayer.kt

@@ -500,8 +500,14 @@ class CustomSwitchStationLayer @JvmOverloads constructor(
                         }
 
                         else -> { // STATUS_UNKNOWN
-                            paint.color = Color.DKGRAY; paint.alpha = 200
-                            canvas.drawCircle(c.x, c.y, switchSize, paint)
+                            val t = pulsePhase
+                            val color = if (t < 0.5f) colRed else colOrange
+                            val a = (160 + 95 * abs(sin(2f * Math.PI.toFloat() * t))).toInt()
+                            paint.color = color; paint.alpha = a
+                            val r = switchSize * (1.0f + 0.10f * sin(2f * Math.PI.toFloat() * t))
+                            canvas.drawCircle(c.x, c.y, r, paint)
+                            paint.alpha = (a * 0.35f).toInt()
+                            canvas.drawCircle(c.x, c.y, r * 1.25f, paint)
                             paint.alpha = 255
                         }
                     }

+ 0 - 26
ui-base/src/main/res/drawable/card_white_bg_core.xml

@@ -1,31 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- 禁用:描边更淡 -->
-    <item android:state_enabled="false">
-        <shape>
-            <solid android:color="?attr/colorContainerBg"/>
-            <stroke android:width="@dimen/iscs_stroke_sm" android:color="?attr/colorWhite20"/>
-            <corners android:radius="@dimen/iscs_radius_sm"/>
-        </shape>
-    </item>
-
-    <!-- 选中/激活:轻底高亮(列表选中、当前块) -->
-    <item android:state_selected="true">
-        <shape>
-            <solid android:color="?attr/colorSelectedGray"/>  <!-- 20% 白 -->
-            <stroke android:width="@dimen/iscs_stroke_sm" android:color="?attr/colorStroke"/>
-            <corners android:radius="@dimen/iscs_radius_sm"/>
-        </shape>
-    </item>
-    <item android:state_activated="true">
-        <shape>
-            <solid android:color="?attr/colorSelectedGray"/>
-            <stroke android:width="@dimen/iscs_stroke_sm" android:color="?attr/colorStroke"/>
-            <corners android:radius="@dimen/iscs_radius_sm"/>
-        </shape>
-    </item>
-
-    <!-- 默认:容器底 + 浅描边 -->
     <item>
         <shape>
             <solid android:color="?attr/colorContainerBg"/>

+ 3 - 0
ui-base/src/main/res/values/attrs.xml

@@ -81,6 +81,9 @@
     <attr name="colorSwitchOn" format="color"/>
     <attr name="colorSwitchOff" format="color"/>
     <attr name="colorMapBase" format="color"/>
+    <attr name="colorJobExecuteStepDone" format="color"/>
+    <attr name="colorJobExecuteStepDoing" format="color"/>
+    <attr name="colorJobExecuteStepPending" format="color"/>
 
     <!-- 辅助 -->
     <attr name="colorHint" format="color" />

+ 3 - 0
ui-base/src/main/res/values/colors_palette.xml

@@ -39,6 +39,9 @@
     <color name="palette_red_bright">#FF5A5F</color>    <!-- 错误/警告突出红:保留 -->
     <color name="palette_yellow_bright">#F5D24A</color> <!-- 进行中/提醒,略降橙感防脏 -->
     <color name="palette_orange_bright">#F97316</color> <!-- 进行中/提醒,略降橙感防脏 -->
+    <color name="chip_done_tint">#0F8C5A</color>          <!-- Done 绿青 -->
+    <color name="chip_doing_tint">#0E66CC</color>         <!-- Doing 蓝(跟 #5AA9FF 同色系更深) -->
+    <color name="chip_pending_tint">#B07B10</color>       <!-- Pending 琥珀棕 -->
 
     <!-- —— 黑透明:保留兼容 —— -->
     <color name="palette_black">#000000</color>

+ 1 - 0
ui-base/src/main/res/values/ids.xml

@@ -5,4 +5,5 @@
     <item name="expand_tag_index" type="id" />
     <item name="i18n_locale_observer_job" type="id" />
     <item name="tag_svg_image_loader" type="id"/>
+    <item name="tag_icon_key" type="id"/>
 </resources>

+ 3 - 0
ui-base/src/main/res/values/theme.xml

@@ -90,6 +90,9 @@
         <item name="colorSwitchOn">@color/palette_green_bright</item>
         <item name="colorSwitchOff">@color/palette_red_bright</item>
         <item name="colorMapBase">@color/palette_dark_gray</item>
+        <item name="colorJobExecuteStepDone">@color/chip_done_tint</item>
+        <item name="colorJobExecuteStepDoing">@color/chip_doing_tint</item>
+        <item name="colorJobExecuteStepPending">@color/chip_pending_tint</item>
 
         <item name="colorHint">@color/palette_stroke_white8</item>
         <item name="colorDisable">@color/palette_text_disabled_dark</item>