DeviceConfig.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. <!-- 步骤1 设备基本信息 -->
  2. <template>
  3. <div v-show="currentStep==0" :class="className">
  4. <div class="form-title">设备基本信息</div>
  5. <div class="form-sub-title">
  6. 带*为必填项
  7. </div>
  8. <!--
  9. <div class="device-name">
  10. <div class="lable-title"><span>*</span>设备名称</div>
  11. <div class="lable">
  12. <el-input
  13. v-model="requestData.name"
  14. placeholder="请输入设备名称"
  15. clearable
  16. maxlength="32"
  17. />
  18. </div>
  19. </div>
  20. -->
  21. <div class="device-sn">
  22. <div class="lable-title"><span>*</span>设备编号</div>
  23. <div class="lable">
  24. <el-input
  25. v-model="requestData.serialNumber"
  26. placeholder="请输入设备编号"
  27. clearable
  28. maxlength="32"
  29. />
  30. </div>
  31. </div>
  32. <div class="device-detail">
  33. <div class="left">
  34. <!--
  35. <div class="check-date">
  36. <div class="lable-title"><span>*</span>送检时间</div>
  37. <div class="lable">
  38. <el-date-picker
  39. v-model="requestData.submitDate"
  40. type="date"
  41. start-placeholder="开始日期"
  42. end-placeholder="结束日期"
  43. format="yyyy/MM/dd"
  44. value-format="yyyy-MM-dd"
  45. />
  46. </div>
  47. </div>
  48. <div class="check-factory">
  49. <div class="lable-title"><span>*</span>送检厂家</div>
  50. <div class="lable">
  51. <el-input
  52. v-model="requestData.vendorName"
  53. placeholder="请输入送检厂家"
  54. clearable
  55. maxlength="32"
  56. />
  57. </div>
  58. </div>
  59. <div class="device-model">
  60. <div class="lable-title"><span>*</span>设备型号</div>
  61. <div class="lable">
  62. <el-input
  63. v-model="requestData.modelName"
  64. placeholder="请输入设备型号"
  65. clearable
  66. maxlength="32"
  67. />
  68. </div>
  69. </div>
  70. <div class="device-productionDate">
  71. <div class="lable-title"><span>*</span>出厂日期</div>
  72. <div class="lable">
  73. <el-date-picker
  74. v-model="requestData.reportDate"
  75. type="date"
  76. start-placeholder="开始日期"
  77. end-placeholder="结束日期"
  78. format="yyyy/MM/dd"
  79. value-format="yyyy-MM-dd"
  80. />
  81. </div>
  82. </div>
  83. <div class="protocol-value">
  84. <div class="lable-title"><span>*</span>设备类型</div>
  85. <div class="lable">
  86. <el-select v-model="requestData.productType" filterable placeholder="请选择">
  87. <el-option
  88. v-for="item in options.deviceProtocolOptions"
  89. :key="item.id"
  90. :label="item.name"
  91. :value="item.id"
  92. />
  93. </el-select>
  94. </div>
  95. </div>-->
  96. </div>
  97. <div class="right">
  98. <div v-if="requestData.productType=='MODBUS_RTU'" class="device-com">
  99. <div class="lable-title">串口</div>
  100. <div class="lable">
  101. <el-select v-model="requestData.devName" filterable placeholder="请选择串口">
  102. <el-option
  103. v-for="item in options.deviceComOptions"
  104. :key="item.id"
  105. :label="item.id"
  106. :value="item.id"
  107. />
  108. </el-select>
  109. </div>
  110. </div>
  111. <div v-if="requestData.productType=='MODBUS_RTU'" class="device-baud">
  112. <div class="lable-title">波特率</div>
  113. <div class="lable">
  114. <el-select v-model="requestData.baudRate" filterable placeholder="请选择波特率">
  115. <el-option
  116. v-for="item in options.deviceBaudOptions"
  117. :key="item.id"
  118. :label="item.name"
  119. :value="item.id"
  120. />
  121. </el-select>
  122. </div>
  123. </div>
  124. <div v-if="requestData.productType=='MODBUS_RTU'" class="device-checkbit">
  125. <div class="lable-title">校验位</div>
  126. <div class="lable">
  127. <el-select v-model="requestData.parity" filterable placeholder="请选择校验位">
  128. <el-option
  129. v-for="item in options.deviceCheckbitOptions"
  130. :key="item.id"
  131. :label="item.name"
  132. :value="item.id"
  133. />
  134. </el-select>
  135. </div>
  136. </div>
  137. <div v-if="requestData.productType=='MQTT'" class="device-model">
  138. <div class="lable-title">订阅主题</div>
  139. <div class="lable">
  140. <el-input
  141. v-model="requestData.topic"
  142. placeholder="请输入订阅主题"
  143. clearable
  144. />
  145. </div>
  146. </div>
  147. <div v-if="requestData.productType=='MQTT'" class="device-model">
  148. <div class="lable-title">用户名</div>
  149. <div class="lable">
  150. <el-input
  151. v-model="requestData.username"
  152. placeholder="请输入用户名"
  153. clearable
  154. />
  155. </div>
  156. </div>
  157. <div v-if="requestData.productType=='MQTT'" class="device-model">
  158. <div class="lable-title">密码</div>
  159. <div class="lable">
  160. <el-input
  161. v-model="requestData.password"
  162. placeholder="请输入密码"
  163. clearable
  164. />
  165. </div>
  166. </div>
  167. <div v-if="requestData.productType=='MODBUS_TCP' || requestData.productType=='IEC104' || requestData.productType=='MQTT'" class="device-ip">
  168. <div class="lable-title">IP</div>
  169. <div class="lable">
  170. <el-input
  171. v-model="requestData.ipAddr"
  172. placeholder="请输入IP"
  173. clearable
  174. />
  175. </div>
  176. </div>
  177. <div v-if="requestData.productType=='MODBUS_TCP' || requestData.productType=='IEC104' || requestData.productType=='MQTT'" class="device-port">
  178. <div class="lable-title">端口</div>
  179. <div class="lable">
  180. <el-input-number v-model="requestData.ipPort" controls-position="right" :min="1" :max="65535" @change.native="dpvChange" />
  181. </div>
  182. </div>
  183. <div v-if="requestData.productType=='MODBUS_RTU'" class="device-databit">
  184. <div class="lable-title">数据位</div>
  185. <div class="lable">
  186. <el-select v-model="requestData.dataBits" filterable placeholder="请选择数据位">
  187. <el-option
  188. v-for="item in options.deviceDatabitOptions"
  189. :key="item.id"
  190. :label="item.name"
  191. :value="item.id"
  192. />
  193. </el-select>
  194. </div>
  195. </div>
  196. <div v-if="requestData.productType=='MODBUS_RTU'" class="device-stopbit">
  197. <div class="lable-title">停止位</div>
  198. <div class="lable">
  199. <el-select v-model="requestData.stopBits" filterable placeholder="请选择停止位">
  200. <el-option
  201. v-for="item in options.deviceStopbitOptions"
  202. :key="item.id"
  203. :label="item.name"
  204. :value="item.id"
  205. />
  206. </el-select>
  207. </div>
  208. </div>
  209. <div v-if="requestData.productType=='LOW_POWER'" class="device-model">
  210. <div class="lable-title">eid</div>
  211. <div class="lable">
  212. <el-input
  213. v-model="requestData.eid"
  214. placeholder="请输入eid"
  215. clearable
  216. />
  217. </div>
  218. </div>
  219. <div v-if="requestData.productType=='LOW_POWER'" class="device-model">
  220. <div class="lable-title">设备类型</div>
  221. <div class="lable">
  222. <el-radio-group v-model="requestData.equip_type" @change="$forceUpdate()">
  223. <el-radio :label="0" border>微功耗</el-radio>
  224. <el-radio :label="2" border>低功耗</el-radio>
  225. </el-radio-group>
  226. <!-- <el-input
  227. v-model="requestData.equip_type"
  228. placeholder="请输入设备类型:0为微功耗,2为低功耗。"
  229. clearable
  230. /> -->
  231. </div>
  232. </div>
  233. <div v-if="requestData.productType=='LOW_POWER'" class="device-model">
  234. <div class="lable-title">设备频点</div>
  235. <div class="lable">
  236. <el-input
  237. v-model="requestData.fre_point"
  238. placeholder="请输入 设备频点"
  239. clearable
  240. />
  241. </div>
  242. </div>
  243. <div v-if="requestData.productType=='LOW_POWER'" class="device-model">
  244. <div class="lable-title">上报周期</div>
  245. <div class="lable">
  246. <el-input
  247. v-model="requestData.business_cycle"
  248. placeholder="请输入 上报周期"
  249. clearable
  250. />
  251. </div>
  252. </div>
  253. </div>
  254. </div>
  255. <!--
  256. <div v-if="loadPictures==3" class="photo-list">
  257. <el-row :gutter="20">
  258. <el-col :span="8">
  259. <div class="device-frontphoto">
  260. <div class="lable-title"><span>*</span>设备正面照</div>
  261. <div class="lable">
  262. <upload-photo :key="'photo1-'+photoUpdateKey[1]" :photo-info="{ name: '1', url: deviceDefaultPictures['p1'],size:deviceDefaultSize['p1'] }" @photoChanged="savePhotoData" @delphoto="delphoto" @photoRemoved="removePicture" />
  263. </div>
  264. </div>
  265. </el-col>
  266. <el-col :span="8">
  267. <div class="device-backphoto">
  268. <div class="lable-title"><span>*</span>设备反面照</div>
  269. <div class="lable">
  270. <upload-photo :key="'photo2-'+photoUpdateKey[2]" :photo-info="{ name: '2', url: deviceDefaultPictures['p2'],size:deviceDefaultSize['p2'] }" @delphoto="delphoto" @photoChanged="savePhotoData" @photoRemoved="removePicture" />
  271. </div>
  272. </div>
  273. </el-col>
  274. <el-col :span="8">
  275. <div class="device-plate">
  276. <div class="lable-title"><span>*</span>设备铭牌</div>
  277. <div class="lable">
  278. <upload-photo :key="'photo3-'+photoUpdateKey[3]" :photo-info="{ name: '3', url: deviceDefaultPictures['p3'],size:deviceDefaultSize['p3'] }" @delphoto="delphoto" @photoChanged="savePhotoData" @photoRemoved="removePicture" />
  279. </div>
  280. </div>
  281. </el-col>
  282. </el-row>
  283. </div>
  284. <div v-else class="photo-list">
  285. <el-row :gutter="20">
  286. <el-col :span="8">
  287. <div class="device-frontphoto">
  288. <div class="lable-title">设备正面照</div>
  289. <div class="lable">
  290. 加载中...
  291. </div>
  292. </div>
  293. </el-col>
  294. <el-col :span="8">
  295. <div class="device-backphoto">
  296. <div class="lable-title">设备反面照</div>
  297. <div class="lable">
  298. 加载中...
  299. </div>
  300. </div>
  301. </el-col>
  302. <el-col :span="8">
  303. <div class="device-plate">
  304. <div class="lable-title">设备铭牌</div>
  305. <div class="lable">
  306. 加载中...
  307. </div>
  308. </div>
  309. </el-col>
  310. </el-row>
  311. </div>
  312. -->
  313. <!-- 底部按钮 -->
  314. <div class="bottom-button">
  315. <div class="cancel-device">
  316. <el-button class="light-button" @click="cancelAct">取消</el-button>
  317. </div>
  318. <div class="save-device">
  319. <el-button class="dark-button" @click="submitDeviceConfig()">下一步</el-button>
  320. </div>
  321. <div class="save-device save-btn">
  322. <!-- <el-button class="dark-button " @click="submitDeviceConfig(true)">保存</el-button> -->
  323. </div>
  324. </div>
  325. </div>
  326. </template>
  327. <script>
  328. import { saveDeviceConfig, getDevicePicture, postPicture } from '@/api/device'
  329. import { httpGet } from '@/api/common-action'
  330. // import router from '@/router'
  331. export default {
  332. components: { },
  333. props: {
  334. className: {
  335. type: String,
  336. default: 'steps-bar-default'
  337. },
  338. currentStep: {
  339. type: Number,
  340. default: 1
  341. },
  342. currentDeviceId: {
  343. type: Number,
  344. default: 0
  345. }
  346. },
  347. data() {
  348. return {
  349. requestData: {},
  350. // 默认选项
  351. options: {
  352. deviceComOptions: [],
  353. deviceProtocolOptions: [],
  354. deviceBaudOptions: [],
  355. deviceCheckbitOptions: [],
  356. deviceStopbitOptions: [],
  357. deviceDatabitOptions: []
  358. },
  359. deviceCheckId: 0,
  360. // 设备照片上传暂存文件
  361. devicePictureUploads: [],
  362. // 获取默认图片
  363. deviceDefaultPictures: {},
  364. // 照片加载状态 true 加载完毕 false 加载中
  365. loadPictures: 0,
  366. photoUpdateKey: [0, 0, 0],
  367. deviceDefaultSize: [],
  368. // 需要删除的图片编号数组
  369. delPhotoArr: []
  370. }
  371. },
  372. computed: {
  373. // LOW_POWER MODBUS_RTU MODBUS_RTU IEC104 MQTT
  374. },
  375. mounted() {
  376. this.$nextTick(() => {
  377. // 网页加载完成后执行
  378. // 获取当前 检测设备id
  379. this.deviceCheckId = this.$route.query.deviceCheckId || 0
  380. // console.log('this.deviceCheckId=', this.deviceCheckId)
  381. // 获取选项
  382. this.options.deviceProtocolOptions = JSON.parse(localStorage.getItem('dictDeviceProductType'))
  383. // 获取默认值
  384. this.options.deviceBaudOptions = JSON.parse(localStorage.getItem('deviceBaudOptions'))
  385. this.options.deviceCheckbitOptions = JSON.parse(localStorage.getItem('deviceCheckbitOptions'))
  386. this.options.deviceStopbitOptions = JSON.parse(localStorage.getItem('deviceStopbitOptions'))
  387. this.options.deviceDatabitOptions = JSON.parse(localStorage.getItem('deviceDatabitOptions'))
  388. this.initFunctions()
  389. // console.log('this.options.deviceDatabitOptions=', this.options.deviceDatabitOptions)
  390. })
  391. },
  392. methods: {
  393. // 初始化
  394. async initFunctions() {
  395. //
  396. // swagger 上面 获取串口选项 /dict/serial/options
  397. httpGet('/dict/serial/options').then(response => {
  398. this.requestData.deviceComOptions = response
  399. // console.log('getOptions /channel/serials response=', response)
  400. }).catch(err => {
  401. console.log('获取串口选项 httpGet err rs=', err)
  402. this.$message({
  403. message: '获取选项失败',
  404. type: 'error',
  405. offset: window.screen.height / 3
  406. })
  407. })
  408. // console.log('默认协议 this.deviceProtocolOptions=', this.requestData.deviceProtocolOptions)
  409. // 如果 当前设备 id 有值 ,则根据设备id获取设备基本信息
  410. if (this.deviceCheckId > 0) {
  411. // 查看检测设备 接口 /test/project/:project
  412. httpGet(`/test/project/${this.deviceCheckId}`).then(response => {
  413. this.requestData = response
  414. this.requestData.equip_type = 0
  415. // console.log('查看检测设备 this.requestData=', this.requestData)
  416. // 获取默认图片
  417. for (let index = 1; index <= 3; index++) {
  418. getDevicePicture(this.deviceCheckId, index).then(res => {
  419. // console.log('getDevicePicture res=', res.size)
  420. // 正面照
  421. const myBlob = new window.Blob([res], { type: 'image/png' })
  422. const imgUrl = window.URL.createObjectURL(myBlob)
  423. this.deviceDefaultSize['p' + index] = res.size
  424. if (res.size !== 0) {
  425. this.deviceDefaultPictures['p' + index] = imgUrl
  426. }
  427. // console.log('getDevicePicture loadPictures=', loadPictures)
  428. // console.log('getDevicePicture index=', index)
  429. this.$forceUpdate()
  430. }).finally(
  431. () => {
  432. // 此处 this.loadPictures 仅用于判断 照片组件是否显示
  433. // 所以只要请求了一次就 +1
  434. this.loadPictures = this.loadPictures + 1
  435. }
  436. )
  437. }
  438. })
  439. } else {
  440. this.loadPictures = 3
  441. if (this.options.deviceProtocolOptions.length > 0) {
  442. this.requestData.productType = this.options.deviceProtocolOptions[1].id
  443. this.requestData.ipAddr = '127.0.0.1'
  444. this.requestData.ipPort = '12701'
  445. }
  446. }
  447. },
  448. // 端口改变
  449. dpvChange(oldV, newV) {
  450. if (newV < 1) {
  451. this.requestData.devicePortValue = oldV
  452. } else if (newV > 65535) {
  453. this.requestData.devicePortValue = oldV
  454. }
  455. },
  456. // 暂存图片数据
  457. savePhotoData(file, photoName) {
  458. // #TODO:这里这两个变量可以合成一个,以后再搞
  459. this.devicePictureUploads[photoName] = file
  460. this.deviceDefaultPictures['p' + photoName] = file.url
  461. },
  462. // 删除照片
  463. removePicture(photoName) {
  464. delete this.deviceDefaultPictures['p' + photoName]
  465. this.delPhotoArr.push(photoName)
  466. // console.log('thisdeviceDefaultPictures', this.deviceDefaultPictures)
  467. this.photoUpdateKey[photoName] = new Date().getTime()
  468. this.$forceUpdate()
  469. },
  470. // 删除未保存图片
  471. delphoto(photoName) {
  472. delete this.deviceDefaultPictures['p' + photoName]
  473. // console.log('thisdeviceDefaultPictures', this.deviceDefaultPictures)
  474. },
  475. // 取消
  476. cancelAct() {
  477. this.$router.push({ path: '/device/index' })
  478. },
  479. // 提交设备基本信息
  480. submitDeviceConfig() {
  481. if (
  482. this.isNull(this.requestData.serialNumber, '请输入设备编号')
  483. ) {
  484. // 如果有任何一个值为空,则直接返回,不提交数据
  485. return
  486. }
  487. const deviceSubmitData = this.clearSubmitData(this.requestData)
  488. // console.log('submitDeviceConfig deviceSubmitData = ', deviceSubmitData)
  489. deviceSubmitData.id = this.currentDeviceId || null
  490. deviceSubmitData.devName = this.devName || '/dev/ttyUSB0'
  491. // 参数合法,数据提交到后端,到下一步
  492. saveDeviceConfig(deviceSubmitData).then(response => {
  493. this.$emit('changeDeviceId', response.id * 1)
  494. // 到下一步
  495. let currentStep = this.currentStep
  496. if (currentStep < 2) {
  497. currentStep = currentStep + 1
  498. this.$emit('changeStep', currentStep)
  499. } else {
  500. // 已经是最后一步了
  501. this.$message({
  502. message: '已经是最后一步了',
  503. type: 'error',
  504. offset: window.screen.height / 3
  505. })
  506. }
  507. })
  508. },
  509. // 提交照片
  510. submitPhoto(picFile, photoName, deviceCheckId) {
  511. const formData = new FormData()
  512. formData.append('file', picFile.raw)
  513. // console.log('formData=', formData)
  514. // 上传新图片
  515. postPicture(deviceCheckId, photoName, formData).then(response => {
  516. // console.log('postPicture response=', response)
  517. // console.log('上传了photo', photoName)
  518. }).catch((e) => {
  519. // console.log('e', e)
  520. })
  521. },
  522. // 清理多余数据参数,避免提交时报错
  523. clearSubmitData(data) {
  524. if (data.code) {
  525. delete data.code
  526. }
  527. // if (data.code) {
  528. // delete data.code
  529. // }
  530. return data
  531. },
  532. // 检查必填项 是否为空
  533. isNull(val, msg) {
  534. msg = msg || '请输入必填项'
  535. if (!val) {
  536. this.$message({
  537. message: msg,
  538. type: 'error',
  539. offset: window.screen.height / 3
  540. })
  541. return true
  542. } else {
  543. return false
  544. }
  545. }
  546. }
  547. }
  548. </script>
  549. <style lang="scss" scoped>
  550. .el-input{
  551. width: 100%;
  552. }
  553. .device-config {
  554. // border: 1px #f00 solid;
  555. text-align: center;
  556. font-size: 16px;
  557. width: 50%;
  558. margin: 0 auto;
  559. .device-detail {
  560. display: flex;
  561. .left, .right {
  562. width: 50%;
  563. }
  564. .left {
  565. padding-right: 20px;
  566. .protocol-value {
  567. // 隐藏设备类型输入框
  568. // 聊天记录关键词:好的,我先用css控制隐藏了
  569. display: none;
  570. }
  571. }
  572. .right {
  573. padding-left: 20px;
  574. // 隐藏设备类型输入框
  575. // 聊天记录关键词:好的,我先用css控制隐藏了
  576. display: none;
  577. }
  578. }
  579. .form-title {
  580. font-size: 20px;
  581. font-weight: bold;
  582. }
  583. .form-sub-title {
  584. font-size: 14px;
  585. padding-top: 4px;
  586. padding-bottom: 20px;
  587. }
  588. .form-sub-title,span {
  589. color: #FF5732;
  590. }
  591. .lable-title {
  592. text-align: left;
  593. padding-bottom: 10px;
  594. color: #707070;
  595. }
  596. .lable {
  597. padding-bottom: 20px;
  598. text-align: left;
  599. .el-select {
  600. width: 100%;
  601. }
  602. }
  603. // 底部按钮
  604. .bottom-button {
  605. display: flex;
  606. justify-content: center;
  607. padding-bottom: 20px;
  608. .cancel-device {
  609. padding-right: 20px;
  610. }
  611. .save-btn{
  612. padding-left: 20px;
  613. }
  614. }
  615. // 按钮公用样式
  616. .dark-button {
  617. background-color: #00706B;
  618. border: 1px #00706B solid;
  619. color: #fff;
  620. }
  621. .light-button {
  622. color: #00706B;
  623. border: 1px #00706B solid;
  624. }
  625. }
  626. </style>