Преглед на файлове

作业执行监控页面基础数据部分内容根据接口返回内容更新数据;作业 执行流程颜色样式渲染实现;点位锁定接口更新;人员共锁接口更新,作业日志页面绘制

wyn преди 3 месеца
родител
ревизия
1a18e13136

BIN
src/assets/images/icon_co-lock.png


BIN
src/assets/images/icon_job_log.png


BIN
src/assets/images/icon_job_members.png


BIN
src/assets/images/icon_red_lock.png


BIN
src/assets/images/information.png


BIN
src/assets/images/jobProcess.png


+ 14 - 0
src/router/modules/remaining.ts

@@ -389,6 +389,20 @@ const remainingRouter: AppRouteRecordRaw[] = [
           activeMenu: '/jobTicket/job/ModeView/TableStepDetail'
         }
       },
+      {
+        path: 'jobTicket/job/JobMonitor',
+        component: () => import('@/views/jobTicket/job/JobMonitor.vue'),
+        name: 'JobMonitor',
+        meta: {
+          title:'作业执行监控',
+          noTagsView: true,
+          noCache: true,
+          hidden: true,
+          canTo: true,
+          icon: 'ep:view',
+          activeMenu: '/jobTicket/job'
+        }
+      },
 
     ]
   },

+ 2 - 0
src/utils/dict.ts

