Device.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <template>
  2. <schema-table
  3. ref="table"
  4. row-key="id"
  5. :schema="schema"
  6. @row-click="onRowClick"
  7. >
  8. <confirm-dialog
  9. ref="editDialog"
  10. :title="dialogTitle"
  11. @confirm="onSave"
  12. >
  13. <div class="c-grid-form u-align-self--center">
  14. <span class="c-grid-form__label required">名称:</span>
  15. <el-input
  16. v-model.trim="currObj.name"
  17. placeholder="最多50个字符"
  18. maxlength="50"
  19. clearable
  20. />
  21. <span class="c-grid-form__label required">产品:</span>
  22. <schema-select
  23. v-model="currObj.productId"
  24. placeholder="请选择产品"
  25. :schema="productSelectSchema"
  26. :disabled="isSub"
  27. />
  28. <span class="c-grid-form__label required">序列号:</span>
  29. <el-input
  30. v-model.trim="currObj.serialNumber"
  31. placeholder="最多50个字符"
  32. maxlength="50"
  33. clearable
  34. />
  35. <span class="c-grid-form__label required">MAC:</span>
  36. <el-input
  37. v-model.trim="currObj.mac"
  38. placeholder="ff:ff:ff:ff:ff:ff"
  39. maxlength="17"
  40. clearable
  41. />
  42. <span class="c-grid-form__label required">地址:</span>
  43. <el-input
  44. v-model.trim="currObj.address"
  45. placeholder="最多100个字符"
  46. maxlength="100"
  47. clearable
  48. />
  49. <span class="c-grid-form__label">经度:</span>
  50. <div class="l-flex--row c-grid-form__option">
  51. <el-input
  52. v-model.trim="currObj.longitude"
  53. class="l-flex__fill c-sibling-item"
  54. placeholder="-180 ~ +180"
  55. maxlength="13"
  56. clearable
  57. />
  58. <span class="c-sibling-item far c-grid-form__label">纬度:</span>
  59. <el-input
  60. v-model.trim="currObj.latitude"
  61. class="l-flex__fill c-sibling-item"
  62. placeholder="-90 ~ +90"
  63. maxlength="12"
  64. clearable
  65. />
  66. </div>
  67. <span />
  68. <a
  69. class="o-link grid"
  70. href="http://api.map.baidu.com/lbsapi/getpoint/index.html"
  71. target="_blank"
  72. />
  73. </div>
  74. </confirm-dialog>
  75. </schema-table>
  76. </template>
  77. <script>
  78. import {
  79. getDevicesByAdmin,
  80. addDevice,
  81. deleteDevice,
  82. getSubDevices,
  83. addSubDevice,
  84. activateDevice,
  85. deactivateDevice,
  86. getProducts
  87. } from '@/api/device'
  88. import {
  89. validMAC,
  90. validLongitude,
  91. validLatitude
  92. } from '@/utils/validate'
  93. export default {
  94. name: 'Device',
  95. props: {
  96. group: {
  97. type: Object,
  98. required: true
  99. }
  100. },
  101. data () {
  102. const productSelectSchema = {
  103. remote: getProducts,
  104. condition: { tenant: this.group.path },
  105. pagination: true,
  106. value: 'id',
  107. label: 'name'
  108. }
  109. return {
  110. currObj: {},
  111. isSub: false,
  112. ratio: null,
  113. productSelectSchema,
  114. schema: {
  115. condition: { productId: void 0, name: '', tenant: this.group.path },
  116. list: getDevicesByAdmin,
  117. transform: this.transform,
  118. transformData: this.transformTableData,
  119. buttons: [
  120. { type: 'add', on: this.onAddDevice }
  121. ],
  122. filters: [
  123. { key: 'productId', type: 'select', placeholder: '全部产品', ...productSelectSchema },
  124. { key: 'name', type: 'search', placeholder: '设备名称' }
  125. ],
  126. cols: [
  127. { type: 'refresh', render (data, h) {
  128. return data.isMaster
  129. ? h('i', {
  130. staticClass: `o-expand-icon u-pointer ${data.loading ? 'el-icon-loading' : 'el-icon-arrow-right'}`,
  131. class: { expand: data.expand }
  132. })
  133. : null
  134. } },
  135. { label: '设备名称', 'min-width': 120, render (data, h) {
  136. return data.empty ? h('span', { staticClass: 'u-color--info' }, '暂无备份设备') : data.name
  137. } },
  138. { prop: 'productName', label: '产品' },
  139. { prop: 'serialNumber', label: '序列号', 'min-width': 100 },
  140. { prop: 'mac', label: 'MAC', 'min-width': 100 },
  141. { type: 'tag', 'width': 100, render ({ empty, activate, onlineStatus }) {
  142. return empty
  143. ? null
  144. : {
  145. type: activate
  146. ? activate === 1
  147. ? void 0
  148. : onlineStatus === 1
  149. ? 'success'
  150. : 'danger'
  151. : 'warning',
  152. label: activate
  153. ? activate === 1
  154. ? '已激活'
  155. : onlineStatus === 1
  156. ? '在线'
  157. : '离线'
  158. : '未激活'
  159. }
  160. }, on: this.onTagClick },
  161. { type: 'invoke', width: 180, render: [
  162. { label: '查看', render ({ empty }) { return !empty }, on: this.onViewDevice },
  163. { label: '添加备份', render ({ isMaster }) { return isMaster }, on: this.onAddSubDevice },
  164. { label: '删除', render ({ empty }) { return !empty }, on: this.onDelDevice }
  165. ] }
  166. ]
  167. }
  168. }
  169. },
  170. computed: {
  171. dialogTitle () {
  172. return this.isSub ? '新增备份设备' : '新增设备'
  173. }
  174. },
  175. methods: {
  176. transform (data) {
  177. return {
  178. ...data,
  179. loaded: false,
  180. loading: false,
  181. expand: false,
  182. subs: [],
  183. isMaster: true
  184. }
  185. },
  186. transformTableData (data) {
  187. const arr = []
  188. data.forEach(item => {
  189. arr.push(item)
  190. if (item.loaded && item.expand) {
  191. arr.push(...item.subs)
  192. }
  193. })
  194. return arr
  195. },
  196. onAddDevice () {
  197. this.isSub = false
  198. this.$master = null
  199. this.productSelectSchema.option = null
  200. this.onAdd()
  201. },
  202. onAddSubDevice (item) {
  203. this.isSub = true
  204. this.$master = item
  205. this.productSelectSchema.option = { value: item.productId, label: item.productName }
  206. this.onAdd()
  207. },
  208. onAdd () {
  209. this.currObj = {
  210. name: '',
  211. productId: this.$master?.productId,
  212. serialNumber: '',
  213. mac: '',
  214. longitude: '',
  215. latitude: '',
  216. address: '',
  217. tenant: this.group.path
  218. }
  219. this.$refs.editDialog.show()
  220. },
  221. onSave (done) {
  222. if (this.check(this.currObj)) {
  223. if (this.isSub) {
  224. addSubDevice(this.$master, this.currObj).then(() => {
  225. done()
  226. this.reloadSubDevices(this.$master)
  227. })
  228. } else {
  229. addDevice(this.currObj).then(() => {
  230. done()
  231. this.$refs.table.resetCondition({ name: this.currObj.name, productId: this.currObj.productId })
  232. })
  233. }
  234. }
  235. },
  236. check (item) {
  237. if (!item.name) {
  238. this.$message({
  239. type: 'warning',
  240. message: '名称不能为空'
  241. })
  242. return false
  243. }
  244. if (!item.productId) {
  245. this.$message({
  246. type: 'warning',
  247. message: '请选择产品'
  248. })
  249. return false
  250. }
  251. if (!item.serialNumber) {
  252. this.$message({
  253. type: 'warning',
  254. message: '序列号不能为空'
  255. })
  256. return false
  257. }
  258. if (!item.mac) {
  259. this.$message({
  260. type: 'warning',
  261. message: 'MAC不能为空'
  262. })
  263. return false
  264. }
  265. if (!validMAC(item.mac)) {
  266. this.$message({
  267. type: 'warning',
  268. message: 'MAC格式不正确,例 ff:ff:ff:ff:ff:ff'
  269. })
  270. return false
  271. }
  272. item.mac = item.mac.toLowerCase()
  273. if (!item.address) {
  274. this.$message({
  275. type: 'warning',
  276. message: '地址不能为空'
  277. })
  278. return false
  279. }
  280. if (item.longitude && !validLongitude(item.longitude)) {
  281. this.$message({
  282. type: 'warning',
  283. message: '经度格式错误,-180 ~ +180'
  284. })
  285. return false
  286. }
  287. if (item.latitude && !validLatitude(item.latitude)) {
  288. this.$message({
  289. type: 'warning',
  290. message: '纬度格式错误,-90 ~ +90'
  291. })
  292. return false
  293. }
  294. return true
  295. },
  296. onViewDevice (item) {
  297. this.$router.push({
  298. name: 'device-detail',
  299. params: {
  300. id: item.id
  301. }
  302. })
  303. },
  304. onDelDevice (item) {
  305. if (item.isMaster) {
  306. deleteDevice(item).then(() => {
  307. this.$refs.table.decrease(1)
  308. })
  309. } else {
  310. deleteDevice(item).then(() => {
  311. this.reloadSubDevices(item.parent)
  312. })
  313. }
  314. },
  315. reloadSubDevices (item) {
  316. item.loaded = false
  317. item.children = []
  318. this.getSubDevices(item)
  319. },
  320. getSubDevices (item, pageSize = 999) {
  321. item.loading = true
  322. getSubDevices({
  323. id: item.id,
  324. pageNum: 1,
  325. pageSize
  326. }).then(({ data, totalCount }) => {
  327. if (totalCount > pageSize) {
  328. this.getSubDevices(item, totalCount)
  329. } else {
  330. item.loading = false
  331. item.loaded = true
  332. item.expand = true
  333. if (data.length === 0) {
  334. item.subs = [{ id: `${Math.random()}`, empty: true }]
  335. } else {
  336. item.subs = data.map(device => {
  337. return {
  338. ...device,
  339. isMaster: false,
  340. empty: false,
  341. parent: item
  342. }
  343. })
  344. }
  345. }
  346. }, () => {
  347. item.loading = false
  348. })
  349. },
  350. onRowClick (data) {
  351. if (data.isMaster) {
  352. if (data.loaded) {
  353. data.expand = !data.expand
  354. } else if (!data.loading) {
  355. this.getSubDevices(data)
  356. }
  357. }
  358. },
  359. onTagClick (data) {
  360. (data.activate ? deactivateDevice : activateDevice)(data).then(() => {
  361. if (data.isMaster) {
  362. this.$refs.table.pageTo()
  363. } else {
  364. this.reloadSubDevices(data.parent)
  365. }
  366. })
  367. }
  368. }
  369. }
  370. </script>