소스 검색

作业执行监控页面基础信息接口对接,作业执行流程展示,底部页面部分内容绘制

wyn 3 달 전
부모
커밋
3576d4afb9
2개의 변경된 파일779개의 추가작업 그리고 84개의 파일을 삭제
  1. 778 84
      src/views/jobTicket/job/JobMonitor.vue
  2. 1 0
      src/views/jobTicket/job/ModeView/TableView.vue

+ 778 - 84
src/views/jobTicket/job/JobMonitor.vue

@@ -1,28 +1,34 @@
 <template>
 <template>
-<!--基本信息-->
+  <!--基本信息-->
   <ContentWrap>
   <ContentWrap>
     <div class="basicInformation">
     <div class="basicInformation">
       <div class="tab-header">
       <div class="tab-header">
-        <img src="@/assets/images/information.png" alt="" class="titleimg"/><span class="tab-title"> 基本信息</span>
+        <img src="@/assets/images/information.png" alt="" class="titleimg" /><span
+          class="tab-title"
+        >
+          基本信息</span
+        >
       </div>
       </div>
       <div class="basicContent">
       <div class="basicContent">
-        <p>SOP: <span>CCO-老液体 2cco#粉料系统-维修</span> </p>
-        <p>作业区域: <span>CCO-BD</span> </p>
-        <p>工艺设备: <span>搅拌机-03</span> </p>
-        <p>作业类型: <span>维修</span> </p>
-        <p>作业状态: <span>进行中</span> </p>
-        <p>开始时间: <span>2025-07-04 14:10:01</span> </p>
-        <p>结束时间: <span>-</span> </p>
-        <p>当前步骤: <span class="specialText">确认隔离方式</span> </p>
-        <p>最新日志: <span>2025-07-04 14:10:01 张天乐 已确认执行识别工作内容</span> </p>
+        <p>作业名称: <span>{{JobForm.ticketName}}</span> </p>
+        <p>作业区域: <span>{{JobForm.workstationName}}</span> </p>
+        <p>工艺设备: <span>{{JobForm.machineryName}}</span> </p>
+        <p>作业类型: <span>{{ ticketTypeLabel }}</span></p>
+        <p>作业状态: <span>{{ ticketStatusLabel }}</span></p>
+        <p>开始时间: <span>{{JobForm.ticketStartTime}}</span> </p>
+        <p>结束时间: <span>{{JobForm.ticketEndTime}}</span> </p>
+        <p>当前步骤: <span class="specialText">待更新</span> </p>
+        <p>最新日志: <span>待更新</span> </p>
       </div>
       </div>
     </div>
     </div>
   </ContentWrap>
   </ContentWrap>
-<!--作业流程-->
+  <!--作业流程-->
   <ContentWrap>
   <ContentWrap>
     <div class="jobProcess">
     <div class="jobProcess">
       <div class="tab-header">
       <div class="tab-header">
-        <img src="@/assets/images/jobProcess.png" alt="" class="titleimg"/><span class="tab-title">作业流程</span>
+        <img src="@/assets/images/jobProcess.png" alt="" class="titleimg" /><span class="tab-title"
+          >作业流程</span
+        >
       </div>
       </div>
       <div class="processDetail">
       <div class="processDetail">
         <!-- VueFlow 主画布 -->
         <!-- VueFlow 主画布 -->
@@ -55,12 +61,7 @@
                 :id="`${id}-bottom`"
                 :id="`${id}-bottom`"
                 class="handle handle-bottom"
                 class="handle handle-bottom"
               />
               />
-              <Handle
-                type="target"
-                position="left"
-                :id="`${id}-left`"
-                class="handle handle-left"
-              />
+              <Handle type="target" position="left" :id="`${id}-left`" class="handle handle-left" />
               <Handle
               <Handle
                 type="source"
                 type="source"
                 position="right"
                 position="right"
@@ -73,84 +74,487 @@
       </div>
       </div>
     </div>
     </div>
   </ContentWrap>
   </ContentWrap>