@@ -254,6 +254,7 @@ export enum DICT_TYPE {
   SOP_TYPE = 'sop_type',
   TICKET_STATUS = 'ticket_status',
   TICKET_TYPE = 'ticket_type',
+  JOB_LOG_TYPE = 'job_log_type',
   HARDWARE_STATUS = 'hardware_status',
   IS_USER_TYPE = 'is_user_type',
   LOCK_TYPE = 'lock_type',
@@ -280,6 +281,7 @@ export enum DICT_TYPE {
   INVENTORY_TYPE = 'Inventory_type',
   MEASURE = 'measure',
   MAP_TYPE = 'map_type',
+  POINT_STATUS='point_status',
   CLASSIFICATION_OF_EXCEPTIONS = 'classification_of_exceptions',
   TYPE_OF_EXCEPTION = 'type_of_exception',
   SEVERITY_LEVEL = 'severity_level',

+ 1 - 1
src/views/jobTicket/job/CreateJob.vue

@@ -2,7 +2,7 @@
   <div>
     <!--    sop表单-->
     <ContentWrap>
-      <el-collapse v-model="activeName" accordion">
+      <el-collapse v-model="activeName" accordion>
         <el-collapse-item name="1">
           <template #title>
             <div style="display: flex; align-items: center; gap: 8px">

+ 388 - 97
src/views/jobTicket/job/JobMonitor.vue

@@ -17,7 +17,7 @@
         <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 class="specialText">{{ currentStepTitle }}</span> </p>
         <p>最新日志: <span>待更新</span> </p>
       </div>
     </div>
@@ -30,11 +30,11 @@
           >作业流程</span
         >
       </div>
-      <div class="processDetail">
+      <div class="processDetail" ref="scrollContainer">
         <!-- VueFlow 主画布 -->
-        <VueFlow style="width: 100%; height: 300px" :min-zoom="1" :max-zoom="1" :default-zoom="1">
+        <VueFlow style="width: 100%; height: 300px" :min-zoom="1" :max-zoom="1" :default-zoom="1" :nodes="nodes" :edges="edges">
           <template #node-default="{ id, data }">
-            <div class="custom-node">
+            <div class="custom-node" :id="id">
               <div class="node-content">
                 <!-- 图标显示 -->
                 <div style="font-size: 30px">
@@ -75,7 +75,7 @@
     </div>
   </ContentWrap>
   <!--作业执行-->
-  <ContentWrap>
+  <ContentWrap style="overflow: auto">
     <div class="jobExecution">
       <el-tabs v-model="activeName" type="card" class="demo-tabs" @tab-click="handleClick">
         <!-- 作业人员-->
@@ -135,21 +135,22 @@
               :key="group.id"
             >
               <div class="tab-header">
-                <p class="tab-title">{{ group.groupName }}</p>
+                <p class="tab-title">{{ group.groupName }}(待锁定:{{group.
+                  waitLock}} 已锁定:{{group.locked}} 已解锁:{{group.unlocked}})</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-button value="fixed">常规</el-radio-button>
+                  <el-radio-button value="auto">扩展</el-radio-button>
                 </el-radio-group>
                 <el-table
-                  :data="getPointsByGroupId(group.id)"
+                  :data="group.ticketPointsRespVOList"
                   :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="pointName" label="隔离点" />
+                  <el-table-column prop="ability" label="作用" />
+                  <el-table-column prop="lockUserName" label="锁定人" />
                   <el-table-column prop="pointStatus" label="锁定状态" >
                     <template #default="scope">
                       <dict-tag
@@ -165,7 +166,7 @@
           </div>
         </el-tab-pane>
         <!-- 人员共锁 -->
-        <el-tab-pane name="third">
+        <el-tab-pane name="third" v-if="isShowclocker">
           <template #label>
             <div class="tab-label">
               <img src="@/assets/images/icon_co-lock.png" alt="" class="titleimg" />
@@ -176,12 +177,12 @@
             <!-- 待共锁-->
             <div class="mumberbox">
               <div class="tab-header">
-                <span class="tab-title">待共锁(5)</span>
+                <span class="tab-title">待共锁({{ waitLockUsers.length }})</span>
               </div>
               <div class="user">
-                <div class="userItem" >
+                <div class="userItem" v-for="user in waitLockUsers" :key="user.userId" >
                   <img src="@/assets/images/icon_co-lock.png" alt=""/>
-                  <p>哇哈哈</p>
+                  <p>{{ user.userName }}</p>
                 </div>
               </div>
             </div>
@@ -191,34 +192,28 @@
             <!-- 已共锁-->
             <div class="mumberbox">
               <div class="tab-header">
-                <span class="tab-title">已共锁(5)</span>
+                <span class="tab-title">已共锁({{ lockedUsers.length }})</span>
               </div>
               <div class="user">
-                <div class="userItem" >
+                <div class="userItem" v-for="user in lockedUsers" :key="user.userId">
                   <img src="@/assets/images/icon_co-lock.png" alt=""/>
-                  <p>哇哈哈</p>
+                  <p>{{ user.userName }}</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">未共锁(0)</span>
+                <span class="tab-title">已解除共锁({{ unlockPendingUsers.length }})</span>
               </div>
               <div class="user">
-                <div class="userItem" >
-                  <img src="@/assets/images/icon_co-lock.png" alt=""/>
-                  <p>哇哈哈</p>
-                </div>
-                <div class="userItem" >
+                <div class="userItem" v-for="user in unlockPendingUsers" :key="user.userId">
                   <img src="@/assets/images/icon_co-lock.png" alt=""/>
-                  <p>哇哈哈</p>
+                  <p>{{ user.userName }} </p>
                 </div>
-
-
               </div>
             </div>
           </div>
@@ -231,16 +226,68 @@
               <span class="tab-text">作业日志</span>
             </div>
           </template>
-          Task
+          <div class="joblogCon">
+            <!--顶部日志内容-->
+            <div class="joblogTop">
+              <p v-for="(item, index) in filteredJoblogList" :key="index">
+                <span v-html="renderLogContent(item.operationContent)"></span>
+              </p>
+            </div>
+            <!-- 底部过滤条件-->
+            <div class="bottomCheck">
+              <el-checkbox
+                :indeterminate="isIndeterminate"
+                :checked="checkAlljoblog"
+                @change="handleCheckAllChange"
+                style="margin:3px 25px;font-size: 16px"
+
+              >
+                全部
+              </el-checkbox>
+
+              <!-- 多选项 -->
+              <el-checkbox-group
+                v-model="checkedJoblogs"
+                @change="handleCheckedJoblogsChange"
+                class="big-checkbox"
+              >
+                <el-checkbox
+                  v-for="item in jobLogtypes"
+                  :label="item.value"
+                  :key="item.value"
+                  class="big-checkbox"
+                >
+                  {{ item.label }}
+                </el-checkbox>
+              </el-checkbox-group>
+            </div>
+          </div>
         </el-tab-pane>
       </el-tabs>
     </div>
   </ContentWrap>
+<!--  作业日志弹框-->
+  <el-dialog
+    v-model="joblogDialogVisible"
+    title="Warning"
+    width="500"
+    align-center
+  >
+    <span>Open the dialog from the center from the screen</span>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="joblogDialogVisible = false">Cancel</el-button>
+        <el-button type="primary" @click="joblogDialogVisible = false">
+          Confirm
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
 </template>
 
 <script setup lang="ts">
+import { ref, nextTick, onMounted, onBeforeUnmount } from 'vue'
 import { Handle, useVueFlow, VueFlow } from '@vue-flow/core'
-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'
@@ -282,11 +329,34 @@ const activeName = ref('first')
 const route = useRoute()
 const jobTypeOptions = ref([])
 const jobStatusOptions = ref([])
+const currentStepTitle = ref('') // 当前步骤名称
+
 // 表格数据
 const jobGroupList=ref([]) //获取作业分组信息
 const ticketPointsList = ref([]) // 隔离点数据
 const tableLayouts = ref([]) // 每组表格的布局
 
+// 人员共锁
+const jobclockerList = ref([])
+const isShowclocker=ref(true)  //是否展示人员共锁
+const waitLockUsers = ref([])
+const lockedUsers = ref([])
+const unlockPendingUsers = ref([])
+
+// 作业日志
+const joblogList = ref([])//原始作业日志数据列表
+const filteredJoblogList = ref([]) // 过滤后日志
+//   作业日志底部查询
+const isIndeterminate= ref(false)
+const checkedJoblogs = ref([])
+const jobLogtypes= ref([])
+const joblogsOptions= ref([]) // 只存所有 dictValue,用于全选逻辑,
+const checkAlljoblog =ref(true)
+const JoblogdialogVisible =ref(false)
+const dialogLog= ref('')
+const isJoblogVisible= ref(false)
+const joblogDialogVisible= ref(false)
+
 
 // 初始化
 onMounted(async () => {
@@ -295,9 +365,15 @@ onMounted(async () => {
   jobStatusOptions.value = await getIntDictOptions(DICT_TYPE.TICKET_STATUS)
   await fetchAllGroupsAndPoints() //获取所有分组和点位 来渲染SOP的首页
   await onModeContent()
+  window.addEventListener('resize', onResize)
+  await onResize()
+})
+onBeforeUnmount(() => {
+  window.removeEventListener('resize', onResize)
 })
 console.log(route.query.id, '是否传递成功')
 
+// 基础信息
 const ticketTypeLabel = computed(() => {
   const match = jobTypeOptions.value.find(item => item.value == JobForm.ticketType)
   return match ? match.label : JobForm.ticketType
@@ -308,39 +384,60 @@ const ticketStatusLabel = computed(() => {
   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
+  ticketPointsList.value = JobForm.ticketGroupList.ticketPointsRespVOList
   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)
+//   人员共锁
+  jobclockerList.value = JobForm.ticketUserList
+  // 判断是否存在共锁人
+  isShowclocker.value = jobclockerList.value.some(item => item.userRole === 'jtcolocker')
+  updateUserGroups() // 分类数据
 }
 
 
+// 作业流程绘制
+const scrollContainer = ref(null)
 
+const scrollToCurrentNode = () => {
+  nextTick(() => {
+    if (!scrollContainer.value) return
+
+    const firstZeroIndex = nodes.value.findIndex(n => n.data.stepStatus === 0)
+    if (firstZeroIndex === -1) return
+
+    const currentNodeId = nodes.value[firstZeroIndex].id
+    const currentNodeEl = document.getElementById(currentNodeId)
+    if (!currentNodeEl) return
+
+    // 计算滚动,让当前节点居中
+    const container = scrollContainer.value
+    const containerRect = container.getBoundingClientRect()
+    const nodeRect = currentNodeEl.getBoundingClientRect()
+
+    const offset = nodeRect.left - containerRect.left - (containerRect.width / 2) + (nodeRect.width / 2)
+
+    container.scrollBy({
+      left: offset,
+      behavior: 'smooth'
+    })
+  })
+}
+
+const onResize = () => {
+  if (window.innerWidth <= 600) {
+    scrollToCurrentNode()
+  }
+}
 
-// 作业流程绘制
 const nodes = ref([]) //储存节点
 const edges = ref([]) // 存储连接线
 const { addNodes, addEdges, setEdges, setNodes } = useVueFlow()
@@ -363,27 +460,41 @@ const clearCanvasProperly = async () => {
 }
 // 初始化数据渲染节点 - 修正版本
 const renderNodesFromData = (data) => {
-  // 清空现有节点
   nodes.value = []
 
+  const firstZeroIndex = data.findIndex(item => item.stepStatus === 0)
+  if (firstZeroIndex !== -1) {
+    currentStepTitle.value = data[firstZeroIndex].stepTitleShort || '无标题'
+  } else {
+    currentStepTitle.value = ''
+  }
+
   data.forEach((item, index) => {
+    let backgroundColor = '#fff'
+    let isCurrent = false
+    if (item.stepStatus === 1) {
+      backgroundColor = '#a0e99b'
+    } else if (item.stepStatus === 0 && index === firstZeroIndex) {
+      backgroundColor = '#ffe58f'
+      isCurrent = true
+    }
+
     const nodeId = `node-${item.id || Date.now() + index}`
 
-    const newNode = {
+    nodes.value.push({
       id: nodeId,
-      position: {
-        x: 100 + index * 200,
-        y: 100
-      },
+      position: { x: 100 + index * 200, y: 100 },
       width: 100,
       height: 150,
       data: {
+        ...item,
         stepIcon: item.stepIcon,
         stepTitleShort: item.stepTitleShort,
-        stepIndex: item.stepIndex || index + 1, // 使用 stepIndex
-        index: item.stepIndex || index + 1, // 保持兼容性
-        // 保存完整的数据用于表单编辑
-        stepData: item
+        stepIndex: item.stepIndex || index + 1,
+        index: item.stepIndex || index + 1,
+        stepData: item,
+        bgColor: backgroundColor,
+        isCurrent
       },
       style: {
         width: '130px',
@@ -396,16 +507,71 @@ const renderNodesFromData = (data) => {
         alignItems: 'center',
         justifyContent: 'space-between',
         padding: '10px',
-        backgroundColor: '#fff'
+        backgroundColor
       },
-      draggable: true
-    }
-
-    addNodes(newNode)
-    nodes.value.push(newNode)
+      draggable: false //设置是否可以拖动生成的图
+    })
   })
 }
 
+// const renderNodesFromData = (data) => {
+//   nodes.value = []
+//
+//   const firstZeroIndex = data.findIndex(item => item.stepStatus === 0)
+//
+//   // 设置当前步骤标题
+//   if (firstZeroIndex !== -1) {
+//     currentStepTitle.value = data[firstZeroIndex].stepTitleShort
+//   } else {
+//     currentStepTitle.value = '' // 或者显示“全部完成”之类的
+//   }
+//
+//   data.forEach((item, index) => {
+//     const nodeId = `node-${item.id || Date.now() + index}`
+//
+//     let backgroundColor = '#fff'
+//     if (item.stepStatus === 1) {
+//       backgroundColor = '#a0e99b'
+//     } else if (item.stepStatus === 0 && index === firstZeroIndex) {
+//       backgroundColor = '#ffe58f'
+//     }
+//
+//     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,
+//         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
+//       },
+//       draggable: true
+//     }
+//
+//     addNodes(newNode)
+//     nodes.value.push(newNode)
+//   })
+// }
+
 // 渲染连接线 - 新增函数
 const renderEdgesFromData = (data) => {
   // 清空现有连接线
@@ -443,8 +609,30 @@ const renderEdgesFromData = (data) => {
   }
 }
 
-const handleClick = (tab: TabsPaneContext, event: Event) => {
+// 底部tabbar点击事件
+const handleClick = async (tab: TabsPaneContext, event: Event) => {
   console.log(tab, event)
+  // console.log(activeName.value,'名称')
+  console.log(tab.paneName, '当前点击的 tab 名称')
+
+  if(tab.paneName === 'fourth') {
+    console.log('作业日志')
+    const dictRes= await getIntDictOptions(DICT_TYPE.JOB_LOG_TYPE)
+    console.log(dictRes,'接口调用是否成功')
+    const dicts = dictRes.map(item => ({
+      label: item.label,
+      value: String(item.value), // 确保是字符串类型
+    }));
+
+    jobLogtypes.value = dicts;
+    joblogsOptions.value = dicts.map(item => item.value);
+    checkedJoblogs.value = [...joblogsOptions.value]; // 初始化全选
+    console.log(checkAlljoblog.value,'选中状态');
+    checkAlljoblog.value = true;
+    console.log(checkAlljoblog.value,'是否选中');
+    isIndeterminate.value = false;
+    filterJoblogs();
+  }
 }
 
 //ticketType改变函数
@@ -532,6 +720,11 @@ const resolvedGroupedPoints = computed(() => {
   return result
 })
 
+
+// 获取某个分组下的隔离点
+// const getPointsByGroupId = (groupId) => {
+//   return ticketPointsList.value.filter((point) => point.groupId === groupId)
+// }
 // 从 JobForm.sopUserList 中提取锁定人并按 groupId 分组
 const groupedLockers = computed(() => {
   const lockerUsers =
@@ -554,6 +747,59 @@ const groupedLockers = computed(() => {
 const coLockUsers = computed(() => {
   return JobForm.ticketUserList?.filter((u) => u.userRole === 'jtcolocker') || []
 })
+
+
+// 人员共锁
+const updateUserGroups = () => {
+  const allUsers = jobclockerList.value
+  console.log(allUsers,jobclockerList.value,'数据拿到了吗')
+
+  waitLockUsers.value = jobclockerList.value.filter(u => u.userRole == 'jtcolocker' && u.jobStatus == 0)
+  console.log(waitLockUsers.value,'待共锁')
+  lockedUsers.value = allUsers.filter(u => u.userRole === 'jtcolocker' && u.jobStatus == 1)
+  unlockPendingUsers.value = allUsers.filter(u => u.userRole === 'jtcolocker' && u.jobStatus == 2)
+}
+
+
+
+// 作用日志
+// 作业日志页面数据展示样式分割
+const renderLogContent=(content)=> {
+  if (!content) return ''
+  // 第一步:先处理 <url>[label] 为 <img> + label
+  content = content.replace(/<([^>]+)>\[([^\]]+)\]/g, (match, url, label) => {
+    return `<img src="${url}" style="height: 25px; vertical-align: middle;"> <span style="color:#007BFF;margin: 0 3px">${label}</span>`
+  })
+  // 第二步:处理剩下的 [label],转成蓝色字体
+  content = content.replace(/\[([^\]]+)\]/g, '<span style="color:#007BFF;margin: 0 5px">$1</span>')
+  return content
+}
+
+//   作业日志底部筛选功能
+const handleCheckedJoblogsChange=(val)=> {
+  const checkedCount = val.length;
+  checkAlljoblog.value = checkedCount === joblogsOptions.value.length;
+  isIndeterminate.value = checkedCount > 0 && checkedCount < joblogsOptions.value.length;
+
+ filterJoblogs();
+}
+const handleCheckAllChange=(val)=> {
+  checkedJoblogs.value = val ? [...joblogsOptions.value] : [];
+  isIndeterminate.value = false;
+  filterJoblogs();
+}
+
+// 实际日志筛选逻辑
+const filterJoblogs = () => {
+  if (checkedJoblogs.value.includes('ALL')) {
+    filteredJoblogList.value = joblogList.value;
+  } else {
+    filteredJoblogList.value = joblogList.value.filter(log =>
+      checkedJoblogs.value.includes(String(log.operationType))
+    );
+  }
+}
+
 </script>
 
 <style scoped lang="scss">
@@ -605,31 +851,10 @@ const coLockUsers = computed(() => {
 .processDetail {
   width: 100%;
   height: 300px;
-  overflow-y: auto;
+  overflow-x: auto;
   //background: green;
 }
-.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;
-}
 .jobExecution {
   width: 100%;
   height: 600px;
@@ -656,6 +881,7 @@ const coLockUsers = computed(() => {
     min-height: 300px;
     display: flex;
     flex-wrap: wrap;
+    //background: #000;
   }
   .left_box {
     width: 500px;
@@ -684,7 +910,7 @@ const coLockUsers = computed(() => {
     position: relative;
     width: 125px;
     height: 180px;
-    background-color: #fff;
+    //background-color: #fff;
     border-radius: 12px;
     display: flex;
     flex-direction: column;
@@ -830,6 +1056,7 @@ const coLockUsers = computed(() => {
   .group-container-user {
     display: flex;
     flex-direction: row;
+    flex-wrap: wrap;
     gap: 16px;
     overflow-x: auto;
     padding-bottom: 10px;
@@ -842,7 +1069,7 @@ const coLockUsers = computed(() => {
     border-radius: 8px;
     box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
     padding: 12px;
-    flex-shrink: 0;
+    //flex-shrink: 0;
     border: 1px solid #eee;
     display: flex;
     flex-direction: column;
@@ -910,7 +1137,7 @@ const coLockUsers = computed(() => {
       margin: 0 15px;
       .user{
         width: 100%;
-        height: 500px;
+        max-height: 500px;
         overflow-y: auto;
         overflow-x: hidden;
         display: flex;
@@ -921,16 +1148,24 @@ const coLockUsers = computed(() => {
         .userItem{
           width: 20%;
           height: 80px;
-          padding: 2px 13px;
+          padding: 2px 3px;
+          margin: 10px;
+          text-align: center;
           //background: #000;
           box-sizing: border-box;
         img{
           width: 50px;
           height:50px;
         }
-          p{
+          p {
             font-size: 16px;
+            display: -webkit-box;
+            -webkit-line-clamp: 1;      /* 最多显示1行 */
+            -webkit-box-orient: vertical;
+            overflow: hidden;
+            text-overflow: ellipsis;
           }
+
         }
       }
     }
@@ -938,7 +1173,41 @@ const coLockUsers = computed(() => {
      margin-top: 15%;
     }
   }
+  //作业日志
+  .joblogCon{
+    width: 98%;
+    height: 75%;
+    margin: auto;
+    //background: greenyellow;
+    .joblogTop{
+      width: 100%;
+      height: 490px;
+      margin: auto;
+      overflow-y: auto;
+      //background: cadetblue;
+      p{
+        font-size: 16px;
+        line-height: 20px;
+      }
+    }
+    .bottomCheck{
+      width:100%;
+      height: 50px;
+      line-height: 50px;
+      font-size: 23px;
+      display: flex;
+      padding: 5px 0;
+      margin: auto;
+      //background: forestgreen;
+
+      .big-checkbox {
+        font-size: 23px; /* 字体大小 */
+      }
+
+    }
+
 
+  }
   /* 小屏幕下隐藏文字,只显示图标 */
   @media (max-width: 768px) {
     .tab-label {
@@ -959,10 +1228,32 @@ const coLockUsers = computed(() => {
         display: none;
       }
     }
+    .group-card-user {
+      width: 160px;
+      min-height: 130px;
+
+    }
+    //点位数据
+    .group-box{
+      margin: 10px 5px;
+    }
+  //  人员共锁
+    .biglockBox {
+      overflow-y: auto;
+      flex-direction: column;
+      align-items: center;
+      //background: #bf2020;
+      .mumberbox {
+        width: 95%;
+        margin: 15px 0;
+      }
+      .arrow {
+        transform: rotate(90deg); // 向右 → 向下
+        margin-top: 10px;
+        margin-bottom: 10px;
+      }
+    }
   }
-  .group-card-user {
-    width: 160px;
-    min-height: 130px;
-  }
+
 }
 </style>

+ 2 - 0
src/views/jobTicket/job/UpdateJob.vue

@@ -1091,6 +1091,7 @@ const goBack=()=>{
   margin-right: 10px;
   display: flex;
   flex-direction: column;
+  flex-wrap: wrap;
 
   img {
     width: 80px;
@@ -1267,6 +1268,7 @@ const goBack=()=>{
 .group-container-user {
   display: flex;
   flex-direction: row;
+  //flex-wrap: wrap;
   gap: 16px;
   overflow-x: auto;
   padding-bottom: 10px;