NewMarsJob.vue 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  1. <template>
  2. <div>
  3. <el-radio-group v-model="tabPosition" style="margin: 5px">
  4. <el-radio-button label="first">选择岗位</el-radio-button>
  5. <el-radio-button label="second">选择SOP</el-radio-button>
  6. <el-radio-button label="third">作业详情</el-radio-button>
  7. </el-radio-group>
  8. <div
  9. style="
  10. display: flex;
  11. justify-content: center;
  12. align-items: center;
  13. position: relative;
  14. "
  15. v-show="tabPosition == 'first'"
  16. >
  17. <!-- 缩放容器 -->
  18. <div
  19. ref="mapContainer"
  20. :style="{
  21. transform: `scale(${scaleFactor})`,
  22. transformOrigin: 'top left',
  23. width: '1250px',
  24. height: '700px',
  25. position: 'relative',
  26. }"
  27. >
  28. <img
  29. style="width: 100%; height: 100%"
  30. src="@/assets/images/marsBg.png"
  31. alt=""
  32. />
  33. <img
  34. v-for="(ticket, index) in TicketListPage"
  35. :key="ticket.ticketId"
  36. :style="{
  37. width: '35px',
  38. cursor: 'pointer',
  39. height: '35px',
  40. position: 'absolute',
  41. top: '220px',
  42. left: `${481 + 40 * index}px`,
  43. }"
  44. :src="require('@/assets/images/marsPoint.png')"
  45. alt=""
  46. @click="handleTicketClick(ticket)"
  47. />
  48. <img
  49. v-for="(ticket, index) in COCOTicketListPage"
  50. :key="ticket.ticketId"
  51. :style="{
  52. width: '35px',
  53. cursor: 'pointer',
  54. height: '35px',
  55. position: 'absolute',
  56. top: '440px',
  57. left: `${650 + 40 * index}px`,
  58. }"
  59. :src="require('@/assets/images/marsPoint.png')"
  60. alt=""
  61. @click="handleTicketClick(ticket)"
  62. />
  63. <div class="deptXLG" @click="handelChange('second', 8, 'R&R')">R&R</div>
  64. <div class="deptCCO" @click="handelChange('second', 7, 'CCO')">CCO</div>
  65. </div>
  66. </div>
  67. <div
  68. style="
  69. display: flex;
  70. flex-direction: column;
  71. justify-content: flex-start;
  72. align-items: flex-start;
  73. position: relative;
  74. "
  75. v-show="tabPosition == 'second'"
  76. >
  77. <h3 style="margin-left: 20px">{{ this.marsSopTitle }} SOP</h3>
  78. <span style="margin-left: 20px">选择 工艺/设备</span>
  79. <el-table
  80. style="width: 50%; margin: 20px"
  81. :header-cell-style="{ background: '#004d8c', color: '#FFFFFF' }"
  82. :data="marsSopPage"
  83. @selection-change="handleSelectionChange"
  84. >
  85. <el-table-column type="selection" width="55" align="center"/>
  86. <el-table-column
  87. label="设备/工艺名称"
  88. align="center"
  89. prop="machineryName"
  90. ></el-table-column>
  91. <el-table-column
  92. label="所属岗位"
  93. align="center"
  94. prop="workstationName"
  95. ></el-table-column>
  96. </el-table>
  97. <h2 style="margin-left: 20px">sop类型</h2>
  98. <el-radio-group
  99. v-model="selectedOption"
  100. size="small"
  101. style="display: flex; flex-direction: column; align-items: flex-start"
  102. >
  103. <el-radio
  104. v-for="(option, index) in filteredSopTypes"
  105. :key="index"
  106. :label="option"
  107. border
  108. style="margin: 10px"
  109. >
  110. {{ option.label }}
  111. </el-radio>
  112. </el-radio-group>
  113. <el-button
  114. type="primary"
  115. style="margin-left: 140px"
  116. @click="handelChange('third')"
  117. >开始执行
  118. </el-button
  119. >
  120. </div>
  121. <div
  122. style="position: relative; display: flex"
  123. v-show="tabPosition == 'third'"
  124. >
  125. <div
  126. class="left"
  127. style="width: 35%; display: flex; flex-direction: column"
  128. >
  129. <div class="left-top">
  130. <el-card class="box-card" style="margin: 10px">
  131. <div slot="header" class="clearfix">
  132. <span>工艺/设备 工艺图</span>
  133. </div>
  134. <img style="margin-left: 25%" :src="this.machineryImg" alt=""/>
  135. </el-card>
  136. </div>
  137. <div class="left-bottom">
  138. <el-card class="box-card" style="margin: 10px">
  139. <div slot="header" class="clearfix">
  140. <span>锁定站信息</span>
  141. </div>
  142. <el-row>
  143. <el-col :span="9">
  144. <el-table :data="selectPointList">
  145. <el-table-column
  146. prop="pointName"
  147. label="隔离点"
  148. ></el-table-column>
  149. <el-table-column
  150. prop="powerTypeName"
  151. label="危险能量类型"
  152. ></el-table-column>
  153. </el-table>
  154. </el-col>
  155. <el-col :span="8">
  156. <MapData
  157. style="width: 300px; height: 320px; margin-left: 15%"
  158. :machineryId="this.machineryId"
  159. ></MapData>
  160. </el-col>
  161. </el-row>
  162. </el-card>
  163. </div>
  164. </div>
  165. <div class="right" style="flex: 1">
  166. <el-card class="box-card" style="margin: 10px; height: 742px">
  167. <div slot="header" class="clearfix">
  168. <span>八大步骤</span>
  169. </div>
  170. <div
  171. style="
  172. width: 100%;
  173. height: 100%;
  174. display: flex;
  175. justify-content: center;
  176. align-items: center;
  177. "
  178. >
  179. <div style="width: 700px; height: 600px">
  180. <div style="width: 100%; height: 100px">
  181. <div>
  182. <!-- :show-header="false"-->
  183. <el-table :data="EightStepForm" style="margin-top: 60px">
  184. <el-table-column label="步骤" prop="stepIndex">
  185. <template slot-scope="scope">
  186. <span>第{{ scope.row.stepIndex }}步</span>
  187. </template>
  188. </el-table-column>
  189. <el-table-column label="步骤" prop="number">
  190. <template slot-scope="scope">
  191. <span v-if="scope.row.lockNum !== null">
  192. <i class="el-icon-goods">{{ scope.row.lockNum }}</i>
  193. </span>
  194. <span v-if="scope.row.userNum !== null">
  195. <i class="el-icon-user">{{ scope.row.userNum }}</i>
  196. </span>
  197. <span v-if="scope.row.conflictJobNum !== null">
  198. <i class="el-icon-s-claim">{{
  199. scope.row.conflictJobNum
  200. }}</i>
  201. </span>
  202. </template>
  203. </el-table-column>
  204. <el-table-column label="状态" prop="stepStatus">
  205. <template slot-scope="scope">
  206. <!-- 判断逻辑 -->
  207. <span
  208. v-if="scope.row.stepIndex == '3' && (scope.row.stepStatus !== '1' || !isStepFourExecuted)"
  209. >
  210. <el-button
  211. type="primary"
  212. plain
  213. size="small"
  214. @click="addInside(scope.row)"
  215. >
  216. 分配
  217. </el-button>
  218. </span>
  219. <span v-if="scope.row.stepIndex == '3' && scope.row.stepStatus === '1' && isStepFourExecuted">
  220. <span
  221. style="
  222. display: inline-block;
  223. width: 8px;
  224. height: 8px;
  225. margin: 1%;
  226. border-radius: 50%;
  227. background: #6aabfb;
  228. "
  229. ></span>
  230. <span>已执行</span>
  231. </span>
  232. <!-- 其他步骤 -->
  233. <span v-if="scope.row.stepIndex != '3' && scope.row.stepStatus !== '1'">
  234. <el-button
  235. type="primary"
  236. plain
  237. size="small"
  238. @click="addInside(scope.row)"
  239. >
  240. 执行
  241. </el-button>
  242. </span>
  243. <span v-if="scope.row.stepIndex != '3' && scope.row.stepStatus === '1'">
  244. <span
  245. style="
  246. display: inline-block;
  247. width: 8px;
  248. height: 8px;
  249. margin: 1%;
  250. border-radius: 50%;
  251. background: #6aabfb;
  252. "
  253. ></span>
  254. <span>已执行</span>
  255. </span>
  256. </template>
  257. </el-table-column>
  258. <el-table-column
  259. label="内容"
  260. prop="stepContent"
  261. width="300"
  262. ></el-table-column>
  263. <el-table-column label="详情" prop="">
  264. <template slot-scope="scope">
  265. <span
  266. v-if="
  267. scope.row.stepIndex == '5' ||
  268. scope.row.stepIndex == '1' ||
  269. scope.row.stepIndex == '8'
  270. "
  271. >
  272. <el-button
  273. type="text"
  274. size="small"
  275. @click="checkDetail(scope.row)"
  276. >查看</el-button
  277. >
  278. </span>
  279. </template>
  280. </el-table-column>
  281. </el-table>
  282. </div>
  283. </div>
  284. </div>
  285. </div>
  286. <el-button style="float: right" type="primary" @click="finshJobticket"
  287. >结束作业
  288. </el-button
  289. >
  290. <el-button
  291. style="float: right; margin-right: 10px"
  292. type="danger"
  293. @click="cancelJobticket"
  294. >取消作业
  295. </el-button
  296. >
  297. </el-card>
  298. </div>
  299. </div>
  300. <!-- 添加或修改外部人员对话框 -->
  301. <el-dialog :visible.sync="open" width="1400px" append-to-body>
  302. <div slot="title" class="dialog-title">
  303. <i></i>
  304. <span class="title">添加人员</span>
  305. </div>
  306. <el-form ref="dialogForm" :model="dialogForm" label-width="70px">
  307. <el-row>
  308. <el-form-item label="上锁人" prop="locker">
  309. <el-select
  310. v-model="dialogForm.locker"
  311. placeholder="上锁人"
  312. clearable
  313. style="width: 230px"
  314. @change="handlelockerChage"
  315. @clear="handlelockerClear"
  316. >
  317. <el-option
  318. v-for="dict in this.listLockerOption"
  319. :key="dict.value"
  320. :label="dict.label"
  321. :value="dict.value"
  322. />
  323. </el-select>
  324. </el-form-item>
  325. </el-row>
  326. <el-row style="display: flex; justify-content: space-between">
  327. <!-- 内部共锁人-->
  328. <el-col :span="7">
  329. <h3>内部共锁人列表</h3>
  330. <el-table
  331. :data="insideTableData"
  332. stripe
  333. ref="insideTable"
  334. height="400"
  335. @selection-change="InSelectionChange"
  336. :header-cell-style="{
  337. 'background-color': '#afccfd',
  338. color: 'white',
  339. }"
  340. >
  341. <el-table-column type="selection" width="55" align="center" />
  342. <el-table-column prop="userId" label="内部人员Id"></el-table-column>
  343. <el-table-column prop="nickName" label="姓名">
  344. <template slot-scope="scope">
  345. <span style="color: #2a87ff">{{ scope.row.nickName }}</span>
  346. </template>
  347. </el-table-column>
  348. <!-- 添加搜索条件的列 -->
  349. <el-table-column label="搜索">
  350. <template slot="header">
  351. <el-input
  352. placeholder="搜索姓名"
  353. v-model="insideSearchQuery"
  354. size="small"
  355. @input="filterInsideTable"
  356. style="width: 90px;"
  357. />
  358. </template>
  359. </el-table-column>
  360. </el-table>
  361. </el-col>
  362. <el-col :span="7">
  363. <h3>外部共锁人列表</h3>
  364. <el-table
  365. :data="outsideTableData"
  366. stripe
  367. ref="outsideTable"
  368. height="400"
  369. @selection-change="OutSelectionChange"
  370. :header-cell-style="{
  371. 'background-color': '#fc3d49',
  372. color: 'white',
  373. }"
  374. >
  375. <el-table-column type="selection" width="55" align="center" />
  376. <el-table-column prop="userId" label="外部人员Id"></el-table-column>
  377. <el-table-column prop="nickName" label="姓名">
  378. <template slot-scope="scope">
  379. <span style="color: #2a87ff">{{ scope.row.nickName }}</span>
  380. </template>
  381. </el-table-column>
  382. <!-- 添加搜索条件的列 -->
  383. <el-table-column label="搜索">
  384. <template slot="header">
  385. <el-input
  386. placeholder="搜索姓名"
  387. v-model="outsideSearchQuery"
  388. size="small"
  389. @input="filterOutsideTable"
  390. style="width: 90px;"
  391. />
  392. </template>
  393. </el-table-column>
  394. </el-table>
  395. </el-col>
  396. <el-col :span="7">
  397. <h3>选中人员列表</h3>
  398. <el-table :data="AllUserTable" stripe height="400">
  399. <!-- <el-table-column type="selection" width="55" align="center"/>-->
  400. <!-- <el-table-column prop="userId" label="外部人员Id">-->
  401. <!-- </el-table-column>-->
  402. <el-table-column prop="userName" label="姓名">
  403. <template slot-scope="scope">
  404. <span style="color: #2a87ff">{{ scope.row.userName }}</span>
  405. </template>
  406. </el-table-column>
  407. <el-table-column prop="userType" label="来源">
  408. <template slot-scope="scope">
  409. <span style="color: #2a87ff">{{
  410. scope.row.userType == '0' ? '内部' : '外部'
  411. }}</span>
  412. </template>
  413. </el-table-column>
  414. <el-table-column label="操作" width="80">
  415. <template slot-scope="scope">
  416. <el-button
  417. v-no-more-click
  418. @click.native.prevent="
  419. deleteRow(scope.$index, AllUserTable)
  420. "
  421. type="text"
  422. size="small"
  423. >
  424. 移除
  425. </el-button>
  426. </template>
  427. </el-table-column>
  428. </el-table>
  429. </el-col>
  430. </el-row>
  431. </el-form>
  432. <div slot="footer" class="dialog-footer">
  433. <el-button v-no-more-click type="primary" @click="confirmAddUser"
  434. >确认
  435. </el-button
  436. >
  437. <el-button v-no-more-click @click="cancel">取 消</el-button>
  438. </div>
  439. </el-dialog>
  440. <!-- 第五步查看作业详情弹窗-->
  441. <el-dialog :visible.sync="FiveDetailvisible" width="1000px" append-to-body>
  442. <el-row>
  443. <el-card class="box-cardStatus">
  444. <div slot="header" class="clearfix">
  445. <span style="font-weight: bolder">作业状态</span>
  446. </div>
  447. <el-table
  448. :data="jobTicket"
  449. :header-cell-style="{ 'text-align': 'center' }"
  450. :cell-style="{ 'text-align': 'center' }"
  451. >
  452. <el-table-column label="作业编号" prop="ticketId">
  453. </el-table-column>
  454. <el-table-column label="作业名称" prop="ticketName">
  455. </el-table-column>
  456. <el-table-column label="状态" align="center" prop="ticketStatus">
  457. <template slot-scope="scope">
  458. <dict-tag
  459. :options="dict.type.ticket_status"
  460. :value="scope.row.ticketStatus"
  461. />
  462. </template>
  463. </el-table-column>
  464. <el-table-column label="上锁钥匙" prop="lockKeyName">
  465. </el-table-column>
  466. <el-table-column label="解锁钥匙" prop="colockKeyName">
  467. </el-table-column>
  468. </el-table>
  469. </el-card>
  470. </el-row>
  471. <el-row>
  472. <el-col :span="7" style="height: 400px">
  473. <el-card class="box-card1">
  474. <div slot="header" class="clearfix">
  475. <span style="font-weight: bolder">人员状态</span>
  476. </div>
  477. <el-table :data="lockUserList">
  478. <el-table-column label="上锁人" prop="userName"></el-table-column>
  479. <el-table-column label="状态" align="center" prop="jobStatus">
  480. <template slot-scope="scope">
  481. <div
  482. class="box"
  483. style="
  484. width: 30px;
  485. height: 30px;
  486. border: 1px solid black;
  487. background-color: white;
  488. margin: 0 auto;
  489. "
  490. >
  491. <span
  492. v-if="
  493. scope.row.jobStatus == 0 ||
  494. scope.row.jobStatus == 1 ||
  495. scope.row.jobStatus == 2 ||
  496. scope.row.jobStatus == 3
  497. "
  498. ></span>
  499. <!-- 显示错号 -->
  500. <span
  501. v-else-if="scope.row.jobStatus == 4"
  502. style="font-size: 20px; line-height: 30px"
  503. >🔒</span
  504. >
  505. <!-- 显示对号 -->
  506. <span
  507. v-else-if="scope.row.jobStatus == 5"
  508. style="font-size: 20px; line-height: 30px"
  509. >✓</span
  510. >
  511. </div>
  512. </template>
  513. </el-table-column>
  514. </el-table>
  515. </el-card>
  516. <el-card class="box-cardgsr">
  517. <el-table :data="colockUserList">
  518. <el-table-column label="共锁人" prop="userName"></el-table-column>
  519. <el-table-column label="状态" align="center" prop="jobStatus">
  520. <template slot-scope="scope">
  521. <div
  522. class="box"
  523. style="
  524. width: 30px;
  525. height: 30px;
  526. border: 1px solid black;
  527. background-color: white;
  528. margin: 0 auto;
  529. "
  530. >
  531. <span
  532. v-if="
  533. scope.row.jobStatus == 0 ||
  534. scope.row.jobStatus == 1 ||
  535. scope.row.jobStatus == 2 ||
  536. scope.row.jobStatus == 3
  537. "
  538. ></span>
  539. <!-- 显示错号 -->
  540. <span
  541. v-else-if="scope.row.jobStatus == 4"
  542. style="font-size: 20px; line-height: 30px"
  543. >🔒</span
  544. >
  545. <!-- 显示对号 -->
  546. <span
  547. v-else-if="scope.row.jobStatus == 5"
  548. style="font-size: 20px; line-height: 30px"
  549. >✓</span
  550. >
  551. </div>
  552. </template>
  553. </el-table-column>
  554. </el-table>
  555. </el-card>
  556. </el-col>
  557. <el-col :span="6">
  558. <el-card class="box-card2">
  559. <div slot="header" class="clearfix">
  560. <span style="font-weight: bolder">隔离点状态</span>
  561. </div>
  562. <el-table :data="ticketPointsList">
  563. <el-table-column label="隔离点" prop="pointName" width="80">
  564. </el-table-column>
  565. <el-table-column label="状态" align="center" prop="pointStatus">
  566. <template slot-scope="scope">
  567. <div
  568. class="box"
  569. style="
  570. width: 30px;
  571. height: 30px;
  572. border: 1px solid black;
  573. background-color: white;
  574. margin: 0 auto;
  575. "
  576. >
  577. <span v-if="scope.row.pointStatus == 0" style=""></span>
  578. <!-- 显示错号 -->
  579. <span
  580. v-else-if="scope.row.pointStatus == 1"
  581. style="font-size: 20px; line-height: 30px"
  582. >🔒</span
  583. >
  584. <!-- 显示对号 -->
  585. <span
  586. v-else-if="scope.row.pointStatus == 2"
  587. style="font-size: 20px; line-height: 30px"
  588. >✓</span
  589. >
  590. </div>
  591. </template>
  592. </el-table-column>
  593. <el-table-column label="挂锁名称" prop="lockName">
  594. </el-table-column>
  595. <el-table-column
  596. label="锁具机构"
  597. prop="locksetName"
  598. ></el-table-column>
  599. </el-table>
  600. </el-card>
  601. </el-col>
  602. </el-row>
  603. <div slot="footer" class="dialog-footer">
  604. <el-button v-no-more-click @click="cancel">关 闭</el-button>
  605. </div>
  606. </el-dialog>
  607. <!-- 第八步查看影响作业票-->
  608. <el-dialog :visible.sync="EightDetailvisible" title="受影响作业票" width="650px" append-to-body>
  609. <el-table :data="AffectedTickets">
  610. <el-table-column label="作业票编号" prop="ticketId" >
  611. </el-table-column>
  612. <el-table-column label="作业票名称" prop="ticketName" width="220" >
  613. </el-table-column>
  614. <el-table-column label="作业票状态" prop="ticketStatus">
  615. <template slot-scope="scope">
  616. <dict-tag
  617. :options="dict.type.ticket_status"
  618. :value="scope.row.ticketStatus"
  619. />
  620. </template>
  621. </el-table-column>
  622. <el-table-column
  623. label="作业票类型"
  624. prop="ticketType"
  625. >
  626. <template slot-scope="scope">
  627. <dict-tag
  628. :options="dict.type.sop_type"
  629. :value="scope.row.ticketType"
  630. />
  631. </template>
  632. </el-table-column>
  633. </el-table>
  634. <div slot="footer" class="dialog-footer">
  635. <el-button v-no-more-click @click="cancel">关 闭</el-button>
  636. </div>
  637. </el-dialog>
  638. </div>
  639. </template>
  640. <script>
  641. import { listMarsDept } from '@/api/system/marsdept'
  642. import { getTechnologyInfo, listTechnology } from '@/api/system/machinery'
  643. import Template from '@/views/print/printtemplate/list.vue'
  644. import { getIsMarsSopPage } from '@/api/mes/sop/sopindex'
  645. import {
  646. addJobTicket,
  647. addJobUsers,
  648. getJobTicketInfo,
  649. getStepEight,
  650. getStepInfo,
  651. getWorkstationTicketList,
  652. listJobTicket,
  653. updateJobStep,
  654. updateJobToCancel,
  655. updateJobToFinish
  656. } from '@/api/mes/job/job'
  657. import MapData from '@/views/mes/job/jobm/Mapdata.vue'
  658. import { getUserList } from '@/api/mes/workCard'
  659. import { getJobPlayTicketInfo } from '@/api/mes/jobplay/jobplay'
  660. import { getLotoInfo, getLotoMapInfo } from '@/api/mes/lotoStation/lotoStation'
  661. export default {
  662. name: 'NewSop',
  663. components: { Template, MapData },
  664. dicts: ['sop_type', 'ticket_status'],
  665. data() {
  666. return {
  667. tabPosition: 'first',
  668. selectedOption: '',
  669. marsSopPage: [], //岗位对应sop列表
  670. marsSopTitle: '', //岗位后 对应展示sop
  671. marsDeptList: [],
  672. listLockerOption: [], //上锁人下拉数据
  673. form: null, //存储选中的设备工艺sop列表数据
  674. machineryImg: null, //第三步作业执行渲染设备工艺图片
  675. machineryId: null, //第三步作业执行渲染电柜的数据
  676. EightStepForm: null, //八大步骤详细内容
  677. ticketId: null, //新增之后 编辑需要使用的id
  678. open: false, //添加人员
  679. openColocker: false, //添加内外部人员
  680. outsideTableData: [], //外部人员表格
  681. insideTableData: [], //内部人员表格
  682. insideTableDataOrign:[],//内部原始数据
  683. outsideTableDataOrign:[],//外部原始数据
  684. selectedInsideRows: [], // 存储选中的内部人员的 userId
  685. selectedOutsideRows: [], // 存储选中的外部人员的 userId
  686. insideSearchQuery: '', // 内部搜索条件
  687. outsideSearchQuery: '', // 外部搜索条件
  688. AllUserTable: [], //所有选中人员列表
  689. dialogForm: {
  690. nickName: '',
  691. username: ''
  692. },
  693. // 弹出层标题
  694. title: '',
  695. // 弹框中显示的form表单内容
  696. newticketUserDTOList: [], //为了上锁人单独传递数据
  697. FiveDetailvisible: false, //第五步详情弹窗
  698. ticketPointsList: [], //第五步详情的隔离点信息
  699. colockUserList: [], //第五步详情的共锁人信息
  700. lockUserList: [], //第五步详情的上锁人信息
  701. jobTicket: [], //第五步详情的作业票信息
  702. TicketListPage: [], //作业票列表page接口传递的数据 底图循环渲染图标 RR岗位作业票
  703. selectPointList: [], //隔离点选中的表格渲染
  704. COCOTicketListPage: [], //CCO岗位的作业票
  705. scaleFactor: 1, // 缩放比例,初始值为1
  706. EightDetailvisible: false,//第八步受影响作业票
  707. AffectedTickets:[],//第八步查看详情信息表格
  708. }
  709. },
  710. computed: {
  711. filteredSopTypes() {
  712. const sopTypesInMarsSopPage = this.marsSopPage.map(
  713. (item) => item.sopType
  714. )
  715. return this.dict.type.sop_type.filter((option) =>
  716. sopTypesInMarsSopPage.includes(option.value)
  717. )
  718. },
  719. isStepFourExecuted() {
  720. const stepFour = this.EightStepForm.find((step) => step.stepIndex == "4");
  721. return stepFour && stepFour.stepStatus === '1';
  722. },
  723. },
  724. mounted() {
  725. this.getList()
  726. },
  727. methods: {
  728. filterInsideTable() {
  729. const query = this.insideSearchQuery.trim().toLowerCase();
  730. const filteredData = this.insideTableDataOrign.filter(item =>
  731. item.nickName.toLowerCase().includes(query)
  732. );
  733. this.insideTableData = filteredData;
  734. // 如果输入框为空或null,回显选中状态
  735. if (!this.insideSearchQuery) {
  736. // 筛选完毕后,勾选 AllUserTable 中有的用户
  737. this.insideTableData.forEach(user => {
  738. const matchingUser = this.AllUserTable.find(u =>
  739. u.userId == user.userId
  740. );
  741. console.log('Matching User:', matchingUser); // 输出匹配结果
  742. if (matchingUser) {
  743. this.$nextTick(() => {
  744. console.log(`Selecting user: ${user.nickName}`);
  745. this.$refs.insideTable.toggleRowSelection(user, true);
  746. });
  747. } else {
  748. this.$nextTick(() => {
  749. console.log(`Deselecting user: ${user.nickName}`);
  750. this.$refs.insideTable.toggleRowSelection(user, false);
  751. });
  752. }
  753. });
  754. }
  755. },
  756. // 外部人员搜索
  757. filterOutsideTable() {
  758. const query = this.outsideSearchQuery.trim().toLowerCase();
  759. const filteredData = this.outsideTableDataOrign.filter(item =>
  760. item.nickName.toLowerCase().includes(query)
  761. );
  762. this.outsideTableData = filteredData;
  763. // 如果输入框为空或null,回显选中状态
  764. if (!this.outsideSearchQuery) {
  765. // 筛选完毕后,勾选 AllUserTable 中有的用户
  766. this.outsideTableData.forEach(user => {
  767. const matchingUser = this.AllUserTable.find(u =>
  768. u.userId == user.userId
  769. );
  770. console.log('Matching User:', matchingUser); // 输出匹配结果
  771. if (matchingUser) {
  772. this.$nextTick(() => {
  773. console.log(`Selecting user: ${user.nickName}`);
  774. this.$refs.outsideTable.toggleRowSelection(user, true);
  775. });
  776. } else {
  777. this.$nextTick(() => {
  778. console.log(`Deselecting user: ${user.nickName}`);
  779. this.$refs.outsideTable.toggleRowSelection(user, false);
  780. });
  781. }
  782. });
  783. }
  784. },
  785. handleTicketClick(data) {
  786. console.log(data, '查看作业票详情')
  787. this.ticketId = data.ticketId
  788. this.tabPosition = 'third'
  789. getStepInfo(this.ticketId).then((res) => {
  790. this.EightStepForm = res.data
  791. console.log(res, '作业票-详细信息')
  792. })
  793. this.machineryId = data.machineryId
  794. // 获取设备工艺图
  795. getTechnologyInfo(data.machineryId).then((res) => {
  796. this.machineryImg = res.data.machineryImg
  797. // 获取电柜选中隔离点
  798. const lotoId = res.data.lotoId
  799. const selectPointsIds = res.data.pointIdList
  800. getLotoMapInfo(lotoId).then((response) => {
  801. console.log(response, '电柜信息--NewMarsJob')
  802. this.selectPointList = response.data.filter((item) =>
  803. selectPointsIds.includes(item.pointId)
  804. )
  805. console.log(this.selectPointList, '拿到的选中隔离点数据')
  806. })
  807. })
  808. },
  809. getList() {
  810. const data = {
  811. pages: 1,
  812. size: -1
  813. }
  814. getWorkstationTicketList(data).then((res) => {
  815. console.log(res, '查看-正在进行中作业票列表')
  816. this.TicketListPage = res.data.filter(
  817. (item) => item.workstationId == '8'
  818. )
  819. this.COCOTicketListPage = res.data.filter(
  820. (item) => item.workstationId == '7'
  821. )
  822. })
  823. listTechnology(data).then((res) => {
  824. console.log(res, 'technologyList')
  825. this.technologyList = res.data.records
  826. })
  827. listMarsDept(data).then((res) => {
  828. console.log(res, 'marsDeptList')
  829. this.marsDeptList = res.data.records
  830. })
  831. const query = {
  832. pageSize: 10000,
  833. pageNum: 1
  834. }
  835. getUserList(query).then((res) => {
  836. console.log(res, 'userList')
  837. this.listLockerOption = res.rows
  838. .filter((item) => item.unitId == 9)
  839. .map((item) => ({
  840. label: item.nickName,
  841. value: item.userId
  842. }))
  843. })
  844. },
  845. // 作业票切换
  846. handelChange(val, workstationId, workstationName) {
  847. console.log(val)
  848. this.tabPosition = val
  849. this.marsSopTitle = workstationName
  850. if (workstationId) {
  851. const data = {
  852. pages: 1,
  853. size: -1,
  854. workstationId: workstationId
  855. }
  856. getIsMarsSopPage(data).then((res) => {
  857. console.log(res, 'SopPage')
  858. this.marsSopPage = res.data.records
  859. })
  860. }
  861. if (val == 'third') {
  862. const data = {
  863. sopId: this.form[0].sopId
  864. }
  865. addJobTicket(data).then((res) => {
  866. console.log(res, '作业票新增')
  867. this.$message.success('作业开始执行')
  868. this.ticketId = res.data
  869. getStepInfo(this.ticketId).then((res) => {
  870. this.EightStepForm = res.data
  871. console.log(res, '作业票-详细信息')
  872. })
  873. })
  874. }
  875. },
  876. // 多选框选中数据
  877. handleSelectionChange(selection) {
  878. console.log(selection, 'mars设备工艺表格多选拿到的数据')
  879. this.form = selection
  880. this.machineryId = selection[0].machineryId
  881. getTechnologyInfo(selection[0].machineryId).then((res) => {
  882. this.machineryImg = res.data.machineryImg
  883. })
  884. },
  885. // 添加内部人员
  886. addInside(row) {
  887. if (row.stepIndex == '3') {
  888. this.open = true
  889. const query = {
  890. pageSize: 10000,
  891. pageNum: 1
  892. }
  893. getUserList(query).then((res) => {
  894. this.insideTableData = res.rows.filter((item) => item.unitId == 9)
  895. this.outsideTableData = res.rows.filter((item) => item.unitId != '9')
  896. console.log(this.insideTableData, this.outsideTableData, '用户')
  897. // 获取已分配人员数据
  898. getJobTicketInfo(this.ticketId).then((res) => {
  899. const assignedUsers = res.data.jobTicketUserList || [];
  900. console.log(assignedUsers, '已分配人员');
  901. this.dialogForm.locker = assignedUsers
  902. .filter(item => item.userRole == 'jtlocker')
  903. .map(item => item.userName);
  904. console.log(this.dialogForm.locker,'上锁人回显数据')
  905. // 更新内部和外部用户的选中状态
  906. this.$nextTick(() => {
  907. // 手动选中内部人员
  908. this.insideTableData.forEach((user) => {
  909. const isAssigned = assignedUsers.some(
  910. (assigned) =>
  911. assigned.userId == user.userId && assigned.userType == '0'&&assigned.userRole!=='jtlocker'
  912. );
  913. if (isAssigned) {
  914. this.$refs.insideTable.toggleRowSelection(user, true);
  915. }
  916. });
  917. // 手动选中外部人员
  918. this.outsideTableData.forEach((user) => {
  919. const isAssigned = assignedUsers.some(
  920. (assigned) =>
  921. assigned.userId == user.userId && assigned.userType == '1'&&assigned.userRole!=='jtlocker'
  922. );
  923. if (isAssigned) {
  924. this.$refs.outsideTable.toggleRowSelection(user, true);
  925. }
  926. });
  927. this.insideTableDataOrign = [...this.insideTableData];
  928. this.outsideTableDataOrign = [...this.outsideTableData];
  929. });
  930. });
  931. })
  932. } else {
  933. const data = {
  934. stepId: row.stepId,
  935. stepStatus: '1'
  936. }
  937. updateJobStep(data).then((res) => {
  938. this.$message.success('执行成功')
  939. getStepInfo(this.ticketId).then((res) => {
  940. this.EightStepForm = res.data
  941. console.log(res, '作业票-详细信息')
  942. })
  943. })
  944. }
  945. },
  946. // 上锁人下拉选择change事件
  947. handlelockerChage(val) {
  948. console.log(val, '上锁人chage')
  949. this.$forceUpdate();
  950. const user = this.listLockerOption.find((item) => item.value == val)
  951. if (user && this.dialogForm.locker !== '') {
  952. const existingUser = this.listLockerOption.find(
  953. (u) => u.userName === user.label
  954. )
  955. if (!existingUser) {
  956. this.newticketUserDTOList.push({
  957. userName: user.label,
  958. userId: user.value,
  959. userType: 0,
  960. userRole: 'jtlocker'
  961. })
  962. console.log(this.newticketUserDTOList, '用户')
  963. } else {
  964. // console.log('用户已存在', user.label)
  965. }
  966. }
  967. },
  968. handlelockerClear(){
  969. this.newticketUserDTOList = []
  970. console.log(this.newticketUserDTOList, '清除后的用户');
  971. },
  972. InSelectionChange(selection) {
  973. selection.forEach((item) => {
  974. if (!this.AllUserTable.some((user) => user.userId === item.userId)) {
  975. this.AllUserTable.push({
  976. userName: item.nickName,
  977. userId: item.userId,
  978. userType: 0,
  979. userRole: 'jtcolocker'
  980. })
  981. }
  982. })
  983. console.log(this.AllUserTable, '内部人员')
  984. },
  985. OutSelectionChange(selection) {
  986. selection.forEach((item) => {
  987. if (!this.AllUserTable.some((user) => user.userId === item.userId)) {
  988. this.AllUserTable.push({
  989. userName: item.nickName,
  990. userId: item.userId,
  991. userType: 1,
  992. userRole: 'jtcolocker'
  993. })
  994. }
  995. })
  996. console.log(this.AllUserTable, '外部人员')
  997. },
  998. confirmAddUser() {
  999. const data = {
  1000. ticketId: this.ticketId,
  1001. ticketUserDTOList: [...this.AllUserTable, ...this.newticketUserDTOList]
  1002. }
  1003. console.log(data, '添加人员')
  1004. addJobUsers(data).then((res) => {
  1005. console.log(res, '添加人员')
  1006. if (res.data) {
  1007. this.$message.success('分配人员成功')
  1008. this.open = false
  1009. this.AllUserTable = []
  1010. this.dialogForm.locker = ''
  1011. getStepInfo(this.ticketId).then((res) => {
  1012. this.EightStepForm = res.data
  1013. console.log(res, '作业票-详细信息')
  1014. })
  1015. }
  1016. })
  1017. },
  1018. // 人员列表删除
  1019. deleteRow(index, rows) {
  1020. console.log(index, rows, '删除的行')
  1021. const deletedItem = rows[index] // 获取要删除的项
  1022. rows.splice(index, 1) // 从显示的列表中删除
  1023. const formIndex = this.dialogForm.ticketUserDTOList.findIndex(
  1024. (item) => item.userName == deletedItem.userName
  1025. )
  1026. if (formIndex !== -1) {
  1027. this.dialogForm.ticketUserDTOList.splice(formIndex, 1) // 从 form.ticketUserDTOList 中删除
  1028. }
  1029. },
  1030. // 取消按钮
  1031. cancel() {
  1032. this.open = false
  1033. this.FiveDetailvisible = false
  1034. this.EightDetailvisible=false
  1035. },
  1036. // 作业票结束
  1037. finshJobticket() {
  1038. const data = {
  1039. ticketId: this.ticketId
  1040. }
  1041. updateJobToFinish(data).then((res) => {
  1042. console.log(res, '结束作业票')
  1043. if (res.data) {
  1044. this.$message.success('作业票结束')
  1045. this.tabPosition = 'first'
  1046. this.getList()
  1047. }
  1048. })
  1049. },
  1050. // 作业票取消
  1051. cancelJobticket() {
  1052. const data = {
  1053. ticketId: this.ticketId
  1054. }
  1055. updateJobToCancel(data).then((res) => {
  1056. console.log(res, '取消作业票')
  1057. if (res.data) {
  1058. this.$message.success('作业票取消')
  1059. this.tabPosition = 'first'
  1060. this.getList()
  1061. }
  1062. })
  1063. },
  1064. // 查看详情八大步骤
  1065. checkDetail(row) {
  1066. if (row.stepIndex == '5') {
  1067. this.FiveDetailvisible = true
  1068. let ticketId = this.ticketId
  1069. getJobPlayTicketInfo(ticketId).then((res) => {
  1070. console.log(res, '作业执行详细信息')
  1071. this.jobTicket = [res.data.jobTicket].map((item) => ({
  1072. ...item,
  1073. lockKeyName: res.data.lockKeyName,
  1074. colockKeyName: res.data.colockKeyName
  1075. }))
  1076. this.lockUserList = res.data.lockUserList
  1077. this.colockUserList = res.data.colockUserList
  1078. this.ticketPointsList = res.data.ticketPointsList
  1079. })
  1080. } else if (row.stepIndex == '8') {
  1081. let ticketId = this.ticketId
  1082. this.EightDetailvisible=true
  1083. getStepEight(ticketId).then((res) => {
  1084. console.log(res, '第八步查看作业票数据')
  1085. this.AffectedTickets=res.data
  1086. })
  1087. }
  1088. }
  1089. }
  1090. }
  1091. </script>
  1092. <style scoped lang="scss">
  1093. .deptXLG {
  1094. position: absolute;
  1095. width: 65px;
  1096. height: 25px;
  1097. left: 500px;
  1098. top: 260px;
  1099. background: #70b26f;
  1100. line-height: 25px;
  1101. text-align: center;
  1102. border-radius: 5px;
  1103. color: #fff;
  1104. cursor: pointer;
  1105. }
  1106. .deptCCO {
  1107. position: absolute;
  1108. width: 65px;
  1109. height: 25px;
  1110. left: 670px;
  1111. top: 480px;
  1112. background: #70b26f;
  1113. line-height: 25px;
  1114. text-align: center;
  1115. border-radius: 5px;
  1116. color: #fff;
  1117. cursor: pointer;
  1118. }
  1119. .box-cardStatus {
  1120. width: 850px;
  1121. margin: 15px;
  1122. }
  1123. .box-card1 {
  1124. width: 250px;
  1125. margin: 15px;
  1126. }
  1127. .box-cardgsr {
  1128. width: 250px;
  1129. height: auto;
  1130. margin: 15px;
  1131. }
  1132. .box-card2 {
  1133. width: 560px;
  1134. margin: 15px;
  1135. }
  1136. .status-container {
  1137. width: 100%;
  1138. height: 100%;
  1139. background: pink;
  1140. display: flex;
  1141. }
  1142. .box {
  1143. width: 30px;
  1144. height: 30px;
  1145. border: 1px solid #e7e5e5;
  1146. background-color: rgb(209, 77, 77);
  1147. }
  1148. .error-icon {
  1149. color: red;
  1150. font-weight: bold;
  1151. }
  1152. .success-icon {
  1153. color: green;
  1154. font-weight: bold;
  1155. }
  1156. //滚动条的宽度
  1157. ::-webkit-scrollbar {
  1158. width: 8px;
  1159. height: 8px;
  1160. background-color: #e4e4e4;
  1161. border-radius: 6px;
  1162. }
  1163. //滚动条的滑块
  1164. ::-webkit-scrollbar-thumb {
  1165. background-color: #a1a3a9;
  1166. border-radius: 6px;
  1167. }
  1168. div[ref="mapContainer"] {
  1169. transition: transform 0.2s ease;
  1170. }
  1171. </style>