Device.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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 __SUB_DEVICE__ && 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. __SUB_DEVICE__
  138. ? { label: '设备名称', 'min-width': 120, render (data, h) {
  139. return data.empty ? h('span', { staticClass: 'u-color--info' }, '暂无备份设备') : data.name
  140. } }
  141. : { prop: 'name', label: '设备名称', 'min-width': 120 },
  142. { prop: 'productName', label: '配置' },
  143. { prop: 'serialNumber', label: '序列号', 'min-width': 140 },
  144. { prop: 'mac', label: 'MAC', 'min-width': 140 },
  145. { type: 'tag', 'width': 100, render ({ empty, activate, onlineStatus }) {
  146. return empty
  147. ? null
  148. : activate
  149. ? onlineStatus === 0
  150. ? { type: 'primary', label: '已启用' }
  151. : onlineStatus === 1
  152. ? { type: 'success', label: '在线' }
  153. : { type: 'danger', label: '离线' }
  154. : { type: 'warning', label: '未激活' }
  155. }, on: this.onTagClick },
  156. { type: 'invoke', width: __SUB_DEVICE__ ? 240 : 160, render: [
  157. { label: '详情', render ({ empty }) { return !empty }, on: this.onViewDevice },
  158. { label: '配置', render ({ isMaster }) { return isMaster }, on: this.onSettingDevice },
  159. { label: '添加备份', render ({ isMaster }) { return __SUB_DEVICE__ && isMaster }, on: this.onAddSubDevice },
  160. { label: '删除', render ({ empty }) { return !empty }, on: this.onDelDevice }
  161. ] }
  162. ]
  163. }
  164. }
  165. },
  166. computed: {
  167. dialogTitle () {
  168. return this.isSub ? '新增备份设备' : '新增设备'
  169. }
  170. },
  171. methods: {
  172. transform (data) {
  173. return {
  174. ...data,
  175. loaded: false,
  176. loading: false,
  177. expand: false,
  178. subs: [],
  179. isMaster: true
  180. }
  181. },
  182. transformTableData (data) {
  183. const arr = []
  184. data.forEach(item => {
  185. arr.push(item)
  186. if (item.loaded && item.expand) {
  187. arr.push(...item.subs)
  188. }
  189. })
  190. return arr
  191. },
  192. onAddDevice () {
  193. this.isSub = false
  194. this.$master = null
  195. this.productSelectSchema.option = null
  196. this.onAdd()
  197. },
  198. onAddSubDevice (item) {
  199. this.isSub = true
  200. this.$master = item
  201. this.productSelectSchema.option = { value: item.productId, label: item.productName }
  202. this.onAdd()
  203. },
  204. onAdd () {
  205. this.currObj = {
  206. name: '',
  207. productId: this.$master?.productId,
  208. serialNumber: '',
  209. mac: '',
  210. longitude: '',
  211. latitude: '',
  212. address: '',
  213. tenant: this.group.path
  214. }
  215. this.$refs.editDialog.show()
  216. },
  217. onSave (done) {
  218. if (this.check(this.currObj)) {
  219. if (this.isSub) {
  220. addSubDevice(this.$master, this.currObj).then(() => {
  221. done()
  222. this.reloadSubDevices(this.$master)
  223. })
  224. } else {
  225. addDevice(this.currObj).then(() => {
  226. done()
  227. this.$refs.table.resetCondition({ name: this.currObj.name, productId: this.currObj.productId })
  228. })
  229. }
  230. }
  231. },
  232. check (item) {
  233. if (!item.name) {
  234. this.$message({
  235. type: 'warning',
  236. message: '名称不能为空'
  237. })
  238. return false
  239. }
  240. if (!item.productId) {
  241. this.$message({
  242. type: 'warning',
  243. message: '请选择产品'
  244. })
  245. return false
  246. }
  247. if (!item.serialNumber) {
  248. this.$message({
  249. type: 'warning',
  250. message: '序列号不能为空'
  251. })
  252. return false
  253. }
  254. if (!item.mac) {
  255. this.$message({
  256. type: 'warning',
  257. message: 'MAC不能为空'
  258. })
  259. return false
  260. }
  261. if (!validMAC(item.mac)) {
  262. this.$message({
  263. type: 'warning',
  264. message: 'MAC格式不正确,例 ff:ff:ff:ff:ff:ff'
  265. })
  266. return false
  267. }
  268. item.mac = item.mac.toLowerCase()
  269. if (!item.address) {
  270. this.$message({
  271. type: 'warning',
  272. message: '地址不能为空'
  273. })
  274. return false
  275. }
  276. if (item.longitude && !validLongitude(item.longitude)) {
  277. this.$message({
  278. type: 'warning',
  279. message: '经度格式错误,-180 ~ +180'
  280. })
  281. return false
  282. }
  283. if (item.latitude && !validLatitude(item.latitude)) {
  284. this.$message({
  285. type: 'warning',
  286. message: '纬度格式错误,-90 ~ +90'
  287. })
  288. return false
  289. }
  290. return true
  291. },
  292. onViewDevice (item) {
  293. this.$router.push({
  294. name: 'device-management-detail',
  295. params: {
  296. id: item.id
  297. }
  298. })
  299. },
  300. onDelDevice (item) {
  301. if (item.isMaster) {
  302. deleteDevice(item).then(() => {
  303. this.$refs.table.decrease(1)
  304. })
  305. } else {
  306. deleteDevice(item).then(() => {
  307. this.reloadSubDevices(item.parent)
  308. })
  309. }
  310. },
  311. reloadSubDevices (item) {
  312. item.loaded = false
  313. item.children = []
  314. this.getSubDevices(item)
  315. },
  316. getSubDevices (item, pageSize = 999) {
  317. item.loading = true
  318. getSubDevices({
  319. id: item.id,
  320. pageNum: 1,
  321. pageSize
  322. }).then(({ data, totalCount }) => {
  323. if (totalCount > pageSize) {
  324. this.getSubDevices(item, totalCount)
  325. } else {
  326. item.loading = false
  327. item.loaded = true
  328. item.expand = true
  329. if (data.length === 0) {
  330. item.subs = [{ id: `${Math.random()}`, empty: true }]
  331. } else {
  332. item.subs = data.map(device => {
  333. return {
  334. ...device,
  335. isMaster: false,
  336. empty: false,
  337. parent: item
  338. }
  339. })
  340. }
  341. }
  342. }, () => {
  343. item.loading = false
  344. })
  345. },
  346. onRowClick (data) {
  347. if (data.isMaster) {
  348. if (data.loaded) {
  349. data.expand = !data.expand
  350. } else if (!data.loading) {
  351. this.getSubDevices(data)
  352. }
  353. }
  354. },
  355. onTagClick (data) {
  356. (data.activate ? deactivateDevice : activateDevice)(data).then(() => {
  357. if (data.isMaster) {
  358. this.$refs.table.pageTo()
  359. } else {
  360. this.reloadSubDevices(data.parent)
  361. }
  362. })
  363. },
  364. onSettingDevice ({ id }) {
  365. this.$router.push({
  366. name: 'device-management-settings',
  367. params: { id }
  368. })
  369. }
  370. }
  371. }
  372. </script>