-
   <!--作业执行-->
   <!--作业执行-->
   <ContentWrap>
   <ContentWrap>
     <div class="jobExecution">
     <div class="jobExecution">
-        <el-tabs
-          v-model="activeName"
-          type="card"
-          class="demo-tabs"
-          @tab-click="handleClick"
-        >
-          <el-tab-pane name="first">
-            <template #label>
-              <div class="tab-label">
-                <img src="@/assets/images/icon_job_members.png" alt="" class="titleimg" />
-                <span class="tab-text ">作业人员</span>
+      <el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleClick">
+        <!-- 作业人员-->
+        <el-tab-pane name="first">
+          <template #label>
+            <div class="tab-label">
+              <img src="@/assets/images/icon_job_members.png" alt="" class="titleimg" />
+              <span class="tab-text">作业人员</span>
+            </div>
+          </template>
+          <div class="jobMemberBox">
+            <!-- 锁定人区域 -->
+            <div class="left_box">
+              <div class="tab-header">
+                <span class="tab-title">锁定人</span>
               </div>
               </div>
-            </template>
-            <div class="jobMemberBox">
-<!--              锁定人-->
-              <div class="lockmember"></div>
-<!--              共锁人-->
-              <div class="co-lockmember"></div>
 
 
+              <!-- 有锁定人数据时显示 -->
+              <div v-if="groupedLockers.length" class="group-container-user">
+                <div v-for="group in groupedLockers" :key="group.groupId" class="group-card-user">
+                  <div class="group-title">{{ group.groupName }}</div>
+                  <div class="user-list">
+                    <div v-for="user in group.users" :key="user.userId" class="user-card">
+                      <img src="@/assets/images/UserBlack.png" />
+                      <div class="user-name">{{ user.userName }}</div>
+                    </div>
+                  </div>
+                </div>
+              </div>
             </div>
             </div>
-          </el-tab-pane>
+            <!-- 共锁人区域 -->
+            <div class="right_box">
+              <div class="tab-header">
+                <span class="tab-title">共锁人</span>
+              </div>
+              <div v-if="coLockUsers.length" class="user-list-colocker">
+                <div v-for="user in coLockUsers" :key="user.userId" class="user-card">
+                  <img src="@/assets/images/UserBlack.png" />
+                  <div class="user-name">{{ user.userName }}</div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+        <!--点位锁定-->
+        <el-tab-pane name="second">
+          <template #label>
+            <div class="tab-label">
+              <img src="@/assets/images/icon_red_lock.png" alt="" class="titleimg" />
+              <span class="tab-text">点位锁定</span>
+            </div>
+          </template>
+          <div class="jobMemberBox">
+            <div
+              class="group-box"
+              v-for="(group, index) in jobGroupList"
+              :key="group.id"
+            >
+              <div class="tab-header">
+                <p class="tab-title">{{ group.groupName }}</p>
+              </div>
+              <!-- 表格数据 -->
+              <div class="tableCon">
+                <el-radio-group v-model="tableLayouts[index]">
+                  <el-radio-button value="fixed">fixed</el-radio-button>
+                  <el-radio-button value="auto">auto</el-radio-button>
+                </el-radio-group>
+                <el-table
+                  :data="getPointsByGroupId(group.id)"
+                  :table-layout="tableLayouts[index]"
+                >
+                  <el-table-column prop="pointId" label="隔离点" />
+                  <el-table-column prop="ticketId" label="作用" />
+                  <el-table-column prop="ticketId" label="锁定人" />
+                  <el-table-column prop="pointStatus" label="锁定状态" >
+                    <template #default="scope">
+                      <dict-tag
+                        :type="DICT_TYPE.POINT_STATUS"
+                        :value="scope.row.pointStatus"
+                      />
+                    </template>
+                  </el-table-column>
 
 
-          <el-tab-pane name="second">
-            <template #label>
-              <div class="tab-label">
-                <img src="@/assets/images/icon_red_lock.png" alt="" class="titleimg" />
-                <span class="tab-text ">点位锁定</span>
+                </el-table>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+        <!-- 人员共锁 -->
+        <el-tab-pane name="third">
+          <template #label>
+            <div class="tab-label">
+              <img src="@/assets/images/icon_co-lock.png" alt="" class="titleimg" />
+              <span class="tab-text">人员共锁</span>
+            </div>
+          </template>
+          <div class="biglockBox">
+            <!-- 待共锁-->
+            <div class="mumberbox">
+              <div class="tab-header">
+                <span class="tab-title">待共锁(5)</span>
+              </div>
+              <div class="user">
+                <div class="userItem" >
+                  <img src="@/assets/images/icon_co-lock.png" alt=""/>
+                  <p>哇哈哈</p>
+                </div>
+              </div>
+            </div>
+            <el-icon :size="50" :color="color" class="arrow">
+              <CaretRight />
+            </el-icon>
+            <!-- 已共锁-->
+            <div class="mumberbox">
+              <div class="tab-header">
+                <span class="tab-title">已共锁(5)</span>
               </div>
               </div>
