标准流程管理+流程创建
This commit is contained in:
12
rc_autoplc_backend/.idea/misc.xml
generated
Normal file
12
rc_autoplc_backend/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
6
rc_autoplc_backend/.idea/vcs.xml
generated
Normal file
6
rc_autoplc_backend/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
54
rc_autoplc_backend/.idea/workspace.xml
generated
Normal file
54
rc_autoplc_backend/.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d47bc58e-d36b-422c-92c6-393c467a25d3" name="Changes" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="MavenImportPreferences">
|
||||
<option name="generalSettings">
|
||||
<MavenGeneralSettings>
|
||||
<option name="useMavenConfig" value="true" />
|
||||
</MavenGeneralSettings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectId" id="37uy9ngFoDUVUddX8Yg9afHWRsn" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="d47bc58e-d36b-422c-92c6-393c467a25d3" name="Changes" comment="" />
|
||||
<created>1767767108230</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1767767108230</updated>
|
||||
<workItem from="1767767109651" duration="29000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<title>北京融创智能仪器管理系统</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -8,6 +8,14 @@ export function stepInfoadd(data: any) {
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfoaddlist(data: any) {
|
||||
return request({
|
||||
url: '/stepInfo/batchAdd',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfodel(id: string | number) {
|
||||
return request({
|
||||
url: `/stepInfo/del/${id}`,
|
||||
@@ -15,6 +23,14 @@ export function stepInfodel(id: string | number) {
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfodellist(data: any[]) {
|
||||
return request({
|
||||
url: '/stepInfo/batchDel',
|
||||
method: 'delete',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfoupd(data: any) {
|
||||
return request({
|
||||
url: '/stepInfo/update',
|
||||
@@ -23,6 +39,14 @@ export function stepInfoupd(data: any) {
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfoupdlist(data: any) {
|
||||
return request({
|
||||
url: '/stepInfo/batchUpdate',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export function stepInfolist(data: any) {
|
||||
return request({
|
||||
url: '/stepInfo/listPage',
|
||||
|
||||
@@ -91,6 +91,14 @@
|
||||
/>
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
:type="scope.row.hasWorkflow ? 'success' : 'warning'"
|
||||
link
|
||||
:loading="scope.row.workflowLoading"
|
||||
@click="handleConfigWorkflow(scope.row)"
|
||||
>
|
||||
{{ scope.row.hasWorkflow ? '编辑流程' : '配置流程' }}
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
@@ -203,6 +211,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
@@ -213,6 +222,7 @@ import {
|
||||
flowInfolist,
|
||||
flowInfobyid,
|
||||
} from '@/api/tb/flowinfo'
|
||||
import { stepInfolist } from '@/api/tb/stepinfo'
|
||||
|
||||
interface FlowInfoItem {
|
||||
id?: number | string
|
||||
@@ -226,8 +236,11 @@ interface FlowInfoItem {
|
||||
testMethod?: string
|
||||
scanNum?: string
|
||||
islandIdList?: string
|
||||
hasWorkflow?: boolean
|
||||
workflowLoading?: boolean
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const tableData = ref<FlowInfoItem[]>([])
|
||||
@@ -334,8 +347,40 @@ const getFlowInfoList = async () => {
|
||||
const totalValue =
|
||||
data.total ?? data.count ?? data.totalCount ?? records.length ?? 0
|
||||
|
||||
tableData.value = records
|
||||
tableData.value = records.map((item: any) => ({
|
||||
...item,
|
||||
hasWorkflow: false,
|
||||
workflowLoading: false,
|
||||
}))
|
||||
total.value = Number(totalValue) || 0
|
||||
|
||||
// 查询每条标准流程是否已配置流程
|
||||
await Promise.all(
|
||||
tableData.value.map(async (row) => {
|
||||
if (!row.id) return
|
||||
row.workflowLoading = true
|
||||
try {
|
||||
const res: any = await stepInfolist({
|
||||
flowId: row.id,
|
||||
pageNum: 1,
|
||||
pageSize: 1,
|
||||
})
|
||||
const data = res?.data ?? res ?? {}
|
||||
const records =
|
||||
data.records ||
|
||||
data.list ||
|
||||
data.rows ||
|
||||
data.items ||
|
||||
(Array.isArray(data.data) ? data.data : [])
|
||||
row.hasWorkflow = Array.isArray(records) && records.length > 0
|
||||
} catch (error) {
|
||||
console.error(`查询流程配置状态失败(${row.id}):`, error)
|
||||
row.hasWorkflow = false
|
||||
} finally {
|
||||
row.workflowLoading = false
|
||||
}
|
||||
})
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('获取流程信息列表失败:', error)
|
||||
ElMessage.error('获取流程信息列表失败')
|
||||
@@ -432,6 +477,23 @@ const handleEdit = async (row: FlowInfoItem) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到流程创建/编辑
|
||||
const handleConfigWorkflow = (row: FlowInfoItem) => {
|
||||
if (!row.id) {
|
||||
ElMessage.warning('缺少流程信息ID')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
name: 'step-info',
|
||||
query: {
|
||||
flowId: row.id,
|
||||
flowIndex: row.flowIndex ?? '',
|
||||
flowName: row.flowName ?? '',
|
||||
mode: row.hasWorkflow ? 'edit' : 'create',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 删除流程信息
|
||||
const handleDelete = async (row: FlowInfoItem) => {
|
||||
if (!row.id) {
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
v-for="(item, index) in islandList"
|
||||
:key="item.id"
|
||||
class="island-card"
|
||||
:style="{ animationDelay: `${index * 50}ms` }"
|
||||
>
|
||||
<!-- 左侧步骤编号和过滤器图标 -->
|
||||
<div class="card-left">
|
||||
@@ -945,6 +946,8 @@ onMounted(() => {
|
||||
min-height: 95px;
|
||||
height: 95px;
|
||||
border: 1px solid rgba(64, 158, 255, 0.1);
|
||||
animation: slideUpIn 0.4s ease-out forwards;
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.2);
|
||||
@@ -1100,6 +1103,18 @@ onMounted(() => {
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
// 功能岛卡片动画:从下往上滑动
|
||||
@keyframes slideUpIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
v-for="(item, index) in islandList"
|
||||
:key="item.id"
|
||||
class="component-item"
|
||||
:style="{ animationDelay: `${index * 50}ms` }"
|
||||
draggable="true"
|
||||
@dragstart="handleDragStart($event, item)"
|
||||
>
|
||||
@@ -24,7 +25,29 @@
|
||||
</div>
|
||||
|
||||
<!-- 中间流程设计画布 -->
|
||||
<div class="workflow-canvas" @dragover="handleDragOver" @drop="handleDrop">
|
||||
<div
|
||||
class="workflow-canvas"
|
||||
v-loading="workflowLoading"
|
||||
@dragover="handleDragOver"
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<div class="canvas-header">
|
||||
<div class="canvas-title">
|
||||
<template v-if="flowIndex && flowName">
|
||||
{{ flowIndex }}、{{ flowName }}
|
||||
</template>
|
||||
<template v-else-if="flowName">
|
||||
{{ flowName }}
|
||||
</template>
|
||||
<template v-else>
|
||||
未选择标准流程
|
||||
</template>
|
||||
</div>
|
||||
<div class="canvas-status">
|
||||
<el-tag v-if="isEditMode" type="success" effect="plain">编辑流程</el-tag>
|
||||
<el-tag v-else type="warning" effect="plain">配置流程</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="workflowItems.length === 0" class="empty-canvas">
|
||||
拖拽左侧功能岛到此处创建流程步骤
|
||||
</div>
|
||||
@@ -35,6 +58,7 @@
|
||||
:key="index"
|
||||
class="workflow-item"
|
||||
:class="{ 'is-selected': selectedItemIndex === index }"
|
||||
:style="{ animationDelay: `${index * 100}ms` }"
|
||||
draggable="true"
|
||||
@dragstart="handleWorkflowItemDragStart($event, index)"
|
||||
@dragover.stop="handleWorkflowItemDragOver($event, index)"
|
||||
@@ -84,9 +108,8 @@
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<el-button @click="clearWorkflow">清空</el-button>
|
||||
<el-button type="primary" plain @click="createWorkflow">新建</el-button>
|
||||
<el-button type="primary" @click="saveWorkflow">保存</el-button>
|
||||
<el-button type="primary" plain @click="clearWorkflow">清空</el-button>
|
||||
<el-button type="primary" @click="saveWorkflow" :loading="savingWorkflow">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -175,6 +198,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
MoreFilled,
|
||||
@@ -198,16 +222,50 @@ import { devselect } from '@/api/tb/devinfo'
|
||||
import { devparamselect } from '@/api/tb/devparam'
|
||||
import { dictypelist } from '@/api/system/dictype'
|
||||
import { dicdatabydicid } from '@/api/system/dicdata'
|
||||
import {
|
||||
stepInfoaddlist,
|
||||
stepInfodel,
|
||||
stepInfodellist,
|
||||
stepInfoupdlist,
|
||||
stepInfolist,
|
||||
} from '@/api/tb/stepinfo'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// 路由携带的标准流程信息
|
||||
const flowId = computed(() => {
|
||||
const raw = route.query.flowId
|
||||
const num = Number(raw)
|
||||
return Number.isNaN(num) ? undefined : num
|
||||
})
|
||||
const flowName = computed(() => (route.query.flowName as string) || '')
|
||||
const flowIndex = computed(() => (route.query.flowIndex as string) || '')
|
||||
const hasRemoteWorkflow = ref(false)
|
||||
const isEditMode = computed(() => {
|
||||
const mode = (route.query.mode as string) || ''
|
||||
return mode === 'edit' || hasRemoteWorkflow.value
|
||||
})
|
||||
|
||||
// 功能岛列表
|
||||
const islandList = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const workflowLoading = ref(false)
|
||||
|
||||
// 当前流程中的组件
|
||||
const workflowItems = ref<any[]>([])
|
||||
const selectedItemIndex = ref(-1)
|
||||
const workflowGridRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const generateInstanceId = (base?: number | string) =>
|
||||
`island-${base ?? 'unknown'}-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||
const getInstanceId = (item: any) => {
|
||||
if (!item.instanceId) {
|
||||
item.instanceId = generateInstanceId(item.id)
|
||||
}
|
||||
return item.instanceId
|
||||
}
|
||||
|
||||
// 计算网格样式
|
||||
const gridStyle = computed(() => {
|
||||
const count = workflowItems.value.length
|
||||
@@ -238,6 +296,7 @@ const paramList = ref<any[]>([])
|
||||
const paramFormData = reactive<Record<string, any>>({})
|
||||
const paramLoading = ref(false)
|
||||
const savingParams = ref(false)
|
||||
const savingWorkflow = ref(false)
|
||||
|
||||
// 字典类型和字典数据缓存
|
||||
const dicTypeCache = ref<Map<string, any>>(new Map())
|
||||
@@ -245,6 +304,24 @@ const dicDataCache = ref<Map<number, any[]>>(new Map())
|
||||
|
||||
// 参数选项映射:paramId -> options[]
|
||||
const paramOptionsMap = reactive<Record<string | number, Array<{ label: string; value: string }>>>({})
|
||||
const paramCache = reactive<Record<string, any[]>>({})
|
||||
const clearParamCache = () => {
|
||||
Object.keys(paramCache).forEach((key) => {
|
||||
delete paramCache[key]
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeListResponse = (res: any) => {
|
||||
const data = res?.data ?? res ?? {}
|
||||
return (
|
||||
data.records ||
|
||||
data.list ||
|
||||
data.rows ||
|
||||
data.items ||
|
||||
(Array.isArray(data.data) ? data.data : []) ||
|
||||
[]
|
||||
)
|
||||
}
|
||||
|
||||
// 中文数字
|
||||
const chineseNumbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
||||
@@ -373,6 +450,11 @@ const getIslandList = async () => {
|
||||
})
|
||||
|
||||
islandList.value = records
|
||||
|
||||
// 若带有标准流程信息则尝试加载已保存的流程
|
||||
if (flowId.value) {
|
||||
await loadWorkflowFromServer()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取功能岛列表失败:', error)
|
||||
ElMessage.error('获取功能岛列表失败')
|
||||
@@ -381,6 +463,88 @@ const getIslandList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 从后端加载已有流程并反填
|
||||
const loadWorkflowFromServer = async () => {
|
||||
if (!flowId.value) return
|
||||
try {
|
||||
workflowLoading.value = true
|
||||
const res: any = await stepInfolist({
|
||||
flowId: flowId.value,
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
})
|
||||
|
||||
const records = normalizeListResponse(res)
|
||||
if (!Array.isArray(records) || records.length === 0) {
|
||||
hasRemoteWorkflow.value = false
|
||||
workflowItems.value = []
|
||||
clearParamCache()
|
||||
return
|
||||
}
|
||||
|
||||
const sortedRecords = [...records].sort(
|
||||
(a: any, b: any) => (a?.stepOrder ?? 0) - (b?.stepOrder ?? 0)
|
||||
)
|
||||
|
||||
workflowItems.value = []
|
||||
clearParamCache()
|
||||
const islandCountMap: Record<string, number> = {}
|
||||
let lastIslandId: any = null
|
||||
let currentInstanceId = ''
|
||||
|
||||
sortedRecords.forEach((record: any) => {
|
||||
const islandId = record.islandId ?? record.islandID ?? record.islandid
|
||||
const islandNameFromRecord = record.islandName || record.islandname || ''
|
||||
if (lastIslandId !== islandId) {
|
||||
const islandMeta = islandList.value.find((it) => it.id === islandId) || {}
|
||||
const islandName = islandMeta.islandName || islandMeta.name || islandNameFromRecord || '功能岛'
|
||||
const descriptionKey = getIslandDescriptionKey(islandName)
|
||||
const count = islandCountMap[descriptionKey] ?? 0
|
||||
islandCountMap[descriptionKey] = count + 1
|
||||
currentInstanceId = generateInstanceId(islandId)
|
||||
workflowItems.value.push({
|
||||
...islandMeta,
|
||||
id: islandId,
|
||||
islandName,
|
||||
name: islandMeta.name || islandName,
|
||||
description: `第${chineseNumbers[count] || count + 1}次${descriptionKey || islandName}`,
|
||||
sort: count,
|
||||
instanceId: currentInstanceId,
|
||||
})
|
||||
paramCache[currentInstanceId] = []
|
||||
lastIslandId = islandId
|
||||
}
|
||||
|
||||
if (!currentInstanceId) return
|
||||
const cacheArr = paramCache[currentInstanceId] || []
|
||||
paramCache[currentInstanceId] = cacheArr
|
||||
cacheArr.push({
|
||||
stepId: record.id,
|
||||
flowId: flowId.value,
|
||||
islandId,
|
||||
islandName: islandNameFromRecord,
|
||||
devId: record.devId ?? record.devid,
|
||||
devName: record.devName ?? record.devname,
|
||||
paramId: record.paramId ?? record.paramid,
|
||||
paramName: record.paramName,
|
||||
paramType: record.paramType,
|
||||
paramUnit: record.paramUnit,
|
||||
paramValue: record.paramValue,
|
||||
formType: record.formType,
|
||||
stepOrder: record.stepOrder,
|
||||
})
|
||||
})
|
||||
|
||||
hasRemoteWorkflow.value = workflowItems.value.length > 0
|
||||
selectedItemIndex.value = -1
|
||||
} catch (error) {
|
||||
console.error('加载流程数据失败:', error)
|
||||
ElMessage.error('加载流程数据失败')
|
||||
} finally {
|
||||
workflowLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 拖拽开始
|
||||
const handleDragStart = (event: DragEvent, item: any) => {
|
||||
// 检查是否超过添加次数限制
|
||||
@@ -423,6 +587,7 @@ const handleDrop = (event: DragEvent) => {
|
||||
...dragItemData,
|
||||
description: `第${chineseNumbers[count]}次${descriptionKey}`,
|
||||
sort: 0,
|
||||
instanceId: generateInstanceId(dragItemData.id),
|
||||
}
|
||||
|
||||
workflowItems.value.push(newItem)
|
||||
@@ -462,6 +627,7 @@ const handleContainerDrop = (event: DragEvent) => {
|
||||
...dragItemData,
|
||||
description: `第${chineseNumbers[count]}次${descriptionKey}`,
|
||||
sort: count,
|
||||
instanceId: generateInstanceId(dragItemData.id),
|
||||
}
|
||||
|
||||
const items = document.querySelectorAll('.workflow-item')
|
||||
@@ -607,6 +773,8 @@ const handleEdit = async (item: any) => {
|
||||
try {
|
||||
paramLoading.value = true
|
||||
paramList.value = []
|
||||
const instanceId = getInstanceId(item)
|
||||
const cachedParams = paramCache[instanceId] || []
|
||||
|
||||
// 获取功能岛绑定的设备
|
||||
const devRes: any = await devselect({})
|
||||
@@ -644,10 +812,20 @@ const handleEdit = async (item: any) => {
|
||||
})
|
||||
// 给每个参数添加设备信息
|
||||
params.forEach((param: any) => {
|
||||
const cached = cachedParams.find(
|
||||
(cacheItem: any) =>
|
||||
cacheItem.paramId === param.id ||
|
||||
cacheItem.paramName === param.paramName
|
||||
)
|
||||
allParams.push({
|
||||
...param,
|
||||
devId: device.id,
|
||||
devName: device.devName || `设备${device.id}`,
|
||||
paramValue: cached?.paramValue ?? param.paramValue,
|
||||
paramType: cached?.paramType ?? param.paramType,
|
||||
paramUnit: cached?.paramUnit ?? param.paramUnit,
|
||||
formType: cached?.formType ?? param.formType,
|
||||
stepId: cached?.stepId,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -664,7 +842,7 @@ const handleEdit = async (item: any) => {
|
||||
})
|
||||
allParams.forEach((param) => {
|
||||
if (param.id) {
|
||||
paramFormData[param.id] = param.paramValue || ''
|
||||
paramFormData[param.id] = param.paramValue ?? ''
|
||||
}
|
||||
})
|
||||
|
||||
@@ -763,9 +941,30 @@ const loadParamOptions = async (params: any[]) => {
|
||||
const handleSaveParams = async () => {
|
||||
try {
|
||||
savingParams.value = true
|
||||
// TODO: 调用API保存参数值
|
||||
// 这里需要根据实际的API接口来保存参数值
|
||||
ElMessage.success('保存成功')
|
||||
if (!editingItem.value) {
|
||||
ElMessage.warning('未选中功能岛')
|
||||
return
|
||||
}
|
||||
|
||||
const instanceId = getInstanceId(editingItem.value)
|
||||
const paramsForCache =
|
||||
paramList.value.map((param) => ({
|
||||
stepId: param.stepId,
|
||||
flowId: flowId.value,
|
||||
islandId: editingItem.value.id,
|
||||
islandName: editingItem.value.islandName || editingItem.value.name,
|
||||
devId: param.devId,
|
||||
devName: param.devName,
|
||||
paramId: param.id,
|
||||
paramName: param.paramName,
|
||||
paramType: param.paramType,
|
||||
paramUnit: param.paramUnit,
|
||||
paramValue: paramFormData[param.id],
|
||||
formType: param.formType,
|
||||
})) || []
|
||||
|
||||
paramCache[instanceId] = paramsForCache
|
||||
ElMessage.success('参数保存成功')
|
||||
drawerVisible.value = false
|
||||
} catch (error) {
|
||||
console.error('保存参数失败:', error)
|
||||
@@ -782,7 +981,26 @@ const handleDelete = (index: number, item: any) => {
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
const cacheKey = getInstanceId(item)
|
||||
const cachedParams = paramCache[cacheKey] || []
|
||||
|
||||
// 删除已保存的步骤数据
|
||||
if (hasRemoteWorkflow.value && cachedParams.some((p) => p.stepId)) {
|
||||
try {
|
||||
await Promise.all(
|
||||
cachedParams
|
||||
.map((p) => p.stepId)
|
||||
.filter(Boolean)
|
||||
.map((id) => stepInfodel(id))
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('删除功能岛关联步骤失败:', error)
|
||||
ElMessage.error('删除功能岛关联步骤失败')
|
||||
}
|
||||
}
|
||||
|
||||
delete paramCache[cacheKey]
|
||||
workflowItems.value.splice(index, 1)
|
||||
if (selectedItemIndex.value === index) {
|
||||
selectedItemIndex.value = -1
|
||||
@@ -810,23 +1028,131 @@ const handleDelete = (index: number, item: any) => {
|
||||
}
|
||||
|
||||
// 清空
|
||||
const clearWorkflow = () => {
|
||||
workflowItems.value = []
|
||||
selectedItemIndex.value = -1
|
||||
ElMessage.info('已清空当前流程')
|
||||
const clearWorkflow = async () => {
|
||||
// 如果是编辑模式(从编辑流程按钮跳转过来),需要调用删除接口
|
||||
if (isEditMode.value && flowId.value) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`您确定要清除[${flowName.value || '该'}]的完整流程吗?`,
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
|
||||
// 先获取所有需要删除的数据 ID
|
||||
try {
|
||||
const res: any = await stepInfolist({
|
||||
flowId: flowId.value,
|
||||
pageNum: 1,
|
||||
pageSize: 10000,
|
||||
})
|
||||
|
||||
const records = normalizeListResponse(res)
|
||||
if (Array.isArray(records) && records.length > 0) {
|
||||
const ids = records.map((r: any) => r.id).filter(Boolean)
|
||||
if (ids.length > 0) {
|
||||
await stepInfodellist(ids)
|
||||
ElMessage.success('流程已清空,可重新配置流程')
|
||||
} else {
|
||||
ElMessage.info('没有可删除的数据')
|
||||
}
|
||||
} else {
|
||||
ElMessage.info('没有可删除的数据')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除流程数据失败:', error)
|
||||
ElMessage.error('删除流程数据失败')
|
||||
return
|
||||
}
|
||||
|
||||
// 新建
|
||||
const createWorkflow = () => {
|
||||
// 清空画布和缓存
|
||||
workflowItems.value = []
|
||||
selectedItemIndex.value = -1
|
||||
ElMessage.success('已创建新的流程')
|
||||
clearParamCache()
|
||||
hasRemoteWorkflow.value = false
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('清空流程失败:', error)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 配置模式或从菜单栏直接进入,仅清除画布卡片
|
||||
workflowItems.value = []
|
||||
selectedItemIndex.value = -1
|
||||
clearParamCache()
|
||||
ElMessage.info('已清空当前流程')
|
||||
}
|
||||
}
|
||||
|
||||
// 保存
|
||||
const saveWorkflow = () => {
|
||||
// 暂时留空,后续实现
|
||||
ElMessage.info('保存功能待实现')
|
||||
const saveWorkflow = async () => {
|
||||
if (!flowId.value) {
|
||||
ElMessage.warning('请先选择标准流程!')
|
||||
return
|
||||
}
|
||||
if (!flowName.value) {
|
||||
ElMessage.warning('缺少标准流程名称(stepName),请返回列表补全')
|
||||
return
|
||||
}
|
||||
if (workflowItems.value.length === 0) {
|
||||
ElMessage.warning('请先在画布上添加功能岛')
|
||||
return
|
||||
}
|
||||
|
||||
let stepOrder = 1
|
||||
const payload: any[] = []
|
||||
|
||||
for (const item of workflowItems.value) {
|
||||
const cacheKey = getInstanceId(item)
|
||||
const params = paramCache[cacheKey] || []
|
||||
if (!params.length) {
|
||||
ElMessage.warning(`请先为${item.islandName || item.name || '功能岛'}配置参数并保存`)
|
||||
return
|
||||
}
|
||||
|
||||
params.forEach((param) => {
|
||||
payload.push({
|
||||
id: param.stepId,
|
||||
flowId: flowId.value,
|
||||
islandId: item.id,
|
||||
devId: param.devId,
|
||||
paramName: param.paramName,
|
||||
paramType: param.paramType,
|
||||
paramUnit: param.paramUnit,
|
||||
paramValue: param.paramValue ?? '',
|
||||
formType: param.formType,
|
||||
stepName: flowName.value,
|
||||
stepOrder: stepOrder++,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (!payload.length) {
|
||||
ElMessage.warning('暂无可保存的参数数据')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
savingWorkflow.value = true
|
||||
const apiAction = hasRemoteWorkflow.value ? stepInfoupdlist : stepInfoaddlist
|
||||
const res: any = await apiAction(payload)
|
||||
if (res?.code === 0 || res?.code === '0') {
|
||||
ElMessage.success(hasRemoteWorkflow.value ? '流程更新成功!' : '流程保存成功')
|
||||
hasRemoteWorkflow.value = true
|
||||
clearParamCache()
|
||||
await loadWorkflowFromServer()
|
||||
} else {
|
||||
ElMessage.error(res?.message || res?.msg || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存流程失败:', error)
|
||||
ElMessage.error('保存流程失败')
|
||||
} finally {
|
||||
savingWorkflow.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭抽屉
|
||||
@@ -921,6 +1247,8 @@ onMounted(() => {
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
transition: all 0.3s;
|
||||
animation: slideUpIn 0.4s ease-out forwards;
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
@@ -961,6 +1289,30 @@ onMounted(() => {
|
||||
position: relative;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.canvas-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #d9ecff;
|
||||
}
|
||||
|
||||
.canvas-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.canvas-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.empty-canvas {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@@ -1019,6 +1371,8 @@ onMounted(() => {
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
animation: fadeInUp 0.5s ease-out forwards;
|
||||
opacity: 0;
|
||||
|
||||
&.is-selected {
|
||||
border-color: #409eff;
|
||||
@@ -1273,5 +1627,29 @@ onMounted(() => {
|
||||
padding: 20px;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
// 功能岛卡片动画:从下往上滑动
|
||||
@keyframes slideUpIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 流程卡片动画:淡入+向上移动
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user