Device.vue 9.9 KB

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