index.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. <template>
  2. <div class="app-container">
  3. <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  4. <el-form-item label="装置" prop="plant">
  5. <el-input
  6. v-model="queryParams.plant"
  7. placeholder="请输入装置"
  8. clearable
  9. size="small"
  10. @keyup.enter.native="handleQuery"
  11. />
  12. </el-form-item>
  13. <el-form-item label="位置" prop="devLoc">
  14. <el-input
  15. v-model="queryParams.devLoc"
  16. placeholder="请输入位置"
  17. clearable
  18. size="small"
  19. @keyup.enter.native="handleQuery"
  20. />
  21. </el-form-item>
  22. <el-form-item label="设备位号" prop="devTag">
  23. <el-input
  24. v-model="queryParams.devTag"
  25. placeholder="请输入设备位号"
  26. clearable
  27. size="small"
  28. @keyup.enter.native="handleQuery"
  29. />
  30. </el-form-item>
  31. <el-form-item label="部件名称" prop="compoName">
  32. <el-input
  33. v-model="queryParams.compoName"
  34. placeholder="请输入部件名称"
  35. clearable
  36. size="small"
  37. @keyup.enter.native="handleQuery"
  38. />
  39. </el-form-item>
  40. <el-form-item label="部件型号" prop="compoModel">
  41. <el-input
  42. v-model="queryParams.compoModel"
  43. placeholder="请输入部件型号"
  44. clearable
  45. size="small"
  46. @keyup.enter.native="handleQuery"
  47. />
  48. </el-form-item>
  49. <el-form-item label="部件描述" prop="compoDesc">
  50. <el-input
  51. v-model="queryParams.compoDesc"
  52. placeholder="请输入部件描述"
  53. clearable
  54. size="small"
  55. @keyup.enter.native="handleQuery"
  56. />
  57. </el-form-item>
  58. <el-form-item label="备注" prop="remarks">
  59. <el-input
  60. v-model="queryParams.remarks"
  61. placeholder="请输入备注"
  62. clearable
  63. size="small"
  64. @keyup.enter.native="handleQuery"
  65. />
  66. </el-form-item>
  67. <el-form-item>
  68. <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  69. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  70. </el-form-item>
  71. </el-form>
  72. <el-row :gutter="10" class="mb8">
  73. <el-col :span="1.5">
  74. <el-button
  75. type="primary"
  76. icon="el-icon-plus"
  77. size="mini"
  78. @click="handleAdd"
  79. v-hasPermi="['reliability:rel_compo:add']"
  80. >新增</el-button>
  81. </el-col>
  82. <el-col :span="1.5">
  83. <el-button
  84. type="success"
  85. icon="el-icon-edit"
  86. size="mini"
  87. :disabled="single"
  88. @click="handleUpdate"
  89. v-hasPermi="['reliability:rel_compo:edit']"
  90. >修改</el-button>
  91. </el-col>
  92. <el-col :span="1.5">
  93. <el-button
  94. type="danger"
  95. icon="el-icon-delete"
  96. size="mini"
  97. :disabled="multiple"
  98. @click="handleDelete"
  99. v-hasPermi="['reliability:rel_compo:remove']"
  100. >删除</el-button>
  101. </el-col>
  102. <el-col :span="1.5">
  103. <el-button
  104. type="info"
  105. icon="el-icon-upload2"
  106. size="mini"
  107. @click="handleImport"
  108. v-hasPermi="['reliability:rel_compo:edit']"
  109. >导入</el-button>
  110. </el-col>
  111. <el-col :span="1.5">
  112. <el-button
  113. type="warning"
  114. icon="el-icon-download"
  115. size="mini"
  116. @click="handleExport"
  117. v-hasPermi="['reliability:rel_compo:list']"
  118. >导出</el-button>
  119. </el-col>
  120. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  121. </el-row>
  122. <el-table v-loading="loading" :data="rel_compoList" @selection-change="handleSelectionChange" :height="clientHeight" border>
  123. <el-table-column type="selection" width="55" align="center" />
  124. <el-table-column label="装置" align="center" prop="plant" width="120" :show-overflow-tooltip="true"/>
  125. <el-table-column label="位置" align="center" prop="devLoc" width="120" :show-overflow-tooltip="true"/>
  126. <el-table-column label="设备位号" align="center" prop="devTag" width="150" :show-overflow-tooltip="true"/>
  127. <el-table-column label="部件名称" align="center" prop="compoName" width="150" :show-overflow-tooltip="true"/>
  128. <el-table-column label="部件型号" align="center" prop="compoModel" width="150" :show-overflow-tooltip="true"/>
  129. <el-table-column label="测厚点" align="center" prop="thicknessPt" width="120" :show-overflow-tooltip="true"/>
  130. <el-table-column label="部件描述" align="center" prop="compoDesc" width="180" :show-overflow-tooltip="true"/>
  131. <el-table-column label="部件照片" align="center" prop="compoPhoto" width="100">
  132. <template slot-scope="scope">
  133. <el-button
  134. v-if="scope.row.compoPhoto"
  135. size="mini"
  136. type="text"
  137. icon="el-icon-picture"
  138. @click="handleViewPhoto(scope.row.compoPhoto)">
  139. 查看
  140. </el-button>
  141. <span v-else>-</span>
  142. </template>
  143. </el-table-column>
  144. <el-table-column label="检查人" align="center" prop="inspector" width="100" :show-overflow-tooltip="true">
  145. <template slot-scope="scope">
  146. {{ scope.row.inspectorName || getStaffName(scope.row.inspector) }}
  147. </template>
  148. </el-table-column>
  149. <el-table-column label="维修更换人" align="center" prop="fixer" width="120" :show-overflow-tooltip="true">
  150. <template slot-scope="scope">
  151. {{ scope.row.fixerName || getStaffName(scope.row.fixer) }}
  152. </template>
  153. </el-table-column>
  154. <el-table-column label="检查频率" align="center" prop="inspFreq" width="110" :show-overflow-tooltip="true">
  155. <template slot-scope="scope">
  156. {{ translateFrequency(scope.row.inspFreq) }}
  157. </template>
  158. </el-table-column>
  159. <el-table-column label="检查内容" align="center" prop="inspContent" width="180" :show-overflow-tooltip="true"/>
  160. <el-table-column label="上次检查日期" align="center" prop="lastInspDate" width="120">
  161. <template slot-scope="scope">
  162. <span>{{ parseTime(scope.row.lastInspDate, '{y}-{m}-{d}') }}</span>
  163. </template>
  164. </el-table-column>
  165. <el-table-column label="维修频率" align="center" prop="fixFreq" width="110" :show-overflow-tooltip="true">
  166. <template slot-scope="scope">
  167. {{ translateFrequency(scope.row.fixFreq) }}
  168. </template>
  169. </el-table-column>
  170. <el-table-column label="维修内容" align="center" prop="fixContent" width="180" :show-overflow-tooltip="true"/>
  171. <el-table-column label="上次维修日期" align="center" prop="lastFixDate" width="120">
  172. <template slot-scope="scope">
  173. <span>{{ parseTime(scope.row.lastFixDate, '{y}-{m}-{d}') }}</span>
  174. </template>
  175. </el-table-column>
  176. <el-table-column label="更换频率" align="center" prop="replaceFreq" width="110" :show-overflow-tooltip="true">
  177. <template slot-scope="scope">
  178. {{ translateFrequency(scope.row.replaceFreq) }}
  179. </template>
  180. </el-table-column>
  181. <el-table-column label="更换内容" align="center" prop="replaceContent" width="180" :show-overflow-tooltip="true"/>
  182. <el-table-column label="上次更换日期" align="center" prop="lastReplaceDate" width="120">
  183. <template slot-scope="scope">
  184. <span>{{ parseTime(scope.row.lastReplaceDate, '{y}-{m}-{d}') }}</span>
  185. </template>
  186. </el-table-column>
  187. <!-- <el-table-column label="下次维护日期" align="center" prop="nextMaintDate" width="120">-->
  188. <!-- <template slot-scope="scope">-->
  189. <!-- <span>{{ parseTime(scope.row.nextMaintDate, '{y}-{m}-{d}') }}</span>-->
  190. <!-- </template>-->
  191. <!-- </el-table-column>-->
  192. <!-- <el-table-column label="维护类型" align="center" prop="nextMaintType" width="120" :show-overflow-tooltip="true"/>-->
  193. <el-table-column label="备注" align="center" prop="remarks" width="150" :show-overflow-tooltip="true"/>
  194. <el-table-column label="操作" align="center" fixed="right" width="120" class-name="small-padding fixed-width">
  195. <template slot-scope="scope">
  196. <el-button
  197. size="mini"
  198. type="text"
  199. icon="el-icon-edit"
  200. @click="handleUpdate(scope.row)"
  201. v-hasPermi="['reliability:rel_compo:edit']"
  202. >修改</el-button>
  203. <el-button
  204. size="mini"
  205. type="text"
  206. icon="el-icon-delete"
  207. @click="handleDelete(scope.row)"
  208. v-hasPermi="['reliability:rel_compo:remove']"
  209. >删除</el-button>
  210. </template>
  211. </el-table-column>
  212. </el-table>
  213. <pagination
  214. v-show="total>0"
  215. :total="total"
  216. :page.sync="queryParams.pageNum"
  217. :limit.sync="queryParams.pageSize"
  218. @pagination="getList"
  219. />
  220. <!-- 添加或修改可靠性部件清单对话框 -->
  221. <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body class="compo-dialog">
  222. <el-form ref="form" :model="form" :rules="rules" label-width="100px">
  223. <!-- 基础数据 -->
  224. <div class="form-section">
  225. <div class="section-header">
  226. <i class="el-icon-document"></i>
  227. <span class="section-title">基础数据</span>
  228. </div>
  229. <el-row :gutter="20">
  230. <el-col :span="12">
  231. <el-form-item label="装置" prop="plant">
  232. <el-input v-model="form.plant" placeholder="请输入装置" />
  233. </el-form-item>
  234. </el-col>
  235. <el-col :span="12">
  236. <el-form-item label="位置" prop="devLoc">
  237. <el-input v-model="form.devLoc" placeholder="请输入位置" />
  238. </el-form-item>
  239. </el-col>
  240. </el-row>
  241. <el-row :gutter="20">
  242. <el-col :span="12">
  243. <el-form-item label="设备位号" prop="devTag">
  244. <el-input v-model="form.devTag" placeholder="请输入设备位号" />
  245. </el-form-item>
  246. </el-col>
  247. <el-col :span="12">
  248. <el-form-item label="部件名称" prop="compoName">
  249. <el-input v-model="form.compoName" placeholder="请输入部件名称" />
  250. </el-form-item>
  251. </el-col>
  252. </el-row>
  253. <el-row :gutter="20">
  254. <el-col :span="12">
  255. <el-form-item label="部件型号" prop="compoModel">
  256. <el-input v-model="form.compoModel" placeholder="请输入部件型号" />
  257. </el-form-item>
  258. </el-col>
  259. <el-col :span="12">
  260. <el-form-item label="测厚点" prop="thicknessPt">
  261. <el-input v-model="form.thicknessPt" placeholder="请输入测厚点" />
  262. </el-form-item>
  263. </el-col>
  264. </el-row>
  265. <el-row :gutter="20">
  266. <el-col :span="24">
  267. <el-form-item label="部件描述" prop="compoDesc">
  268. <el-input v-model="form.compoDesc" type="textarea" :rows="1" placeholder="请输入部件描述" />
  269. </el-form-item>
  270. </el-col>
  271. </el-row>
  272. <el-row :gutter="20">
  273. <el-col :span="24">
  274. <el-form-item label="部件照片" prop="compoPhoto">
  275. <el-upload
  276. class="upload-demo"
  277. :action="uploadPhoto.url"
  278. :headers="uploadPhoto.headers"
  279. :data="uploadPhoto.data"
  280. :on-success="handlePhotoSuccess"
  281. :on-remove="handleRemovePhoto"
  282. :before-upload="beforePhotoUpload"
  283. :file-list="photoFileList"
  284. :limit="1"
  285. list-type="picture-card"
  286. :on-exceed="handleExceedPhoto"
  287. accept="image/*">
  288. <i class="el-icon-plus"></i>
  289. <div slot="tip" class="el-upload__tip">只能上传jpg/png/gif文件,且不超过15MB</div>
  290. </el-upload>
  291. </el-form-item>
  292. </el-col>
  293. </el-row>
  294. <el-row :gutter="20">
  295. <el-col :span="24">
  296. <el-form-item label="备注" prop="remarks">
  297. <el-input v-model="form.remarks" type="textarea" :rows="1" placeholder="请输入备注" />
  298. </el-form-item>
  299. </el-col>
  300. </el-row>
  301. </div>
  302. <!-- 维修策略 -->
  303. <div class="form-section">
  304. <div class="section-header">
  305. <i class="el-icon-setting"></i>
  306. <span class="section-title">维修策略</span>
  307. </div>
  308. <el-row :gutter="20">
  309. <el-col :span="12">
  310. <el-form-item label="检查人" prop="inspector">
  311. <el-select v-model="form.inspector" placeholder="请选择检查人" clearable filterable style="width: 100%">
  312. <el-option
  313. v-for="staff in staffOptions"
  314. :key="staff.id"
  315. :label="staff.name"
  316. :value="staff.staffid">
  317. </el-option>
  318. </el-select>
  319. </el-form-item>
  320. </el-col>
  321. <el-col :span="12">
  322. <el-form-item label="维修更换人" prop="fixer">
  323. <el-select v-model="form.fixer" placeholder="请选择维修更换人" clearable filterable style="width: 100%">
  324. <el-option
  325. v-for="staff in staffOptions"
  326. :key="staff.id + '_fixer'"
  327. :label="staff.name"
  328. :value="staff.staffid">
  329. </el-option>
  330. </el-select>
  331. </el-form-item>
  332. </el-col>
  333. </el-row>
  334. <el-row :gutter="20">
  335. <el-col :span="24">
  336. <el-form-item label="检查频率" prop="inspFreq">
  337. <div style="display: flex; gap: 8px; align-items: center; width: 300px;">
  338. <el-input-number
  339. v-model="inspFreqNumber"
  340. :min="1"
  341. :max="100"
  342. controls-position="right"
  343. style="width: 130px; flex-shrink: 0;"
  344. placeholder="次数"
  345. @change="updateInspFreq" />
  346. <el-select v-model="inspFreqUnit" placeholder="单位" style="width: 130px; flex-shrink: 0;" @change="updateInspFreq" popper-append-to-body>
  347. <el-option label="年(y)" value="y"></el-option>
  348. <el-option label="月(m)" value="m"></el-option>
  349. </el-select>
  350. </div>
  351. </el-form-item>
  352. </el-col>
  353. </el-row>
  354. <el-row :gutter="20">
  355. <el-col :span="24">
  356. <el-form-item label="检查内容" prop="inspContent">
  357. <el-input v-model="form.inspContent" type="textarea" :rows="1" placeholder="请输入检查内容" />
  358. </el-form-item>
  359. </el-col>
  360. </el-row>
  361. <el-row :gutter="20">
  362. <el-col :span="24">
  363. <el-form-item label="维修频率" prop="fixFreq">
  364. <div style="display: flex; gap: 8px; align-items: center; width: 300px;">
  365. <el-input-number
  366. v-model="fixFreqNumber"
  367. :min="1"
  368. :max="100"
  369. controls-position="right"
  370. style="width: 130px; flex-shrink: 0;"
  371. placeholder="次数"
  372. @change="updateFixFreq" />
  373. <el-select v-model="fixFreqUnit" placeholder="单位" style="width: 130px; flex-shrink: 0;" @change="updateFixFreq" popper-append-to-body>
  374. <el-option label="年(y)" value="y"></el-option>
  375. <el-option label="月(m)" value="m"></el-option>
  376. </el-select>
  377. </div>
  378. </el-form-item>
  379. </el-col>
  380. </el-row>
  381. <el-row :gutter="20">
  382. <el-col :span="24">
  383. <el-form-item label="维修内容" prop="fixContent">
  384. <el-input v-model="form.fixContent" type="textarea" :rows="1" placeholder="请输入维修内容" />
  385. </el-form-item>
  386. </el-col>
  387. </el-row>
  388. <el-row :gutter="20">
  389. <el-col :span="24">
  390. <el-form-item label="更换频率" prop="replaceFreq">
  391. <div style="display: flex; gap: 8px; align-items: center; width: 300px;">
  392. <el-input-number
  393. v-model="replaceFreqNumber"
  394. :min="1"
  395. :max="100"
  396. controls-position="right"
  397. style="width: 130px; flex-shrink: 0;"
  398. placeholder="次数"
  399. @change="updateReplaceFreq" />
  400. <el-select v-model="replaceFreqUnit" placeholder="单位" style="width: 130px; flex-shrink: 0;" @change="updateReplaceFreq" popper-append-to-body>
  401. <el-option label="年(y)" value="y"></el-option>
  402. <el-option label="月(m)" value="m"></el-option>
  403. </el-select>
  404. </div>
  405. </el-form-item>
  406. </el-col>
  407. </el-row>
  408. <el-row :gutter="20">
  409. <el-col :span="24">
  410. <el-form-item label="更换内容" prop="replaceContent">
  411. <el-input v-model="form.replaceContent" type="textarea" :rows="1" placeholder="请输入更换内容" />
  412. </el-form-item>
  413. </el-col>
  414. </el-row>
  415. </div>
  416. </el-form>
  417. <div slot="footer" class="dialog-footer">
  418. <el-button type="primary" @click="submitForm">确 定</el-button>
  419. <el-button @click="cancel">取 消</el-button>
  420. </div>
  421. </el-dialog>
  422. <!-- 用户导入对话框 -->
  423. <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
  424. <el-upload
  425. ref="upload"
  426. :limit="1"
  427. accept=".xlsx, .xls"
  428. :headers="upload.headers"
  429. :action="upload.url + '?updateSupport=1'"
  430. :disabled="upload.isUploading"
  431. :on-progress="handleFileUploadProgress"
  432. :on-success="handleFileSuccess"
  433. :auto-upload="false"
  434. drag
  435. >
  436. <i class="el-icon-upload"></i>
  437. <div class="el-upload__text">
  438. 将文件拖到此处,或
  439. <em>点击上传</em>
  440. </div>
  441. <div class="el-upload__tip" slot="tip">
  442. <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
  443. <form ref="downloadFileForm" :action="upload.downloadAction" target="FORMSUBMIT">
  444. <input name="type" :value="upload.type" hidden/>
  445. </form>
  446. </div>
  447. <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
  448. </el-upload>
  449. <div slot="footer" class="dialog-footer">
  450. <el-button type="primary" @click="submitFileForm">确 定</el-button>
  451. <el-button @click="upload.open = false">取 消</el-button>
  452. </div>
  453. </el-dialog>
  454. <!-- 图片预览对话框 -->
  455. <el-dialog title="查看照片" :visible.sync="photoPreviewVisible" width="800px" append-to-body>
  456. <div class="photo-preview-container">
  457. <img :src="previewPhotoUrl" alt="部件照片" style="width: 100%; height: auto;">
  458. </div>
  459. </el-dialog>
  460. </div>
  461. </template>
  462. <script>
  463. import { listRel_compo, getRel_compo, delRel_compo, addRel_compo, updateRel_compo, exportRel_compo, importTemplate} from "@/api/reliability/rel_compo";
  464. import { treeselect } from "@/api/system/dept";
  465. import { listStaffmgrAll } from "@/api/plant/staffmgr";
  466. import { getToken } from "@/utils/auth";
  467. import Treeselect from "@riophae/vue-treeselect";
  468. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  469. export default {
  470. name: "Rel_compo",
  471. components: { Treeselect },
  472. data() {
  473. return {
  474. // 遮罩层
  475. loading: true,
  476. // 选中数组
  477. ids: [],
  478. // 非单个禁用
  479. single: true,
  480. // 非多个禁用
  481. multiple: true,
  482. // 显示搜索条件
  483. showSearch: false,
  484. // 总条数
  485. total: 0,
  486. // 可靠性部件清单表格数据
  487. rel_compoList: [],
  488. // 弹出层标题
  489. title: "",
  490. // 部门树选项
  491. deptOptions: undefined,
  492. // 人员列表选项
  493. staffOptions: [],
  494. clientHeight:300,
  495. // 是否显示弹出层
  496. open: false,
  497. // 用户导入参数
  498. upload: {
  499. //下载模板请求地址
  500. downloadAction: process.env.VUE_APP_BASE_API + '/common/template',
  501. //下载模板类型
  502. type: 'rel_compo',
  503. // 是否显示弹出层(用户导入)
  504. open: false,
  505. // 弹出层标题(用户导入)
  506. title: "",
  507. // 是否禁用上传
  508. isUploading: false,
  509. // 设置上传的请求头部
  510. headers: { Authorization: "Bearer " + getToken() },
  511. // 上传的地址
  512. url: process.env.VUE_APP_BASE_API + "/reliability/rel_compo/importData"
  513. },
  514. // 部件照片上传参数
  515. uploadPhoto: {
  516. // 设置上传的请求头部
  517. headers: { Authorization: "Bearer " + getToken() },
  518. // 上传的地址(使用支持自定义路径的接口)
  519. url: process.env.VUE_APP_BASE_API + "/common/uploadWithPath",
  520. // 上传路径参数
  521. data: { path: "/rel/compo" }
  522. },
  523. // 部件照片文件列表
  524. photoFileList: [],
  525. // 图片预览相关
  526. photoPreviewVisible: false,
  527. previewPhotoUrl: '',
  528. // 频率拆分数据
  529. inspFreqNumber: null,
  530. inspFreqUnit: 'y',
  531. fixFreqNumber: null,
  532. fixFreqUnit: 'y',
  533. replaceFreqNumber: null,
  534. replaceFreqUnit: 'y',
  535. // 查询参数
  536. queryParams: {
  537. pageNum: 1,
  538. pageSize: 20,
  539. plant: null,
  540. devLoc: null,
  541. devTag: null,
  542. compoName: null,
  543. compoModel: null,
  544. thicknessPt: null,
  545. compoDesc: null,
  546. compoPhoto: null,
  547. inspector: null,
  548. fixer: null,
  549. inspFreq: null,
  550. inspContent: null,
  551. lastInspDate: null,
  552. fixFreq: null,
  553. fixContent: null,
  554. lastFixDate: null,
  555. replaceFreq: null,
  556. replaceContent: null,
  557. lastReplaceDate: null,
  558. nextMaintDate: null,
  559. nextMaintType: null,
  560. createrCode: null,
  561. createdate: null,
  562. updaterCode: null,
  563. updatedate: null,
  564. deptId: null,
  565. remarks: null
  566. },
  567. // 表单参数
  568. form: {},
  569. // 表单校验
  570. rules: {
  571. compoName: [
  572. { required: true, message: "部件名称不能为空", trigger: "blur" }
  573. ],
  574. }
  575. };
  576. },
  577. watch: {
  578. // 根据名称筛选部门树
  579. deptName(val) {
  580. this.$refs.tree.filter(val);
  581. }
  582. },
  583. created() {
  584. //设置表格高度对应屏幕高度
  585. this.$nextTick(() => {
  586. this.clientHeight = document.body.clientHeight -250
  587. })
  588. this.getList();
  589. this.getTreeselect();
  590. this.getStaffList();
  591. },
  592. methods: {
  593. /** 查询可靠性部件清单列表 */
  594. getList() {
  595. this.loading = true;
  596. listRel_compo(this.queryParams).then(response => {
  597. this.rel_compoList = response.rows;
  598. this.total = response.total;
  599. this.loading = false;
  600. });
  601. },
  602. /** 查询部门下拉树结构 */
  603. getTreeselect() {
  604. treeselect().then(response => {
  605. this.deptOptions = response.data;
  606. });
  607. },
  608. /** 查询人员列表 */
  609. getStaffList() {
  610. listStaffmgrAll().then(response => {
  611. this.staffOptions = response.rows || response.data || [];
  612. });
  613. },
  614. // 取消按钮
  615. cancel() {
  616. this.open = false;
  617. this.reset();
  618. },
  619. // 表单重置
  620. reset() {
  621. this.form = {
  622. compoId: null,
  623. plant: null,
  624. devLoc: null,
  625. devTag: null,
  626. compoName: null,
  627. compoModel: null,
  628. thicknessPt: null,
  629. compoDesc: null,
  630. compoPhoto: null,
  631. inspector: null,
  632. fixer: null,
  633. inspFreq: null,
  634. inspContent: null,
  635. lastInspDate: null,
  636. fixFreq: null,
  637. fixContent: null,
  638. lastFixDate: null,
  639. replaceFreq: null,
  640. replaceContent: null,
  641. lastReplaceDate: null,
  642. nextMaintDate: null,
  643. nextMaintType: null,
  644. delFlag: null,
  645. createrCode: null,
  646. createdate: null,
  647. updaterCode: null,
  648. updatedate: null,
  649. deptId: null,
  650. remarks: null
  651. };
  652. this.photoFileList = [];
  653. // 重置频率拆分字段
  654. this.inspFreqNumber = null;
  655. this.inspFreqUnit = 'y';
  656. this.fixFreqNumber = null;
  657. this.fixFreqUnit = 'y';
  658. this.replaceFreqNumber = null;
  659. this.replaceFreqUnit = 'y';
  660. this.resetForm("form");
  661. },
  662. /** 搜索按钮操作 */
  663. handleQuery() {
  664. this.queryParams.pageNum = 1;
  665. this.getList();
  666. },
  667. /** 重置按钮操作 */
  668. resetQuery() {
  669. this.resetForm("queryForm");
  670. this.handleQuery();
  671. },
  672. // 多选框选中数据
  673. handleSelectionChange(selection) {
  674. this.ids = selection.map(item => item.compoId)
  675. this.single = selection.length!==1
  676. this.multiple = !selection.length
  677. },
  678. /** 新增按钮操作 */
  679. handleAdd() {
  680. this.reset();
  681. // 设置频率默认值
  682. this.updateInspFreq();
  683. this.updateFixFreq();
  684. this.updateReplaceFreq();
  685. this.open = true;
  686. this.title = "添加可靠性部件清单";
  687. },
  688. /** 修改按钮操作 */
  689. handleUpdate(row) {
  690. this.reset();
  691. const compoId = row.compoId || this.ids
  692. getRel_compo(compoId).then(response => {
  693. this.form = response.data;
  694. // 如果有照片,加载到文件列表
  695. if (this.form.compoPhoto) {
  696. // 如果是相对路径,需要拼接完整URL
  697. let imageUrl = this.form.compoPhoto;
  698. if (imageUrl && !imageUrl.startsWith('http')) {
  699. imageUrl = process.env.VUE_APP_BASE_API + imageUrl;
  700. }
  701. this.photoFileList = [{
  702. name: '部件照片',
  703. url: imageUrl
  704. }];
  705. console.log('加载图片URL:', imageUrl);
  706. }
  707. // 解析频率字段
  708. this.parseFrequency(this.form.inspFreq, 'insp');
  709. this.parseFrequency(this.form.fixFreq, 'fix');
  710. this.parseFrequency(this.form.replaceFreq, 'replace');
  711. this.open = true;
  712. this.title = "修改可靠性部件清单";
  713. });
  714. },
  715. /** 提交按钮 */
  716. submitForm() {
  717. this.$refs["form"].validate(valid => {
  718. if (valid) {
  719. if (this.form.compoId != null) {
  720. updateRel_compo(this.form).then(response => {
  721. this.msgSuccess("修改成功");
  722. this.open = false;
  723. this.getList();
  724. });
  725. } else {
  726. addRel_compo(this.form).then(response => {
  727. this.msgSuccess("新增成功");
  728. this.open = false;
  729. this.getList();
  730. });
  731. }
  732. }
  733. });
  734. },
  735. /** 删除按钮操作 */
  736. handleDelete(row) {
  737. const compoIds = row.compoId || this.ids;
  738. this.$confirm('是否确认删除?', "警告", {
  739. confirmButtonText: "确定",
  740. cancelButtonText: "取消",
  741. type: "warning"
  742. }).then(function() {
  743. return delRel_compo(compoIds);
  744. }).then(() => {
  745. this.getList();
  746. this.msgSuccess("删除成功");
  747. })
  748. },
  749. /** 导出按钮操作 */
  750. handleExport() {
  751. const queryParams = this.queryParams;
  752. this.$confirm('是否确认导出所有可靠性部件清单数据项?', "警告", {
  753. confirmButtonText: "确定",
  754. cancelButtonText: "取消",
  755. type: "warning"
  756. }).then(function() {
  757. return exportRel_compo(queryParams);
  758. }).then(response => {
  759. this.download(response.msg);
  760. })
  761. },
  762. /** 导入按钮操作 */
  763. handleImport() {
  764. this.upload.title = "用户导入";
  765. this.upload.open = true;
  766. },
  767. /** 下载模板操作 */
  768. importTemplate() {
  769. this.$refs['downloadFileForm'].submit()
  770. },
  771. // 文件上传中处理
  772. handleFileUploadProgress(event, file, fileList) {
  773. this.upload.isUploading = true;
  774. },
  775. // 文件上传成功处理
  776. handleFileSuccess(response, file, fileList) {
  777. this.upload.open = false;
  778. this.upload.isUploading = false;
  779. this.$refs.upload.clearFiles();
  780. this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
  781. this.getList();
  782. },
  783. // 提交上传文件
  784. submitFileForm() {
  785. this.$refs.upload.submit();
  786. },
  787. /** 上传前的校验 */
  788. beforePhotoUpload(file) {
  789. const isImage = file.type.startsWith('image/');
  790. const isLt15M = file.size / 1024 / 1024 < 15;
  791. if (!isImage) {
  792. this.$message.error('只能上传图片文件!');
  793. return false;
  794. }
  795. if (!isLt15M) {
  796. this.$message.error('上传图片大小不能超过 15MB!');
  797. return false;
  798. }
  799. return true;
  800. },
  801. /** 图片上传成功回调 */
  802. handlePhotoSuccess(response, file, fileList) {
  803. console.log('上传接口返回数据:', response);
  804. // 若依框架上传接口返回格式
  805. if (response && response.fileName) {
  806. // 保存文件路径到表单(相对路径)
  807. this.form.compoPhoto = response.fileName;
  808. // 构建完整URL用于预览
  809. let imageUrl = response.url || response.fileName;
  810. if (imageUrl && !imageUrl.startsWith('http')) {
  811. imageUrl = process.env.VUE_APP_BASE_API + imageUrl;
  812. }
  813. this.photoFileList = [{
  814. name: file.name,
  815. url: imageUrl
  816. }];
  817. console.log('图片路径已保存到 form.compoPhoto:', this.form.compoPhoto);
  818. console.log('预览URL:', imageUrl);
  819. this.$message.success('上传成功');
  820. } else {
  821. console.error('上传返回数据格式不正确:', response);
  822. this.$message.error(response.msg || '上传失败');
  823. }
  824. },
  825. /** 删除图片 */
  826. handleRemovePhoto(file, fileList) {
  827. this.form.compoPhoto = null;
  828. this.photoFileList = [];
  829. },
  830. /** 超出文件个数限制 */
  831. handleExceedPhoto(files, fileList) {
  832. this.$message.warning('只能上传1张图片');
  833. },
  834. /** 查看图片 */
  835. handleViewPhoto(photoPath) {
  836. if (photoPath) {
  837. // 如果是相对路径,拼接完整URL
  838. let imageUrl = photoPath;
  839. if (imageUrl && !imageUrl.startsWith('http')) {
  840. imageUrl = process.env.VUE_APP_BASE_API + imageUrl;
  841. }
  842. this.previewPhotoUrl = imageUrl;
  843. this.photoPreviewVisible = true;
  844. }
  845. },
  846. /** 根据人员ID获取人员姓名 */
  847. getStaffName(staffId) {
  848. if (!staffId) return '-';
  849. const staff = this.staffOptions.find(s => s.staffid === staffId);
  850. return staff ? staff.name : staffId;
  851. },
  852. /** 更新检查频率 */
  853. updateInspFreq() {
  854. if (this.inspFreqNumber && this.inspFreqUnit) {
  855. this.form.inspFreq = this.inspFreqNumber + this.inspFreqUnit;
  856. } else if (this.inspFreqUnit) {
  857. // 如果只有单位没有数字,使用默认值1
  858. this.form.inspFreq = '1' + this.inspFreqUnit;
  859. } else {
  860. this.form.inspFreq = null;
  861. }
  862. },
  863. /** 更新维修频率 */
  864. updateFixFreq() {
  865. if (this.fixFreqNumber && this.fixFreqUnit) {
  866. this.form.fixFreq = this.fixFreqNumber + this.fixFreqUnit;
  867. } else if (this.fixFreqUnit) {
  868. // 如果只有单位没有数字,使用默认值1
  869. this.form.fixFreq = '1' + this.fixFreqUnit;
  870. } else {
  871. this.form.fixFreq = null;
  872. }
  873. },
  874. /** 更新更换频率 */
  875. updateReplaceFreq() {
  876. if (this.replaceFreqNumber && this.replaceFreqUnit) {
  877. this.form.replaceFreq = this.replaceFreqNumber + this.replaceFreqUnit;
  878. } else if (this.replaceFreqUnit) {
  879. // 如果只有单位没有数字,使用默认值1
  880. this.form.replaceFreq = '1' + this.replaceFreqUnit;
  881. } else {
  882. this.form.replaceFreq = null;
  883. }
  884. },
  885. /** 解析频率字符串 */
  886. parseFrequency(freqStr, type) {
  887. // 匹配数字和单位,如 "12y", "6m"
  888. const match = freqStr ? freqStr.match(/^(\d+)([ym])$/) : null;
  889. if (match) {
  890. const number = parseInt(match[1]);
  891. const unit = match[2];
  892. if (type === 'insp') {
  893. this.inspFreqNumber = number;
  894. this.inspFreqUnit = unit;
  895. } else if (type === 'fix') {
  896. this.fixFreqNumber = number;
  897. this.fixFreqUnit = unit;
  898. } else if (type === 'replace') {
  899. this.replaceFreqNumber = number;
  900. this.replaceFreqUnit = unit;
  901. }
  902. } else {
  903. // 没有值时设置默认值
  904. if (type === 'insp') {
  905. this.inspFreqNumber = 1;
  906. this.inspFreqUnit = 'y';
  907. } else if (type === 'fix') {
  908. this.fixFreqNumber = 1;
  909. this.fixFreqUnit = 'y';
  910. } else if (type === 'replace') {
  911. this.replaceFreqNumber = 1;
  912. this.replaceFreqUnit = 'y';
  913. }
  914. }
  915. },
  916. /** 翻译频率字段 */
  917. translateFrequency(frequency) {
  918. if (!frequency) return '';
  919. // 匹配数字和单位
  920. const match = frequency.match(/^(\d+)([ym])$/);
  921. if (match) {
  922. const number = match[1];
  923. const unit = match[2];
  924. switch (unit) {
  925. case 'y':
  926. return `${number}年一次`;
  927. case 'm':
  928. return `${number}月一次`;
  929. default:
  930. return frequency;
  931. }
  932. }
  933. return frequency;
  934. }
  935. }
  936. };
  937. </script>
  938. <style scoped>
  939. /* 表单分区样式 */
  940. .form-section {
  941. margin-bottom: 30px;
  942. padding: 20px;
  943. background: #f8f9fa;
  944. border-radius: 8px;
  945. border: 1px solid #e9ecef;
  946. }
  947. .form-section:last-of-type {
  948. margin-bottom: 0;
  949. }
  950. .section-header {
  951. display: flex;
  952. align-items: center;
  953. margin-bottom: 20px;
  954. padding-bottom: 12px;
  955. border-bottom: 2px solid #409eff;
  956. }
  957. .section-header i {
  958. font-size: 20px;
  959. color: #409eff;
  960. margin-right: 8px;
  961. }
  962. .section-title {
  963. font-size: 16px;
  964. font-weight: 600;
  965. color: #303133;
  966. }
  967. /* 对话框样式 */
  968. .compo-dialog >>> .el-dialog__body {
  969. padding: 20px 30px;
  970. max-height: 70vh;
  971. overflow-y: auto;
  972. }
  973. .compo-dialog >>> .el-form-item {
  974. margin-bottom: 18px;
  975. }
  976. .compo-dialog >>> .el-form-item__label {
  977. font-weight: 500;
  978. color: #606266;
  979. }
  980. /* 上传组件样式 */
  981. .upload-demo >>> .el-upload--picture-card {
  982. width: 148px;
  983. height: 148px;
  984. line-height: 148px;
  985. }
  986. .upload-demo >>> .el-upload-list--picture-card .el-upload-list__item {
  987. width: 148px;
  988. height: 148px;
  989. }
  990. /* Textarea 样式优化 */
  991. .form-section >>> .el-textarea__inner {
  992. resize: vertical;
  993. font-family: inherit;
  994. }
  995. /* 底部按钮样式 */
  996. .dialog-footer {
  997. padding: 15px 20px;
  998. text-align: right;
  999. border-top: 1px solid #e9ecef;
  1000. }
  1001. .dialog-footer .el-button {
  1002. min-width: 80px;
  1003. }
  1004. </style>