package com.iscs.bozzys.api import android.util.Log import com.iscs.bozzys.R import com.iscs.bozzys.ui.pages.edit.step.compose.NodeUI import com.iscs.bozzys.utils.StringToListSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json /** * 流程节点 */ @Serializable data class Node( val id: Int = 0, val workId: Int = 0, val uuid: String = "", val parentUuid: String = "", val childrenUuid: String = "", val nodeName: String = "", val nodeIcon: String = "", val type: String = "", val position: String = "", val data: String = "", val description: String? = null, val workerUserId: Int = 0, val workerGroupId: Int? = null, val formId: Int = 0, val formData: String? = null, val createTime: Long = 0L, val approvalStatus: String = "", val approvalOpinion: String = "", val isolationType: String? = null, // 隔离类型 val isolationPoints: String? = null, // 解除隔离的点位 val isolationNodeUuid: String? = null, // 解除隔离关联的节点uuid val nodeUserList: List? = null, // 隔离和解除隔离关联的上锁人和共锁人 val smsTemplateCode: String? = null, // 短信通知 val messageTemplateCode: String? = null, // 站内信息 val emailTemplateCode: String? = null, // 邮件通知 val appTemplateCode: String? = null, // app消息推送 val deviceNumber: String? = null, // 设备序列号 val attachments: String? = null, // 携带的数据 val points: List? = null, // 隔离点位信息 val keys: List? = null, // 隔离点位参与的挂锁 val locks: List? = null, // 隔离点位参与的钥匙 ) { /** * 校验是否可以通过手机进行操作 */ fun checkCanOptionByPhone(): Boolean { return !(listOf("lock", "unlock", "coLock","unlockCoLock").contains(type) && !listOf("0", "2").contains(isolationType)) } /** * 校验请求参数 * * @param forms 表单数据 */ fun checkCanSubmit(forms: List): String { forms.forEach { Log.d("NodeOption", "checkCanSubmit -> $it") if (it.required) { if ((it.value.getOrNull(0) ?: "").isEmpty()) { return (it.placeholder.getOrNull(0) ?: "").ifEmpty { "请填写${it.label}" } } } } return "" } /** * 构建请求参数 * * @param forms 表单数据 */ fun buildSubmitParams(forms: List, workFormList: List): MutableMap { val nodeName = forms.find { it.name == "nodeName" }?.value?.getOrNull(0) ?: "" val params = mutableMapOf("nodeId" to id, "nodeName" to nodeName) if (type != "createJob") { val workerUserId = forms.find { it.name == "workerUserId" }?.value?.getOrNull(0) ?: "0" val formId = forms.find { it.name == "formId" }?.value?.getOrNull(0) ?: "0" val findWork = workFormList.find { it.id == formId.toInt() } val formData = if (findWork != null) Json.encodeToString(findWork) else null val noticeType = forms.find { it.name == "noticeType" }?.value ?: emptyList() params["workerUserId"] = workerUserId.toInt() params["formId"] = formId.toInt() params["formData"] = formData // 处理隔离点信息表单 if (listOf("isolation", "releaseIsolation").contains(type)) { val isolationType = forms.find { it.name == "isolationType" }?.value?.getOrNull(0) ?: "-1" val isolationPoints = forms.find { it.name == "isolationPoints" }?.value ?: emptyList() if (isolationType == "1") { // 移除负责人 params.remove("workerUserId") // 上锁人和共锁人 val locker = forms.find { it.name == "locker" }?.value?.getOrNull(0) ?: "-1" val group = forms.find { it.name == "group" }?.value ?: emptyList() val userList = mutableListOf>() if (locker.toInt() > 0) userList += mutableMapOf("userId" to locker.toInt(), "type" to "jtlocker") group.forEach { userList += mutableMapOf("userId" to it.toInt(), "type" to "jtcolocker") } params["nodeUserDOList"] = userList } params["isolationType"] = isolationType params["isolationPoints"] = isolationPoints.joinToString( prefix = "[", postfix = "]", separator = "," ) if (type == "releaseIsolation") { val isolationNode = forms.find { it.name == "isolationNode" }?.value?.getOrNull(0) // 解除隔离,这里需要填写关联的节点uuid params["isolationNodeUuid"] = isolationNode } } // 通知方式 // 短信 params["smsTemplateCode"] = if (noticeType.contains("sms")) "true" else "false" // 站内信 params["messageTemplateCode"] = if (noticeType.contains("message")) "true" else "false" // 邮件 params["emailTemplateCode"] = if (noticeType.contains("email")) "true" else "false" // app通知 params["appTemplateCode"] = if (noticeType.contains("app")) "true" else "false" } return params } /** * 更新节点信息 * * @param forms */ fun updateNodeInfo(forms: List, nodes: List): Node { val nodeName = forms.find { it.name == "nodeName" }?.value?.getOrNull(0) ?: "" if (type != "createJob") { // 解析关联表单 val formId = forms.find { it.name == "formId" }?.value?.getOrNull(0) ?: "-1" // 解析表单数据 val formData = forms.find { it.name == "formData" }?.value?.getOrNull(0) // 解析负责人 var workerUserId = forms.find { it.name == "workerUserId" }?.value?.getOrNull(0) ?: "0" // 解析隔离方式 var isolationType = forms.find { it.name == "isolationType" }?.value?.getOrNull(0) // 解析点位 var isolationPoints = forms.find { it.name == "isolationPoints" }?.value ?: emptyList() // 解析上锁人 val locker = forms.find { it.name == "locker" }?.value?.getOrNull(0) ?: "-1" // 解析共锁人 val group = forms.find { it.name == "group" }?.value ?: emptyList() // 构建上锁人和共锁人列表 val userList = mutableListOf() if (locker.toInt() > 0) userList += User(userId = locker.toInt(), type = "jtlocker") if (group.isNotEmpty()) group.forEach { userList += User(userId = it.toInt(), type = "jtcolocker") } // 解析隔离节点 val isolationNode = forms.find { it.name == "isolationNode" }?.value?.getOrNull(0) // 如果是解除隔离操作,隔离方式、隔离点位、负责人(或者上锁人、解锁人)需要从选中的点位中获取 if (type == "releaseIsolation") { nodes.find { it.node?.uuid == isolationNode }?.node?.let { // 从节点中将数据copy到当前节点 workerUserId = "${it.workerUserId}" isolationType = it.isolationType isolationPoints = if (it.isolationPoints.isNullOrEmpty()) { emptyList() } else { it.isolationPoints.replace("[", "").replace("]", "").split(",") } userList.addAll(it.nodeUserList ?: emptyList()) } } // 通知方式 val noticeType = forms.find { it.name == "noticeType" }?.value ?: emptyList() return Node( id = id, workId = workId, uuid = uuid, parentUuid = parentUuid, childrenUuid = childrenUuid, nodeName = nodeName, type = type, position = position, workerUserId = workerUserId.toInt(), formId = formId.toInt(), formData = formData, isolationType = isolationType, isolationPoints = isolationPoints.joinToString( prefix = "[", postfix = "]", separator = "," ), isolationNodeUuid = isolationNode, nodeUserList = if (userList.isEmpty()) null else userList, smsTemplateCode = if (noticeType.contains("sms")) "true" else "false", messageTemplateCode = if (noticeType.contains("message")) "true" else "false", emailTemplateCode = if (noticeType.contains("email")) "true" else "false", appTemplateCode = if (noticeType.contains("app")) "true" else "false" ) } return Node( id = id, workId = workId, uuid = uuid, parentUuid = parentUuid, childrenUuid = childrenUuid, nodeName = nodeName, type = type, position = position ) } /** * 构建表单列表 * * @param workerUserList 负责人列表 * @param lockerUserList 上锁人列表 * @param groupUserList 共锁人列表 * @param workFormList 工作表单列表 * @param isolationMethodList 获取隔离方式列表 * @param isolationList 点位列表 * @param isLocker 是否上锁人 */ fun buildFormList( workerUserList: List, lockerUserList: List, groupUserList: List, workFormList: List, isolationMethodList: List, isolationList: List, nodes: List = listOf(), isLocker: Boolean = false, ): List { Log.d("NodeOption", "buildFormList -> $this") val list = ArrayList() // 添加节点名称 list += FormField( id.toString(), "input", "节点名称", name = "nodeName", true, value = listOf(nodeName), placeholder = listOf("请输入节点名称") ) if (type == "createJob") return list // 添加节点负责人 list += FormField( id.toString(), "select", "负责人", "workerUserId", true, placeholder = listOf("请选择负责人"), options = workerUserList.map { FormOption(it.nickname, it.id.toString()) }, value = if (workerUserId > 0) listOf(workerUserId.toString()) else listOf() ) // 添加业务表单 list += FormField( id.toString(), "select", "业务表单", name = "formId", true, placeholder = listOf("请选择业务表单"), options = workFormList.map { FormOption(it.name ?: "", it.id.toString()) }, value = if (formId > 0) listOf(formId.toString()) else listOf() ) // 隔离配置 if (listOf("isolation", "releaseIsolation").contains(type)) { // 先移除负责人,需要在后面进行添加 list.removeIf { it.name == "workerUserId" } // 而且业务表单非必填 val formField = list.find { it.name == "formId" }?.copy(required = false) list.removeIf { it.name == "formId" } formField?.let { list.add(it) } val isolations = nodes.map { it.node }.filter { it != null && it.type == "isolation" } var enabled = true var isLockerTemp = isLocker // 如果是解除隔离操作,这里只能选择当前流程中已经存在的隔离点位 if (type == "releaseIsolation") { enabled = false // 增加隔离点选择列表 list += FormField( id.toString(), type = "select", label = "选择隔离节点", name = "isolationNode", required = true, placeholder = listOf("请选择隔离节点"), options = isolations.map { FormOption(it?.nodeName ?: "", value = it?.uuid ?: "") }, value = if (isolationNodeUuid.isNullOrEmpty()) listOf() else listOf(isolationNodeUuid) ) // 如果是解除隔离的操作,这里需要先校验选择的节点是否是拆除 isLockerTemp = isolationType == "1" } // 抽取隔离方式value值 val valueOfIsolationType = if (isolationType.isNullOrEmpty()) { listOf() // val type = dataMap["isolationMethod"] // if (type == null) listOf() else listOf("$type") } else listOf(isolationType) // 隔离方式 list += FormField( id.toString(), "select", "隔离方式", "isolationType", true, placeholder = listOf("请选择隔离方式"), options = isolationMethodList.map { FormOption(it.label, it.value) }, value = valueOfIsolationType, enabled = enabled ) // 抽取隔离点位value值 val points = if (isolationPoints.isNullOrEmpty()) "" else isolationPoints.replace("[", "").replace("]", "") val valueOfIsolationPoints = if (points.isNotEmpty()) { points.split(",") } else { listOf() // when (val value = dataMap["isolationPoints"]) { // // 如果是数组 // is List<*> -> value.map { "$it".toFloat().toInt().toString() } // // 如果是String // is String -> { // value.replace("[", "").replace("]", "").split(",") // } // // 其他不处理 // else -> listOf() // } } // 隔离点选择,可多选 list += FormField( id.toString(), "select", "隔离点选择(可多选)", "isolationPoints", true, listOf("请选择隔离点"), multiSelect = true, options = isolationList.map { FormOption(it.pointName ?: "", it.id.toString()) }, value = valueOfIsolationPoints, enabled = enabled ) if (isLockerTemp) { var locker = nodeUserList?.find { it.type == "jtlocker" } var group = nodeUserList?.filter { it.type == "jtcolocker" } ?: emptyList() // 如果是解除隔离,且当前解锁和工作人列表为空,需要默认配置 if (type == "releaseIsolation" && nodeUserList.isNullOrEmpty()) { val bindNode = nodes.find { it.node?.uuid == isolationNodeUuid && !isolationNodeUuid.isNullOrEmpty() } val nodeUserList = bindNode?.node?.nodeUserList locker = nodeUserList?.find { it.type == "jtlocker" } group = nodeUserList?.filter { it.type == "jtcolocker" } ?: emptyList() } // 上锁人 list += FormField( id.toString(), "select", "上锁人", "locker", true, placeholder = listOf("请选择上锁人"), options = lockerUserList.map { FormOption(it.nickname, it.id.toString()) }, value = if (locker != null) listOf(locker.userId.toString()) else listOf(), enabled = enabled ) // 共锁人 list += FormField( id.toString(), "select", "共锁人(可多选)", "group", false, placeholder = listOf("请选择共锁人"), options = groupUserList.map { FormOption(it.nickname, it.id.toString()) }, value = if (group.isNotEmpty()) group.map { it.userId.toString() } else listOf(), multiSelect = true, enabled = enabled ) } else { // 负责人 list += FormField( id.toString(), "select", "负责人", "workerUserId", true, placeholder = listOf("请选择负责人"), options = workerUserList.map { FormOption(it.nickname, it.id.toString()) }, value = if (workerUserId > 0) listOf(workerUserId.toString()) else listOf(), enabled = enabled ) } } val notices = arrayListOf() if (smsTemplateCode == "true") notices += "sms" if (messageTemplateCode == "true") notices += "message" if (emailTemplateCode == "true") notices += "email" if (appTemplateCode == "true") notices += "app" // 通知方式 list += FormField( id.toString(), "checkbox", "通知方式", "noticeType", false, listOf(), notices, options = listOf( FormOption("短信", "sms"), FormOption("站内信", "message"), FormOption("邮件", "email"), FormOption("App通知", "app"), ) ) // // 通知人 // list += FormField( // id.toString(), "select", "通知人", nodeName, false, listOf(), options = listOf( // FormOption("任务负责人", "p1"), // FormOption("任务参与人", "p2"), // FormOption("任务负责和参与人", "all"), // FormOption("指定人", "custom"), // ) // ) // // 通知时间 // list += FormField( // id.toString(), "select", "通知时间", nodeName, false, listOf(), options = listOf( // FormOption("任务开始前30分钟", "0.5"), // FormOption("任务开始前1小时", "1"), // FormOption("任务开始前2小时", "2"), // FormOption("任务开始前5小时", "5"), // ) // ) return list } /** * 获取node图标,暂时本地通过type获取 */ fun getIcon(): Int { return when (type) { // 开始/创建 "createJob" -> R.drawable.node_icon_create_job // 审核 "review" -> R.drawable.node_icon_review // 确认 "confirm" -> R.drawable.node_icon_confirm // 录入信息 "inputInfo" -> R.drawable.node_icon_input_info // 隔离 "isolation" -> R.drawable.node_icon_isolation // 解除隔离 "releaseIsolation" -> R.drawable.node_icon_release_isolation // 还锁 "returnLock" -> R.drawable.node_icon_return_lock // 结束 "complete" -> R.drawable.node_icon_complete else -> R.drawable.tips } } /** * 将作业票转换为JSON */ fun toKeyTicket(lockList: List): String { val json = Json { // 格式化默认值 encodeDefaults = true // 去除字段为null的字段 explicitNulls = false } val target = if (type == "releaseIsolation") 1 else 0 // 锁具id构成 var lockId = 0 val keyTicket = KeyTicket( data = listOf( TicketTask( taskId = id.toString(), codeId = id, dataList = points?.map { point -> TicketPoint( dataId = point.id, equipName = point.pointName ?: point.pointNfc, equipRfidNo = point.pointNfc, target = target, infoRfidNo = point.lockNfc ) } ?: emptyList()) ), lockList = lockList.map { lock -> lockId++ TicketLock(lockId = lockId, rfid = lock.lockNfc) }) return json.encodeToString(keyTicket) } } /** * 表单需要的组件 * * @param id * @param type * @param label * @param name * @param required * @param placeholder * @param options * @param cardTitle * @param gridColumns * @param children */ @Serializable data class FormField( val id: String = "", val type: String = "", val label: String = "", val name: String = "", val required: Boolean = false, @Serializable(with = StringToListSerializer::class) val placeholder: List = listOf(), @Serializable(with = StringToListSerializer::class) var value: List = listOf(), var options: List = listOf(), val cardTitle: String = "", val gridColumns: Int = 0, val enabled: Boolean = true, val multiSelect: Boolean = false, val children: List = listOf(), val maxCount: Int? = null, // 文件上传的最大限制个数 val uploadType: String? = "file" // 上传文件类型 ) /** * 表单Option字段 * * @param label 标题 * @param value 数值 */ @Serializable data class FormOption(val label: String = "", val value: String = "") /** * 节点位置信息 */ @Serializable data class NodePositon(val x: Float, val y: Float) /** * 节点信息 */ @Serializable data class NodeInfo(val edgeCount: Int, val edges: List) /** * 节点连接线信息 */ @Serializable data class NodeConnection( val id: String, val source: String, val target: String, val sourceHandle: String, val targetHandle: String, val type: String ) /** * 拆除盲板需要的字段 */ @Serializable data class Attachment(val name: String = "", val url: String = "")