Kaynağa Gözat

refactor(更新)
- 数据库修改
- sop和作业票的分组新增
- 区域管理的样式修改

周文健 4 ay önce
ebeveyn
işleme
e9c89a3ded

BIN
app/src/main/assets/data.db


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

@@ -1,6 +1,9 @@
 package com.grkj.iscs.features.main.fragment.data_manage
 
 import android.view.Gravity
+import android.view.ViewGroup
+import androidx.core.view.isInvisible
+import androidx.core.view.isVisible
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.ViewModelProvider
 import com.drake.brv.utils.linear
@@ -37,7 +40,7 @@ class WorkstationManageFragment : BaseFragment<FragmentWorkstationManageBinding>
             navController.popBackStack()
         }
         binding.addWorkstation.setDebouncedClickListener {
-            AddWorkstationDialog.show{
+            AddWorkstationDialog.show {
                 viewModel.addWorkstation(it).observe(this) {
                     if (it) {
                         TipDialog.show(
@@ -104,7 +107,17 @@ class WorkstationManageFragment : BaseFragment<FragmentWorkstationManageBinding>
                 val node = getModel<WorkstationManageVo>()
                 itemBinding.node = node
                 // ① 动态缩进
-                itemBinding.rootLayout.setPadding(indentPx * node.level, 0, 0, 0)
+                itemBinding.itemLine.layoutParams.apply {
+                    width = indentPx * (node.level + 1)
+                }
+                itemBinding.childTopLine.isInvisible =
+                    node.orderNum == 0 && node.level == 0
+                itemBinding.childBottomLine.isInvisible =
+                    node.orderNum == viewModel.workstationManageData.filter { it.parentId == node.parentId }
+                        .sortedBy { it.orderNum }.last().orderNum
+                (itemBinding.childLineLayout.layoutParams as ViewGroup.MarginLayoutParams).apply {
+                    leftMargin = indentPx * node.level
+                }
                 itemBinding.tvName.isSelected = node.isSelected
                 itemBinding.root.setOnClickListener {
                     viewModel.workstationManageData.filter { it.isSelected }

+ 1 - 1
app/src/main/res/layout/fragment_workstation_manage.xml

@@ -121,7 +121,7 @@
                 android:layout_height="match_parent"
                 android:background="@drawable/common_card_bg"
                 android:paddingHorizontal="@dimen/common_spacing"
-                android:paddingBottom="@dimen/common_spacing" />
+                android:paddingVertical="@dimen/common_spacing" />
         </com.scwang.smart.refresh.layout.SmartRefreshLayout>
     </LinearLayout>
 </layout>

+ 48 - 11
app/src/main/res/layout/item_workstation.xml

@@ -9,22 +9,59 @@
     </data>
 
     <LinearLayout
-        android:id="@+id/rootLayout"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/common_spacing"
-        android:gravity="center_vertical"
         android:orientation="horizontal">
 
-        <TextView
-            android:id="@+id/tvName"
+        <LinearLayout
+            android:id="@+id/child_line_layout"
             android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:visibility="visible">
+
+            <View
+                android:id="@+id/child_top_line"
+                android:layout_width="@dimen/line_height"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@color/black" />
+
+            <View
+                android:id="@+id/child_bottom_line"
+                android:layout_width="@dimen/line_height"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@color/black" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/rootLayout"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:background="@drawable/bg_workstation_item"
-            android:paddingVertical="@dimen/common_spacing"
-            android:paddingHorizontal="30dp"
-            android:text="@{node.workstationName}"
-            android:textColor="@color/text_color_workstation_item"
-            android:textSize="@dimen/common_btn_text_size" />
+            android:gravity="center_vertical"
+            android:layout_marginVertical="@dimen/common_spacing"
+            android:orientation="horizontal">
+
+            <View
+                android:id="@+id/item_line"
+                android:layout_width="10dp"
+                android:layout_height="@dimen/line_height"
+                android:layout_gravity="center_vertical"
+                android:background="@color/black" />
+
+            <TextView
+                android:id="@+id/tvName"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="@dimen/common_spacing_2x"
+                android:background="@drawable/bg_workstation_item"
+                android:paddingHorizontal="30dp"
+                android:paddingVertical="@dimen/common_spacing"
+                android:text="@{node.workstationName}"
+                android:textColor="@color/text_color_workstation_item"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
     </LinearLayout>
+
 </layout>

+ 69 - 75
data/src/main/java/com/grkj/data/database/ISCSDatabase.kt

@@ -1,57 +1,21 @@
 package com.grkj.data.database
 
+import android.os.Environment
+import android.util.Log
 import androidx.room.Database
 import androidx.room.Room
 import androidx.room.RoomDatabase
 import androidx.room.TypeConverters
 import com.grkj.data.converters.Converters
-import com.grkj.data.dao.ExceptionDao
-import com.grkj.data.dao.HardwareDao
-import com.grkj.data.dao.IsSopDao
-import com.grkj.data.dao.IsolationPointDao
-import com.grkj.data.dao.JobTicketDao
-import com.grkj.data.dao.RfidTokenDao
-import com.grkj.data.dao.RoleDao
-import com.grkj.data.dao.SysMenuDao
-import com.grkj.data.dao.UserDao
-import com.grkj.data.dao.WorkflowStepDao
-import com.grkj.data.dao.WorkstationDao
-import com.grkj.data.model.dos.IsExceptionSourceStandard
-import com.grkj.data.model.dos.IsExceptionStandard
-import com.grkj.data.model.dos.IsIsolationPoint
-import com.grkj.data.model.dos.IsJobCard
-import com.grkj.data.model.dos.IsJobTicket
-import com.grkj.data.model.dos.IsJobTicketKey
-import com.grkj.data.model.dos.IsJobTicketLock
-import com.grkj.data.model.dos.IsJobTicketPoints
-import com.grkj.data.model.dos.IsJobTicketStep
-import com.grkj.data.model.dos.IsJobTicketUser
-import com.grkj.data.model.dos.IsKey
-import com.grkj.data.model.dos.IsLock
-import com.grkj.data.model.dos.IsLockCabinet
-import com.grkj.data.model.dos.IsLockCabinetSlots
-import com.grkj.data.model.dos.IsLockset
-import com.grkj.data.model.dos.IsLocksetType
-import com.grkj.data.model.dos.IsRfidToken
-import com.grkj.data.model.dos.IsSop
-import com.grkj.data.model.dos.IsSopPoints
-import com.grkj.data.model.dos.IsSopUser
-import com.grkj.data.model.dos.IsUserWorkstation
-import com.grkj.data.model.dos.IsWorkstation
-import com.grkj.data.model.dos.SysMenu
-import com.grkj.data.model.dos.SysRole
-import com.grkj.data.model.dos.SysRoleMenu
-import com.grkj.data.model.dos.SysUserCharacteristicDo
-import com.grkj.data.model.dos.SysUserDo
-import com.grkj.data.model.dos.SysUserRole
-import com.grkj.data.model.dos.WorkflowMode
-import com.grkj.data.model.dos.WorkflowStep
-import com.grkj.data.model.dos.WorkflowStepTemplate
+import com.grkj.data.dao.*
+import com.grkj.data.model.dos.*
 import com.grkj.shared.config.Constants
 import com.sik.sikcore.SIKCore
 import kotlinx.coroutines.Dispatchers
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
+import java.io.File
+import java.io.FileOutputStream
 
 /**
  * 本地数据库
@@ -62,53 +26,83 @@ import org.slf4j.LoggerFactory
         SysRole::class, SysUserRole::class, IsUserWorkstation::class, IsWorkstation::class, IsIsolationPoint::class, IsRfidToken::class,
         IsSop::class, IsSopUser::class, IsSopPoints::class, IsJobTicket::class, IsJobTicketKey::class, IsJobTicketLock::class,
         IsJobTicketPoints::class, IsJobTicketStep::class, IsJobTicketUser::class,
-        IsKey::class, IsLock::class, IsLockCabinet::class, IsLockCabinetSlots::class, IsLocksetType::class, IsLockset::class, SysMenu::class, SysRoleMenu::class,
-        WorkflowStep::class, WorkflowMode::class, WorkflowStepTemplate::class, IsExceptionStandard::class, IsExceptionSourceStandard::class
+        IsKey::class, IsLock::class, IsLockCabinet::class, IsLockCabinetSlots::class, IsLocksetType::class, IsLockset::class,
+        SysMenu::class, SysRoleMenu::class,
+        WorkflowStep::class, WorkflowMode::class, WorkflowStepTemplate::class,
+        IsExceptionStandard::class, IsExceptionSourceStandard::class, IsSopGroup::class, IsJobTicketGroup::class
     ],
     version = ISCSMigrations.VERSION,
     exportSchema = true
 )
-@TypeConverters(Converters::class)    // 注册下面要写的 Converters
+@TypeConverters(Converters::class)
 abstract class ISCSDatabase : RoomDatabase() {
-    companion object {
-        private val logger: Logger = LoggerFactory.getLogger(ISCSDatabase::class.java)
-
-        /**
-         * 单例
-         */
-        @JvmStatic
-        val instance: ISCSDatabase by lazy {
-            Room.databaseBuilder(
-                SIKCore.getApplication(), ISCSDatabase::class.java, "iscs_database"
-            ).apply {
-                if (Constants.DEBUG) {
-//                    fallbackToDestructiveMigration(true)
-                }
-            }.createFromAsset("data.db").setQueryCallback(Dispatchers.IO) { sql, args ->
-                logger.debug("SQL:$sql,Args:$args")
-            }.build()
-        }
-    }
 
     abstract fun userDao(): UserDao
-
     abstract fun hardwareDao(): HardwareDao
-
     abstract fun roleDao(): RoleDao
-
     abstract fun workstationDao(): WorkstationDao
-
     abstract fun isolationPointDao(): IsolationPointDao
-
     abstract fun rfidTokenDao(): RfidTokenDao
-
     abstract fun isSopDao(): IsSopDao
-
     abstract fun jobTicketDao(): JobTicketDao
-
     abstract fun sysMenuDao(): SysMenuDao
-
     abstract fun workflowStepDao(): WorkflowStepDao
-
     abstract fun exceptionDao(): ExceptionDao
-}
+
+    companion object {
+        private const val DB_NAME = "iscs_database.db"
+        private val logger: Logger = LoggerFactory.getLogger(ISCSDatabase::class.java)
+
+        // 外部存储目录路径
+        private val EXTERNAL_DB_FILE: File by lazy {
+            File(Environment.getExternalStorageDirectory(), "ISCS/database/$DB_NAME")
+        }
+
+        @JvmStatic
+        val instance: ISCSDatabase by lazy {
+            val context = SIKCore.getApplication()
+
+            // 检查并创建外部目录
+            val parentDir = EXTERNAL_DB_FILE.parentFile
+            if (parentDir != null) {
+                if (!parentDir.exists()) {
+                    val ok = parentDir.mkdirs()
+                    if (!ok) {
+                        Log.e("ISCSDatabase", "无法创建目录: ${parentDir.absolutePath}")
+                    } else {
+                        logger.info("创建目录: ${parentDir.absolutePath}")
+                    }
+                }
+            }
+
+            // 若文件不存在,从 assets 拷贝
+            if (!EXTERNAL_DB_FILE.exists()) {
+                try {
+                    context.assets.open("data.db").use { input ->
+                        FileOutputStream(EXTERNAL_DB_FILE).use { output ->
+                            input.copyTo(output)
+                        }
+                    }
+                    logger.info("已从 assets 复制数据库到: ${EXTERNAL_DB_FILE.absolutePath}")
+                } catch (e: Exception) {
+                    logger.error("复制数据库失败", e)
+                }
+            }
+
+            // 构建 RoomDatabase,使用外部存储路径
+            val builder = Room.databaseBuilder(
+                context,
+                ISCSDatabase::class.java,
+                EXTERNAL_DB_FILE.absolutePath
+            )
+            if (Constants.DEBUG) {
+                builder.setQueryCallback( Dispatchers.IO,{ sql, args ->
+                    logger.debug("SQL: $sql, args: $args")
+                })
+                // 不要使用 fallbackToDestructiveMigration()
+            }
+
+            builder.build()
+        }
+    }
+}

+ 2 - 2
data/src/main/java/com/grkj/data/model/dos/IsJobTicketGroup.kt

@@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
 /**
  * 作业分组分组
  */
-@Entity(tableName = "is_sop_group")
+@Entity(tableName = "is_job_ticket_group")
 class IsJobTicketGroup : BaseStandardBean() {
     @PrimaryKey(autoGenerate = true)
     var id: Long = 0
@@ -18,7 +18,7 @@ class IsJobTicketGroup : BaseStandardBean() {
     @ColumnInfo(name = "group_name")
     var groupName: String = ""
 
-    var deleted: String = ""
+    var deleted: String? = ""
 
     @ColumnInfo(name = "tenant_id")
     var tenantId: Long? = null

+ 2 - 2
data/src/main/java/com/grkj/data/model/dos/IsSopGroup.kt

@@ -18,9 +18,9 @@ class IsSopGroup : BaseStandardBean() {
     @ColumnInfo(name = "group_name")
     var groupName: String = ""
 
-    var deleted: String = ""
+    var deleted: String? = ""
 
     @ColumnInfo(name = "tenant_id")
-    var tenantId: Long?=null
+    var tenantId: Long? = null
 
 }