add.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. <template>
  2. <div class="plan_container">
  3. <el-form
  4. :model="addForm"
  5. ref="addFormRef"
  6. :rules="rules"
  7. label-width="100px"
  8. >
  9. <el-row>
  10. <!-- <el-col :span="6">
  11. <el-form-item label="计划单号:" prop="planCode">
  12. <el-input
  13. v-model="addForm.planCode"
  14. size="small"
  15. placeholder="自动带出"
  16. disabled
  17. ></el-input>
  18. </el-form-item>
  19. </el-col> -->
  20. <el-col :span="6">
  21. <el-form-item label="计划名称:" prop="planName">
  22. <el-input
  23. v-model.trim="addForm.planName"
  24. placeholder="请输入"
  25. ></el-input>
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="6">
  29. <el-form-item label="审批部门:" prop="verifyDeptCode">
  30. <deptSelect
  31. v-model="addForm.verifyDeptCode"
  32. @change="searchDeptNodeClick"
  33. />
  34. </el-form-item>
  35. </el-col>
  36. <el-col :span="6">
  37. <el-form-item label="审批人:" prop="approvalUserId">
  38. <personSelect
  39. ref="executorRef"
  40. v-model="addForm.approvalUserId"
  41. :init="false"
  42. />
  43. </el-form-item>
  44. </el-col>
  45. <el-col :span="6">
  46. <el-form-item label="紧急程度:" prop="urgent">
  47. <DictSelection dictName="紧急程度" clearable v-model="addForm.urgent">
  48. </DictSelection>
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="24">
  52. <div class="btns_wrapper">
  53. <el-button type="primary" size="small" @click="selectRepairNotes"
  54. >选择报修记录</el-button
  55. >
  56. <el-button
  57. type="primary"
  58. size="small"
  59. @click="handleBatchRemoveEqui"
  60. >删除</el-button
  61. >
  62. </div>
  63. </el-col>
  64. </el-row>
  65. </el-form>
  66. <p>设备明细</p>
  67. <el-table
  68. :data="equipmentData"
  69. border
  70. style="margin-top: 10px"
  71. @selection-change="equiMultipleSelectChange"
  72. >
  73. <el-table-column type="selection" align="center" />
  74. <el-table-column label="报修记录编码" prop="code" />
  75. <el-table-column label="设备编码" prop="deviceCode" />
  76. <el-table-column label="设备名称" prop="deviceName" />
  77. <el-table-column label="计划完成时间" prop="expectedTime" width="220">
  78. <template slot-scope="scope">
  79. <el-input
  80. v-model="scope.row.expectedTime"
  81. size="small"
  82. disabled
  83. placeholder="设置执行人自动带出"
  84. style="width: 100%"
  85. />
  86. </template>
  87. </el-table-column>
  88. <!-- <el-table-column label="执行部门" prop="deptName">
  89. <template slot-scope="scope">
  90. <el-input
  91. v-model="scope.row.deptName"
  92. size="small"
  93. disabled
  94. placeholder="设置执行人自动带出"
  95. />
  96. </template>
  97. </el-table-column> -->
  98. <el-table-column label="执行人" prop="workOrderExecutorId">
  99. <template slot-scope="scope">
  100. <personSelect
  101. v-if="scope.$index == 0"
  102. :disabled="true"
  103. v-model="scope.row.workOrderExecutorId"
  104. placeholder="设置"
  105. @click.native="settingExecutor(scope.$index, scope.row)"
  106. />
  107. <personSelect
  108. v-else
  109. readonly
  110. v-model="scope.row.workOrderExecutorId"
  111. placeholder="同上"
  112. @click.native="dittoName(scope.$index, scope.row)"
  113. :disabled="true"
  114. />
  115. </template>
  116. </el-table-column>
  117. <el-table-column label="操作">
  118. <template slot-scope="scope">
  119. <el-button type="text" @click="handleRemoveEquiItem(scope.$index)"
  120. >删除</el-button
  121. >
  122. </template>
  123. </el-table-column>
  124. </el-table>
  125. <div class="btns">
  126. <el-button type="primary" size="small" @click="handleSubmitAdd"
  127. >提交</el-button
  128. >
  129. <el-button size="small" @click="$router.go(-1)">返回</el-button>
  130. </div>
  131. <!-- 选择报修记录弹窗 -->
  132. <ele-modal
  133. title="选择报修记录"
  134. :visible.sync="selectNotesVisible"
  135. :before-close="closeRepairNotesDialog"
  136. :close-on-click-modal="false"
  137. :close-on-press-escape="false"
  138. width="65%"
  139. >
  140. <div class="search_msg">
  141. <el-input
  142. v-model="code"
  143. style="width: 30%;margin-right: 20px;"
  144. clearable
  145. placeholder="请输入编码"
  146. ></el-input>
  147. <el-button type="primary" @click="searchByKeyWords">确定</el-button>
  148. <el-button type="primary" @click="resetSearch">重置</el-button>
  149. </div>
  150. <el-table
  151. :data="notesData"
  152. @selection-change="notesMultipleSelectChange"
  153. ref="multipleTable"
  154. >
  155. <el-table-column
  156. type="selection"
  157. width="55"
  158. align="center"
  159. ></el-table-column>
  160. <el-table-column
  161. label="报修记录编码"
  162. prop="code"
  163. align="center"
  164. ></el-table-column>
  165. <el-table-column
  166. label="设备编码"
  167. prop="deviceCode"
  168. align="center"
  169. ></el-table-column>
  170. <el-table-column
  171. label="设备名称"
  172. prop="deviceName"
  173. align="center"
  174. ></el-table-column>
  175. <el-table-column label="来源" align="center">
  176. <template slot-scope="{ row }">
  177. <span>{{ getDictValue('报修来源', row.sourceType) }}</span>
  178. </template>
  179. </el-table-column>
  180. <el-table-column
  181. label="报修人"
  182. prop="requestUserName"
  183. width="70"
  184. align="center"
  185. ></el-table-column>
  186. <el-table-column
  187. label="报修时间"
  188. prop="createTime"
  189. width="150"
  190. align="center"
  191. ></el-table-column>
  192. <el-table-column
  193. label="期望完成时间"
  194. prop="expectedTime"
  195. width="150"
  196. align="center"
  197. ></el-table-column>
  198. </el-table>
  199. <div class="pagination_wrapper">
  200. <el-pagination
  201. background
  202. layout="total, sizes, prev, pager, next, jumper"
  203. :page-sizes="[10, 15, 20, 30, 50]"
  204. :current-page.sync="pagination.pageNum"
  205. :page-size.sync="pagination.size"
  206. :total="total"
  207. @current-change="handleCurrentChange"
  208. @size-change="handleSizeChange"
  209. >
  210. </el-pagination>
  211. </div>
  212. <template v-slot:footer>
  213. <el-button type="primary" size="small" @click="handleConfirm"
  214. >确定</el-button
  215. >
  216. <el-button size="small" @click="closeRepairNotesDialog">关闭</el-button>
  217. </template>
  218. </ele-modal>
  219. <!-- 设置执行人弹窗 -->
  220. <ele-modal
  221. title="派单"
  222. :visible.sync="settingExecutorVisible"
  223. class="setting_executor_dialog"
  224. :before-close="closeSettingExecutorDialog"
  225. :close-on-click-modal="false"
  226. :close-on-press-escape="false"
  227. width="60%"
  228. >
  229. <div>
  230. <el-form
  231. :model="infoData"
  232. :rules="infoFormRules"
  233. ref="infoFormRef"
  234. label-width="130px"
  235. >
  236. <el-row>
  237. <el-col :span="8">
  238. <el-form-item label="报修记录编号:">
  239. <span>{{ infoData.code }}</span>
  240. </el-form-item>
  241. </el-col>
  242. <el-col :span="8">
  243. <el-form-item label="设备编码:">
  244. <span>{{ infoData.deviceCode }}</span>
  245. </el-form-item>
  246. </el-col>
  247. <el-col :span="8">
  248. <el-form-item label="设备名称:">
  249. <span>{{ infoData.deviceName }}</span>
  250. </el-form-item>
  251. </el-col>
  252. </el-row>
  253. <el-row>
  254. <el-col :span="8">
  255. <el-form-item label="设备型号:">
  256. <span>{{infoData.category && infoData.category.modelType}}</span>
  257. </el-form-item>
  258. </el-col>
  259. <el-col :span="16">
  260. <el-form-item label="设备位置:">
  261. <span>
  262. {{ infoData.position }}
  263. </span>
  264. </el-form-item>
  265. </el-col>
  266. </el-row>
  267. <el-row>
  268. <el-col :span="24">
  269. <el-form-item label="故障描述:">
  270. <span>{{ infoData.remark }}</span>
  271. </el-form-item>
  272. </el-col>
  273. </el-row>
  274. <!-- <el-row>
  275. <el-col :span="16">
  276. <el-form-item label="图片:">
  277. <el-image
  278. v-for="(item, index) in infoData.repairsImg"
  279. :key="index"
  280. style="width: 100px; height: 100px; margin-right: 5px"
  281. :src="item.url"
  282. :preview-src-list="[item.url]"
  283. >
  284. </el-image>
  285. </el-form-item>
  286. </el-col>
  287. <el-col :span="8">
  288. <el-form-item label="视频:">
  289. <span>{{ infoData.repairsVideo }}</span>
  290. </el-form-item>
  291. </el-col>
  292. </el-row> -->
  293. <el-row class="valid_row">
  294. <el-col :span="8">
  295. <el-form-item label="计划完成时间:">
  296. <el-date-picker
  297. v-model="infoData.expectedTime"
  298. type="datetime"
  299. size="small"
  300. placeholder="选择日期时间"
  301. value-format="yyyy-MM-dd HH:mm:ss"
  302. >
  303. </el-date-picker>
  304. </el-form-item>
  305. </el-col>
  306. <el-col :span="8">
  307. <el-form-item label="执行部门:" prop="deptCode">
  308. <deptSelect
  309. v-model="infoData.deptCode"
  310. @change="deptNodeClick"
  311. />
  312. </el-form-item>
  313. </el-col>
  314. <el-col :span="8">
  315. <el-form-item label="执行人:" prop="workOrderExecutorId">
  316. <personSelect
  317. ref="setExecutor"
  318. v-model="infoData.workOrderExecutorId"
  319. :init="false"
  320. />
  321. </el-form-item>
  322. </el-col>
  323. </el-row>
  324. <el-row>
  325. <el-col :span="24">
  326. <el-form-item label="维修方案:">
  327. <el-input
  328. type="textarea"
  329. :rows="3"
  330. v-model="infoData.maintenanceContent"
  331. placeholder="请输入"
  332. ></el-input>
  333. </el-form-item>
  334. </el-col>
  335. </el-row>
  336. </el-form>
  337. </div>
  338. <template v-slot:footer>
  339. <el-button type="primary" size="small" @click="saveSetting"
  340. >保存</el-button
  341. >
  342. <el-button size="small" @click="closeSettingExecutorDialog"
  343. >关闭</el-button
  344. >
  345. </template>
  346. </ele-modal>
  347. </div>
  348. </template>
  349. <script>
  350. import personSelect from '@/components/CommomSelect/person-select.vue';
  351. import deptSelect from '@/components/CommomSelect/dept-select.vue';
  352. import { getPage , savePlanRepair } from '@/api/maintenance/repair_report';
  353. import { getAssetInfo } from '@/api/ledgerAssets';
  354. import dictMixins from '@/mixins/dictMixins';
  355. export default {
  356. mixins: [dictMixins],
  357. components: {
  358. personSelect,
  359. deptSelect
  360. },
  361. data () {
  362. return {
  363. equipmentData: [], // 设备明细表格
  364. equiSelection: [], // 设备明细 - 表格多选
  365. selectNotesVisible: false, // 弹窗
  366. notesData: [], // 弹窗- 报修记录表格
  367. notesSelection: [], // 弹窗 - 表格多选
  368. code: '', // 弹窗 - 关键字搜索
  369. addForm: { },
  370. pagination: {
  371. pageNum: 1,
  372. size: 10,
  373. },
  374. total: 0,
  375. rules: {
  376. planName: [{ required: true, message: '请输入计划名称',trigger: 'blur' }],
  377. urgent: [{ required: true, message: '请选择紧急程度',trigger: 'change' }],
  378. verifyDeptCode: [{ required: true, message: '请选择审批部门',trigger: 'change' }],
  379. approvalUserId: [{ required: true, message: '请选择审批人',trigger: 'change' }]
  380. },
  381. settingIndex: null, // 保存的设备明细表格行index
  382. settingExecutorVisible: false, // 设置执行人弹窗
  383. infoData: { deptCode: '' }, // 设置执行人弹窗详情数据
  384. infoFormRules: {
  385. deptCode: [
  386. { required: true, message: '请选择执行部门', trigger: 'change' }
  387. ],
  388. workOrderExecutorId: [
  389. { required: true, message: '请选择执行人', trigger: 'change' }
  390. ]
  391. }
  392. }
  393. },
  394. created () {
  395. this.requestDict('报修来源');
  396. },
  397. methods: {
  398. //选择部门(搜索)
  399. searchDeptNodeClick (info) {
  400. // 根据部门获取人员
  401. const params = { groupId: info };
  402. this.$nextTick(() => {
  403. this.$refs.executorRef.getList(params);
  404. });
  405. },
  406. // // 获取详情
  407. // async _getPlanInfo () {
  408. // const res = await maintenancePlan.planInfoDetailApi(this.$route.query.id)
  409. // this.addForm = res.data
  410. // this.equipmentData = res.data.planDetailRespList
  411. // },
  412. // 设备明细 - 表格多选
  413. equiMultipleSelectChange (val) {
  414. this.equiSelection = val
  415. },
  416. // 设备明细 - 删除表格行
  417. handleRemoveEquiItem (index) {
  418. this.equipmentData.splice(index, 1)
  419. },
  420. // 设备明细 - 批量删除行
  421. handleBatchRemoveEqui () {
  422. this.equiSelection.forEach(item => {
  423. const index = this.equipmentData.findIndex(c => c.id === item.id)
  424. this.equipmentData.splice(index, 1)
  425. })
  426. },
  427. // 获取报修详情
  428. getSbinfo (params) {
  429. getAssetInfo(params).then(res => {
  430. if (res) {
  431. this.infoData = res
  432. this.$set(this.infoData,'position',res.positionList[0].pathName?res.positionList[0].pathName:'')
  433. this.$set(this.infoData,'deviceCode',res.code)
  434. this.$set(this.infoData,'deviceName',res.name)
  435. }
  436. })
  437. },
  438. // 设备明细 - 打开设置执行人弹窗
  439. async settingExecutor (index, row) {
  440. console.log('打开设置执行人弹窗', index, row)
  441. this.getSbinfo(row.deviceId)
  442. this.settingIndex = index
  443. this.settingExecutorVisible = true
  444. this.$set(this.infoData, 'remark', row.remark)
  445. this.$set(this.infoData, 'code', row.code)
  446. },
  447. // 点击同上
  448. async dittoName (index, row) {
  449. if (!this.equipmentData[0].workOrderExecutorId) {
  450. this.$message.warning('请先设置第一条数据的执行人')
  451. } else {
  452. this.settingExecutor(index, row)
  453. }
  454. },
  455. // 选择部门(搜索)
  456. deptNodeClick (info) {
  457. const params = { groupId: info };
  458. this.$nextTick(() => {
  459. this.$refs.setExecutor.getList(params);
  460. });
  461. },
  462. // 弹窗 - 关闭
  463. closeRepairNotesDialog () {
  464. this.selectNotesVisible = false
  465. this.notesSelection = []
  466. this.$refs.multipleTable.clearSelection()
  467. },
  468. // 弹窗 - 确认选择报修记录
  469. handleConfirm () {
  470. let arr = []
  471. this.notesSelection.map(item => {
  472. if (item) {
  473. arr.push(item)
  474. }
  475. })
  476. this.notesSelection = arr
  477. this.equipmentData = this.notesSelection
  478. this.equipmentData.forEach(item => {
  479. item['repairInfoId'] = item.id
  480. item['plannedTime'] = item.expectedTime
  481. })
  482. this.closeRepairNotesDialog()
  483. },
  484. // 弹窗 - 打开选择报修记录
  485. selectRepairNotes () {
  486. this.selectNotesVisible = true
  487. this.$nextTick(async () => {
  488. await this._getNotesData()
  489. // 将设备明细回显到 报修记录表格并勾选已有的
  490. if (this.equipmentData.length > 0) {
  491. console.log(this.equipmentData)
  492. console.log(this.notesData)
  493. this.equipmentData.forEach(item => {
  494. const row = this.notesData.find(c => c.id === item.repairInfoId)
  495. this.$refs.multipleTable.toggleRowSelection(row, true)
  496. })
  497. }
  498. })
  499. },
  500. // 弹窗 - 报修记录表格数据
  501. async _getNotesData () {
  502. let params = {
  503. ...this.pagination,
  504. code:this.code,
  505. statusList:'0,6'
  506. }
  507. const res = await getPage(params)
  508. this.notesData = res.list
  509. this.total = res.count
  510. },
  511. // 弹窗 - 分页器方法
  512. handleCurrentChange (page) {
  513. this.pagination.pageNum = page
  514. this._getNotesData()
  515. },
  516. handleSizeChange (size) {
  517. this.pagination.pageNum = 1
  518. this.pagination.size = size
  519. this._getNotesData()
  520. },
  521. // 弹窗 - 按关键字搜索
  522. searchByKeyWords () {
  523. this._getNotesData()
  524. },
  525. resetSearch(){
  526. this.code = ''
  527. this._getNotesData()
  528. },
  529. // 弹窗 - 表格多选
  530. notesMultipleSelectChange (val) {
  531. this.notesSelection = val
  532. },
  533. // 弹窗 - 关闭设置执行人弹窗
  534. closeSettingExecutorDialog () {
  535. this.infoData = { deptCode: '' }
  536. this.$refs.infoFormRef.resetFields()
  537. this.settingExecutorVisible = false
  538. },
  539. // 弹窗 - 保存设置执行人
  540. saveSetting () {
  541. this.$refs.infoFormRef.validate(valid => {
  542. if (valid) {
  543. this.$set(
  544. this.equipmentData[this.settingIndex],
  545. 'expectedTime',
  546. this.infoData.expectedTime
  547. )
  548. this.$set(
  549. this.equipmentData[this.settingIndex],
  550. 'deptCode',
  551. this.infoData.deptCode
  552. )
  553. this.$set(
  554. this.equipmentData[this.settingIndex],
  555. 'workOrderExecutorId',
  556. this.infoData.workOrderExecutorId
  557. )
  558. this.$set(
  559. this.equipmentData[this.settingIndex],
  560. 'maintenanceContent',
  561. this.infoData.maintenanceContent
  562. )
  563. console.log('[this.settingIndex]', [this.settingIndex])
  564. if (!this.settingIndex) {
  565. this.equipmentData.map(item => {
  566. // item.workOrderExecutorName = this.infoData.workOrderExecutorName
  567. item.workOrderExecutorId = this.infoData.workOrderExecutorId
  568. // item.workOrderExecutorPhone = this.infoData.workOrderExecutorPhone
  569. // item.deptName = this.infoData.deptName
  570. item.maintenanceContent = this.infoData.maintenanceContent
  571. })
  572. }
  573. console.log(' this.equipmentData', this.equipmentData)
  574. this.closeSettingExecutorDialog()
  575. }
  576. })
  577. },
  578. // 提交新增
  579. handleSubmitAdd () {
  580. this.$refs.addFormRef.validate(async valid => {
  581. if (valid) {
  582. if (this.equipmentData.length === 0) {
  583. return this.$message.warning('请选择设备报修记录!')
  584. }
  585. let data = JSON.parse(JSON.stringify(this.addForm))
  586. data['planEquiList'] = this.equipmentData
  587. // let api = maintenancePlan.savePlanInfo
  588. let msg = '新增成功!'
  589. // 修改
  590. if (this.$route.query.id) {
  591. delete data.planDetailRespList
  592. // api = maintenancePlan.updatePlanInfo
  593. msg = '修改成功!'
  594. }
  595. // console.log(data)
  596. const res = await savePlanRepair(data)
  597. // console.log('保存新增:', res)
  598. this.$message.success(msg)
  599. this.$router.go(-1)
  600. }
  601. })
  602. }
  603. }
  604. }
  605. </script>
  606. <style lang="scss" scoped>
  607. .plan_container {
  608. background-color: #fff;
  609. padding: 20px 30px;
  610. margin-top: 10px;
  611. }
  612. .btns_wrapper {
  613. text-align: right;
  614. margin: 15px 0;
  615. }
  616. .btns {
  617. text-align: center;
  618. margin-top: 15px;
  619. }
  620. ::v-deep .el-table th.el-table__cell {
  621. background-color: #f0f3f3;
  622. }
  623. .search_msg {
  624. margin-bottom: 5px;
  625. }
  626. .pagination_wrapper {
  627. text-align: right;
  628. padding-top: 10px;
  629. }
  630. .dialog_btns {
  631. text-align: center;
  632. padding: 10px 0;
  633. }
  634. .setting_executor_dialog {
  635. .setting_btns {
  636. text-align: right;
  637. }
  638. .repair_row {
  639. margin-bottom: 15px;
  640. }
  641. ::v-deep .valid_row {
  642. .el-form-item {
  643. margin-bottom: 20px;
  644. }
  645. .el-form-item__error {
  646. padding-top: 0;
  647. }
  648. .el-date-editor.el-input {
  649. width: 190px;
  650. }
  651. }
  652. }
  653. </style>