-            </template>
-            Config
-          </el-tab-pane>
-
-          <el-tab-pane name="third">
-            <template #label>
-              <div class="tab-label">
-                <img src="@/assets/images/icon_co-lock.png" alt="" class="titleimg" />
-                <span class="tab-text ">人员共锁</span>
+              <div class="user">
+                <div class="userItem" >
+                  <img src="@/assets/images/icon_co-lock.png" alt=""/>
+                  <p>哇哈哈</p>
+                </div>
               </div>
               </div>
-            </template>
-            Role
-          </el-tab-pane>
-
-          <el-tab-pane name="fourth">
-            <template #label>
-              <div class="tab-label">
-                <img src="@/assets/images/icon_job_log.png" alt="" class="titleimg" />
-                <span class="tab-text ">作业日志</span>
+            </div>
+            <el-icon :size="50" :color="color" class="arrow">
+              <CaretRight />
+            </el-icon>
+            <!-- 未共锁-->
+            <div class="mumberbox">
+              <div class="tab-header">
+                <span class="tab-title">未共锁(0)</span>
               </div>
               </div>
-            </template>
-            Task
-          </el-tab-pane>
-        </el-tabs>
+              <div class="user">
+                <div class="userItem" >
+                  <img src="@/assets/images/icon_co-lock.png" alt=""/>
+                  <p>哇哈哈</p>
+                </div>
+                <div class="userItem" >
+                  <img src="@/assets/images/icon_co-lock.png" alt=""/>
+                  <p>哇哈哈</p>
+                </div>
 
 
 
 
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+        <!--作业日志-->
+        <el-tab-pane name="fourth">
+          <template #label>
+            <div class="tab-label">
+              <img src="@/assets/images/icon_job_log.png" alt="" class="titleimg" />
+              <span class="tab-text">作业日志</span>
+            </div>
+          </template>
+          Task
+        </el-tab-pane>
+      </el-tabs>
     </div>
     </div>
-
   </ContentWrap>
   </ContentWrap>
-
 </template>
 </template>
 
 
-
 <script setup lang="ts">
 <script setup lang="ts">
-import {Handle, VueFlow} from "@vue-flow/core";
+import { Handle, useVueFlow, VueFlow } from '@vue-flow/core'
 import { ref } from 'vue'
 import { ref } from 'vue'
+import * as JobPointGroup from '@/api/job/jobPointGroup'
+import * as PointApi from '@/api/dv/spm/index'
+import * as JobApi from '@/api/job/index'
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import type { TableInstance } from 'element-plus'
+import { CaretRight } from '@element-plus/icons-vue'
 
 
-const route = useRoute()
-console.log(route.query.id,'是否传递成功')
+const tableLayout = ref<TableInstance['tableLayout']>('fixed')
+const tableLayout1 = ref<TableInstance['tableLayout1']>('fixed')
+
+const JobForm = reactive({
+  createTime: null,
+  id: null,
+  machineryId: null,
+  machineryName: null,
+  modeId: null,
+  sopGroupList: null,
+  sopIndex: null,
+  sopName: null,
+  workstationId: null,
+  workstationName: null,
+  ticketCode: null,
+  ticketName: null,
+  sopId: null,
+  ticketType: null,
+  ticketContent: null,
+  ticketStatus: null,
+  ticketStartTime: null,
+  ticketEndTime: null,
+  ticketGroupList: null,
+  ticketPointsList: null,
+  ticketStepList: null,
+  ticketUserList: null
+})
+const allGroups = ref<any[]>([]) //获取所有分组
+const groupList = ref([]) //获取当前sopId的分组
+const allPoints = ref<any[]>([]) //获取所有点位
 const activeName = ref('first')
 const activeName = ref('first')
+const route = useRoute()
+const jobTypeOptions = ref([])
+const jobStatusOptions = ref([])
+// 表格数据
+const jobGroupList=ref([]) //获取作业分组信息
+const ticketPointsList = ref([]) // 隔离点数据
+const tableLayouts = ref([]) // 每组表格的布局
+
+
+// 初始化
+onMounted(async () => {
+  await getDetail()
+  jobTypeOptions.value = await getIntDictOptions(DICT_TYPE.TICKET_TYPE)
+  jobStatusOptions.value = await getIntDictOptions(DICT_TYPE.TICKET_STATUS)
+  await fetchAllGroupsAndPoints() //获取所有分组和点位 来渲染SOP的首页
+  await onModeContent()
+})
+console.log(route.query.id, '是否传递成功')
+
+const ticketTypeLabel = computed(() => {
+  const match = jobTypeOptions.value.find(item => item.value == JobForm.ticketType)
+  return match ? match.label : JobForm.ticketType
+})
+
+const ticketStatusLabel = computed(() => {
+  const match = jobStatusOptions.value.find(item => item.value == JobForm.ticketStatus)
+  return match ? match.label : JobForm.ticketStatus
+})
+
+// 获取详情
+// const getDetail = async () => {
+//   // 获取sop信息
+//   const JobData = await JobApi.selectJobTicketById(route.query.id)
+//   // 将JobData的数据复制给JobForm
+//   Object.assign(JobForm, JobData)
+//   jobGroupList.value=JobForm.ticketGroupList
+//   tableData.value = JobForm.ticketPointsList
+//   console.log(JobData,'数据有哪些',tableData.value,'隔离点数据',jobGroupList.value,'分组信息')
+// }
+
+// 初始化详情数据
+const getDetail = async () => {
+  const JobData = await JobApi.selectJobTicketById(route.query.id)
+  // 将JobData的数据复制给JobForm
+  Object.assign(JobForm, JobData)
+
+  jobGroupList.value = JobForm.ticketGroupList
+  ticketPointsList.value = JobForm.ticketPointsList
+  console.log(JobData,'数据有哪些',ticketPointsList.value,'隔离点数据',jobGroupList.value,'分组信息')
+  // 初始化每个表格的布局设置为 'fixed'
+  tableLayouts.value = jobGroupList.value.map(() => 'fixed')
+}
+
+// 获取某个分组下的隔离点
+const getPointsByGroupId = (groupId) => {
+  return ticketPointsList.value.filter((point) => point.groupId === groupId)
+}
+
+
+
+
+// 作业流程绘制
+const nodes = ref([]) //储存节点
+const edges = ref([]) // 存储连接线
+const { addNodes, addEdges, setEdges, setNodes } = useVueFlow()
+// 模式初始化
+const onModeContent = async (value) => {
+  JobForm.modeId = value
+  await clearCanvasProperly()
+  const Data = await JobApi.selectJobTicketById(route.query.id)
+  const sortedData = Data.ticketStepList.sort((a, b) => (a.stepIndex || 0) - (b.stepIndex || 0))
+  renderNodesFromData(sortedData)
+  renderEdgesFromData(sortedData)
+}
+
+// 独立的清空画布函数
+const clearCanvasProperly = async () => {
+  setNodes([])
+  setEdges([])
+  nodes.value = [] // 同步响应式数据(如果有自定义 nodes)
+  edges.value = []
+}
+// 初始化数据渲染节点 - 修正版本
+const renderNodesFromData = (data) => {
+  // 清空现有节点
+  nodes.value = []
+
+  data.forEach((item, index) => {
+    const nodeId = `node-${item.id || Date.now() + index}`
+
+    const newNode = {
+      id: nodeId,
+      position: {
+        x: 100 + index * 200,
+        y: 100
+      },
+      width: 100,
+      height: 150,
+      data: {
+        stepIcon: item.stepIcon,
+        stepTitleShort: item.stepTitleShort,
+        stepIndex: item.stepIndex || index + 1, // 使用 stepIndex
+        index: item.stepIndex || index + 1, // 保持兼容性
+        // 保存完整的数据用于表单编辑
+        stepData: item
+      },
+      style: {
+        width: '130px',
+        height: '180px',
+        borderRadius: '12px',
+        border: '1px solid #999',
+        textAlign: 'center',
+        display: 'flex',
+        flexDirection: 'column',
+        alignItems: 'center',
+        justifyContent: 'space-between',
+        padding: '10px',
+        backgroundColor: '#fff'
+      },
+      draggable: true
+    }
+
+    addNodes(newNode)
+    nodes.value.push(newNode)
+  })
+}
+
+// 渲染连接线 - 新增函数
+const renderEdgesFromData = (data) => {
+  // 清空现有连接线
+  edges.value = []
+
+  // 根据 stepIndex 顺序创建连接线
+  for (let i = 0; i < data.length - 1; i++) {
+    const currentStep = data[i]
+    const nextStep = data[i + 1]
+
+    const sourceNodeId = `node-${currentStep.id}`
+    const targetNodeId = `node-${nextStep.id}`
+
+    // 创建连接线,从右侧连接到左侧
+    const edge = {
+      id: `edge-${currentStep.id}-${nextStep.id}`,
+      source: sourceNodeId,
+      target: targetNodeId,
+      sourceHandle: `${sourceNodeId}-right`, // 从右侧连接点出发
+      targetHandle: `${targetNodeId}-left`, // 连接到左侧连接点
+      type: 'smoothstep',
+      style: { stroke: '#333', strokeWidth: 2 },
+      markerEnd: {
+        type: 'arrowclosed',
+        width: 20,
+        height: 20,
+        color: '#333'
+      }
+    }
+
+    addEdges(edge)
+    edges.value.push(edge)
+
+    console.log('创建连接线:', edge)
+  }
+}
 
 
 const handleClick = (tab: TabsPaneContext, event: Event) => {
 const handleClick = (tab: TabsPaneContext, event: Event) => {
   console.log(tab, event)
   console.log(tab, event)
 }
 }
-</script>
 
 
+//ticketType改变函数
+const handleTicketpTypeChange = (value) => {
+  JobForm.ticketType = value
+}
+
+// 获取所有点位和分组的数据
+const fetchAllGroupsAndPoints = async () => {
+  try {
+    // 分组信息
+    const groupRes = await JobPointGroup.getJobTicketGroupPage({ pageSize: -1, pageNo: 1 })
+    allGroups.value = groupRes.list
+    console.log('获取分组', groupRes.list)
+    // 获取当前ticketId的分组
+    if (route.query.id) {
+      const groupData = await JobPointGroup.getJobTicketGroupPage({
+        pageSize: -1,
+        pageNo: 1,
+        ticketId: route.query.id
+      })
+      groupList.value = groupData.list
+    }
+
+    // 点位信息
+    const pointRes = await PointApi.getIsIsolationPointPage({ pageSize: -1, pageNo: 1 })
+    allPoints.value = pointRes?.list
+    console.log('获取点位', pointRes)
+  } catch (e) {}
+}
+// 回显分组和点位数据的计算属性
+const resolvedGroupedPoints = computed(() => {
+  const groupsMap = new Map<string, { groupId: string; groupName: string; points: any[] }>()
+
+  console.log('JobForm.sopPointsList:', JobForm.ticketPointsList)
+  console.log('allGroups.value:', allGroups.value)
+  console.log('allPoints.value:', allPoints.value)
+
+  JobForm.ticketPointsList.forEach((item) => {
+    const groupId = String(item.groupId)
+    const pointId = item.pointId
+
+    console.log('处理项目:', { groupId, pointId, item })
+
+    // 查分组名
+    const groupInfo = allGroups.value.find((g) => String(g.id) === groupId)
+    const groupName = groupInfo?.groupName
+
+    console.log('找到的分组信息:', groupInfo, '分组名:', groupName)
+
+    // 查点位详情
+    const pointInfo = allPoints.value.find((p) => p.id == pointId)
+    const pointName = pointInfo?.pointName
+    const pointIcon = pointInfo?.pointIcon
+
+    console.log('找到的点位信息:', pointInfo, '点位名:', pointName)
+
+    if (!groupsMap.has(groupId)) {
+      groupsMap.set(groupId, {
+        groupId,
+        groupName,
+        points: []
+      })
+    }
+
+    const group = groupsMap.get(groupId)!
+
+    // 检查是否重复
+    const isDuplicate = group.points.some((p) => p.pointId === pointId)
+    console.log('是否重复:', isDuplicate, '当前组内点位:', group.points)
+
+    // 防止重复添加
+    if (!isDuplicate) {
+      group.points.push({
+        pointId,
+        pointName,
+        pointIcon
+      })
+      console.log('添加点位后:', group.points)
+    }
+  })
+
+  const result = Array.from(groupsMap.values())
+  console.log('最终结果:', result)
+  return result
+})
+
+// 从 JobForm.sopUserList 中提取锁定人并按 groupId 分组
+const groupedLockers = computed(() => {
+  const lockerUsers =
+    JobForm.ticketUserList?.filter((u) => u.userRole === 'jtlocker' && u.groupId != null) || []
+  const groupMap = new Map()
+
+  lockerUsers.forEach((user) => {
+    if (!groupMap.has(user.groupId)) {
+      const groupName =
+        groupList.value.find((g) => g.id === user.groupId)?.groupName || '未命名分组'
+      groupMap.set(user.groupId, { groupId: user.groupId, groupName, users: [] })
+    }
+    groupMap.get(user.groupId).users.push(user)
+  })
+
+  return Array.from(groupMap.values())
+})
+
+// 提取共锁人
+const coLockUsers = computed(() => {
+  return JobForm.ticketUserList?.filter((u) => u.userRole === 'jtcolocker') || []
+})
+</script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
 .basicInformation {
 .basicInformation {
@@ -158,7 +562,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
   border-radius: 4px;
   border-radius: 4px;
   margin-top: 20px;
   margin-top: 20px;
 
 
-  .basicContent{
+  .basicContent {
     width: 100%;
     width: 100%;
     height: 100%;
     height: 100%;
     overflow-y: auto;
     overflow-y: auto;
@@ -167,13 +571,13 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
     padding: 10px 20px;
     padding: 10px 20px;
     box-sizing: border-box;
     box-sizing: border-box;
     //background: pink;
     //background: pink;
-    p{
+    p {
       display: block;
       display: block;
       min-width: 32%;
       min-width: 32%;
       min-height: 25px;
       min-height: 25px;
       margin: 8px 5px;
       margin: 8px 5px;
       //background: green;
       //background: green;
-      .specialText{
+      .specialText {
         color: #42bafa;
         color: #42bafa;
       }
       }
     }
     }
@@ -187,7 +591,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
   border-radius: 4px 4px 0 0;
   border-radius: 4px 4px 0 0;
   display: flex;
   display: flex;
   align-items: center; /* 垂直居中 */
   align-items: center; /* 垂直居中 */
-  .titleimg{
+  .titleimg {
     width: 25px;
     width: 25px;
     height: 25px;
     height: 25px;
     margin-right: 8px;
     margin-right: 8px;
@@ -198,7 +602,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
     color: #303133;
     color: #303133;
   }
   }
 }
 }
-.processDetail{
+.processDetail {
   width: 100%;
   width: 100%;
   height: 300px;
   height: 300px;
   overflow-y: auto;
   overflow-y: auto;
@@ -226,26 +630,315 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
   align-items: center;
   align-items: center;
   justify-content: space-between;
   justify-content: space-between;
 }
 }
-.jobExecution{
+.jobExecution {
   width: 100%;
   width: 100%;
   height: 600px;
   height: 600px;
   //background: blue;
   //background: blue;
-  .tab-label{
+  .tab-label {
     padding: 12px 20px;
     padding: 12px 20px;
     border-radius: 4px 4px 0 0;
     border-radius: 4px 4px 0 0;
     display: flex;
     display: flex;
     align-items: center; /* 垂直居中 */
     align-items: center; /* 垂直居中 */
-    .titleimg{
+    .titleimg {
       width: 25px;
       width: 25px;
       height: 25px;
       height: 25px;
       margin-right: 8px;
       margin-right: 8px;
     }
     }
-    .tab-text  {
+    .tab-text {
       font-size: 14px;
       font-size: 14px;
       font-weight: 500;
       font-weight: 500;
       color: #303133;
       color: #303133;
     }
     }
   }
   }
+
+  .jobMemberBox {
+    width: 100%;
+    min-height: 300px;
+    display: flex;
+    flex-wrap: wrap;
+  }
+  .left_box {
+    width: 500px;
+    margin-right: 10px;
+    display: flex;
+    flex-direction: column;
+
+    img {
+      width: 80px;
+      height: 80px;
+    }
+  }
+
+  .right_box {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+
+    img {
+      width: 80px;
+      height: 80px;
+    }
+  }
+  //作业流程
+  .custom-node {
+    position: relative;
+    width: 125px;
+    height: 180px;
+    background-color: #fff;
+    border-radius: 12px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-between;
+    padding: 10px;
+    box-sizing: border-box;
+  }
+
+  .node-content {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  //连接点样式
+
+  .handle {
+    width: 12px;
+    height: 12px;
+    background-color: #1a192b;
+    border: 2px solid #fff;
+    border-radius: 50%;
+    cursor: crosshair;
+    position: absolute;
+    z-index: 10;
+  }
+
+  .handle:hover {
+    background-color: #555;
+    transform: scale(1.2);
+  }
+
+  .handle-top {
+    top: -8px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+
+  .handle-bottom {
+    bottom: -8px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+
+  .handle-left {
+    left: -8px;
+    top: 50%;
+    transform: translateY(-50%);
+  }
+
+  .handle-right {
+    right: -8px;
+    top: 50%;
+    transform: translateY(-50%);
+  }
+
+  //连接点全局样式
+  :deep(.vue-flow__handle) {
+    width: 12px;
+    height: 12px;
+    background-color: #1a192b;
+    border: 2px solid #fff;
+    border-radius: 50%;
+    cursor: crosshair;
+  }
+
+  :deep(.vue-flow__handle:hover) {
+    background-color: #555;
+    transform: scale(1.2);
+  }
+
+  //连接线样式
+  :deep(.vue-flow__edge-path) {
+    stroke: #333;
+    stroke-width: 2;
+  }
+
+  :deep(.vue-flow__edge) {
+    z-index: 1;
+  }
+
+  // 箭头样式
+  :deep(.vue-flow__edge-marker) {
+    fill: #333;
+  }
+
+  .group-container {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px; /* 卡片之间的间距 */
+  }
+
+  .point-group {
+    border: 1px solid #ccc;
+    border-radius: 8px;
+    padding: 12px;
+    min-width: 250px;
+    background-color: #fafafa;
+    height: 250px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
+  }
+
+  .group-title {
+    font-weight: 600;
+    font-size: 16px;
+    margin-bottom: 12px;
+    padding-bottom: 6px;
+    border-bottom: 1px solid #e0e0e0;
+    color: #333;
+  }
+
+  .points-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px;
+  }
+
+  .point-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    width: 60px;
+  }
+
+  .point-icon {
+    width: 40px;
+    height: 40px;
+    object-fit: contain;
+  }
+
+  .point-name {
+    font-size: 12px;
+    text-align: center;
+    margin-top: 4px;
+    color: #555;
+  }
+
+  //用户的卡片
+  .group-container-user {
+    display: flex;
+    flex-direction: row;
+    gap: 16px;
+    overflow-x: auto;
+    padding-bottom: 10px;
+  }
+
+  .group-card-user {
+    width: 180px;
+    min-height: 150px;
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
+    padding: 12px;
+    flex-shrink: 0;
+    border: 1px solid #eee;
+    display: flex;
+    flex-direction: column;
+    margin-top: 10px;
+  }
+
+  .group-title {
+    font-weight: bold;
+    font-size: 16px;
+    margin-bottom: 10px;
+    color: #333;
+    text-align: center;
+    border-bottom: 1px solid #f0f0f0;
+    padding-bottom: 6px;
+  }
+
+  .user-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+    justify-content: center;
+  }
+
+  .user-list-colocker {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+    justify-content: flex-start;
+    margin-top: 10px;
+  }
+
+  .user-card {
+    width: 60px;
+    text-align: center;
+
+    img {
+      width: 40px;
+      height: 40px;
+      border-radius: 4px;
+      border: 1px solid #ccc;
+    }
+
+    .user-name {
+      font-size: 12px;
+      margin-top: 4px;
+      color: #555;
+      word-break: break-all;
+    }
+  }
+  //点位数据
+  .group-box{
+    margin: 0 20px;
+  }
+
+  //人员共锁
+  .biglockBox{
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    //background: green;
+    .mumberbox{
+      width: 28%;
+      height: 100%;
+      margin: 0 15px;
+      .user{
+        width: 100%;
+        height: 500px;
+        overflow-y: auto;
+        overflow-x: hidden;
+        display: flex;
+        flex-wrap: wrap;
+        padding:2px 5px;
+        box-sizing: border-box;
+        //background: pink;
+        .userItem{
+          width: 20%;
+          height: 80px;
+          padding: 2px 13px;
+          //background: #000;
+          box-sizing: border-box;
+        img{
+          width: 50px;
+          height:50px;
+        }
+          p{
+            font-size: 16px;
+          }
+        }
+      }
+    }
+    .arrow{
+     margin-top: 15%;
+    }
+  }
+
   /* 小屏幕下隐藏文字,只显示图标 */
   /* 小屏幕下隐藏文字,只显示图标 */
   @media (max-width: 768px) {
   @media (max-width: 768px) {
     .tab-label {
     .tab-label {
@@ -267,8 +960,9 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
       }
       }
     }
     }
   }
   }
+  .group-card-user {
+    width: 160px;
+    min-height: 130px;
+  }
 }
 }
-
-
-
 </style>
 </style>

+ 1 - 0
src/views/jobTicket/job/ModeView/TableView.vue

@@ -121,6 +121,7 @@
           </template>
           </template>
         </el-table-column>
         </el-table-column>
       </el-table>
       </el-table>
+
     </div>
     </div>
 
 
     <!-- 步骤功能弹框 -->
     <!-- 步骤功能弹框 -->