Commit a9cc0aa4 by 谢林威

Merge branch 'develop' of gitlab.seetatech.com:seeta-device/deviceManage into develop

2 parents fa5bd8c9 3a4ea50a
Pipeline #5898 passed
in 2 minutes 13 seconds
......@@ -1871,63 +1871,6 @@
"integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"ssri": {
"version": "8.0.1",
"resolved": "https://registry.nlark.com/ssri/download/ssri-8.0.1.tgz?cache=0&sync_timestamp=1621364668574&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fssri%2Fdownload%2Fssri-8.0.1.tgz",
......@@ -1936,28 +1879,6 @@
"requires": {
"minipass": "^3.1.1"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.4.1",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.4.1.tgz",
"integrity": "sha512-nL1bDhfMAZgTVmVkOXQaK/WJa9zFDLM9vKHbh5uGv6HeH1TmZrXMWUEVhUrACT38XPhXM4Awtjj25EvhChEgXw==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
}
}
},
......@@ -13017,6 +12938,11 @@
}
}
},
"sortablejs": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
},
"source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npm.taobao.org/source-list-map/download/source-list-map-2.0.1.tgz",
......@@ -14527,6 +14453,87 @@
}
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.5.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.5.0.tgz",
"integrity": "sha512-WXh+7AgFxGTgb5QAkQtFeUcHNIEq3PGVQ8WskY5ZiFbWBkOwcCPRs4w/2tVyTbh2q6TVRlO3xfvIukUtjsu62A==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-property-decorator": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz",
......@@ -14579,6 +14586,14 @@
"integrity": "sha1-HuO8mhbsv1EYvjNLsV+cRvgvWCU=",
"dev": true
},
"vuedraggable": {
"version": "2.24.3",
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz",
"integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==",
"requires": {
"sortablejs": "1.10.2"
}
},
"vuex": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
......
......@@ -40,6 +40,7 @@
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.1.3",
"vue-showdown": "^2.4.1",
"vuedraggable": "^2.24.3",
"vuex": "^3.0.1",
"vuex-persistedstate": "^4.0.0-beta.3",
"xregexp": "^4.2.4",
......
......@@ -6,7 +6,7 @@
<style>
#app {
font-family: PingFangSC-Regular, PingFang SC, Avenir, Helvetica, Arial, sans-serif;
font-family: PingFangSC-Regular, 微软雅黑;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
......
......@@ -17,6 +17,7 @@ export const createParameter = data => axios(POST, FRONT + PARAMETER + '/create'
export const deleteParameter = data => axios(GET, FRONT + PARAMETER + '/delete', data)
export const editParameter = data => axios(POST, FRONT + PARAMETER + '/change', data)
export const detailParameter = data => axios(GET, FRONT + PARAMETER + '/query', data)
export const getTagByServiceType = data => axios(GET, FRONT + PARAMETER + '/service/query', data)
const TABLE = '/table'
export const getTable = data => axios(GET, FRONT + TABLE + '/query_list', data)
......@@ -34,3 +35,21 @@ export const addApp = data => axios(POST, FRONT + APPID + '/add', data)
const ACCOUNt = '/account'
export const getAccount = data => axios(GET, FRONT + ACCOUNt + '/query', data)
const DEVICE = '/device'
export const getDevice = data => axios(POST, FRONT + DEVICE + '/query_list', data)
export const getDeviceService = data => axios(GET, FRONT + DEVICE + '/service/query')
export const getTag = data => axios(GET, FRONT + DEVICE + '/tag/query_list')
export const getServiceParamter = data => axios(GET, FRONT + DEVICE + '/service/parameter/query', data)
export const setServiceParamter = data => axios(POST, FRONT + DEVICE + '/service/parameter/change', data)
export const deleteTag = data => axios(GET, FRONT + DEVICE + '/tag/delete', data)
export const addTag = data => axios(POST, FRONT + DEVICE + '/tag/add', data)
export const postServiceRequest = data => axios(POST, FRONT + DEVICE + '/service/direct', data)
export const postServiceCommand = data => axios(POST, FRONT + DEVICE + '/service/command', data)
export const addTemplate = data => axios(POST, FRONT + DEVICE + '/service/template/dispatch', data)
export const deleteTemplate = data => axios(POST, FRONT + DEVICE + '/service/template/revoke', data)
export const deleteDevice = data => axios(POST, FRONT + DEVICE + '/delete', data)
const SERVICE = '/service'
export const getService = data => axios(POST, FRONT + SERVICE + '/query_list', data)
export const getServiceDevice = data => axios(GET, FRONT + SERVICE + '/device/query', data)
......@@ -14,6 +14,7 @@ import formTable from './form/index.vue'
// import ajaxButton from './form/ajax-button.vue'
import seetaInput from './seeta-ui/seeta-input.vue'
import seetaButton from './seeta-ui/seeta-button.vue'
// import seetaCheckBox from './seeta-ui/seeta-checkbox.vue'
// import seetaCollapse from './seeta-ui/seeta-collapse.vue'
import seetaForm from './seeta-ui/seeta-form/form.vue'
import seetaFormItem from './seeta-ui/seeta-form/form-item.vue'
......@@ -30,6 +31,7 @@ import seetaCrumb from './seeta-ui/seeta-crumb.vue'
// import name from './list-filter/name.vue'
// import time from './list-filter/time.vue'
import puzzlevalidator from './PuzzleValidator'
// import nameFilter from './list-filter/name.vue'
import Vue from 'vue'
import datePicker from './calendar/index.vue'
......@@ -42,6 +44,8 @@ import datePicker from './calendar/index.vue'
// Vue.component('v-select', select)
Vue.component('v-textarea', textarea)
Vue.component('dropdown', dropdown)
// Vue.component('st-checkbox', seetaCheckBox)
// Vue.component('nameFilter', nameFilter)
// Vue.component('code-editor', codeEditor)
// Vue.component('tabs', tabs)
// Vue.component('data-empty', dataEmpty)
......
......@@ -7,7 +7,8 @@
:placeholder="placeholder",
@keyup.enter="search"
)
.iconfont.icon-search(@click="search")
i.el-input__icon.el-icon-search.icon-search(@click="search")
//- .iconfont.icon-search(@click="search")
</template>
<script lang="ts">
import { Vue, Prop, Component, Watch } from 'vue-property-decorator'
......@@ -23,26 +24,36 @@ export default class nameFilter extends Vue {
}
search() {
const routeQuery = this.$route.query
// 避免重复搜索
if (this.name === routeQuery.name) return
const query = {
...routeQuery,
name: this.name,
page_index: '1',
}
this.$router.replace({ query: _.omitBy(query, item => item === '') })
this.$emit('startSearch', this.name)
// const routeQuery = this.$route.query
// // 避免重复搜索
// if (this.name === routeQuery.name || this.name === '') return
// const query = {
// ...routeQuery,
// name: this.name,
// page_index: '1',
// }
// this.$router.replace({ query: _.omitBy(query, item => item === '') })
}
}
</script>
<style lang="sass" scoped>
.search
height: 32px
width: 240px
position: relative
display: inline-block
.search-input
width: 100%
padding-right: 35px
padding: 5.5px 35px 5.5px 12px
font-size: 14px
font-family: PingFangSC-Regular
color: #333333
letter-spacing: 0
&::-webkit-input-placeholder
font-family: PingFangSC-Regular
font-size: 14px
color: #999999
.icon-search
position: absolute
right: 0
......
......@@ -361,13 +361,13 @@ export default {
padding: 13px 20px
font-size: 16px
border-bottom: 1px solid $--dialog-header-border
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #3C3D40
line-height: 22px
.popup-body
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #666666
line-height: 20px
......
......@@ -53,7 +53,7 @@ export default {
::v-deep .el-form-item__label
padding: 0 20px 0 0
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #666666
</style>
......@@ -16,6 +16,7 @@ const getByteLen = item => {
}
export default {
getByteLen: getByteLen,
ipV4: /((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})|\*)){1,3}/,
// 实例名称校验
normName: (rule, value, cb) => {
// 支持中文、英文、日文、数字和特殊字符_-@(),长度限制4~30个字符,中文及日文算2个字符
......
......@@ -23,11 +23,12 @@ export default {
::v-deep input[type=text], ::v-deep input[type=password], ::v-deep input[type=number], ::v-deep textarea
font-size: 14px
color: #333
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
font-family: PingFangSC-Regular, 微软雅黑
letter-spacing: 0
&::placeholder
color: #999999
font-size: 14px
letter-spacing: 0
.el-textarea.el-input--small
::v-deep .el-textarea__inner
border-radius: 2px
......
......@@ -40,13 +40,13 @@ export default class seetaSelect extends Vue {
.el-select-dropdown
.el-select-dropdown__item
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #333333
.el-select-dropdown__item.selected
font-weight: normal
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
color: #409EFF
.el-select__tags
.el-icon-close
......@@ -57,13 +57,13 @@ export default class seetaSelect extends Vue {
color: #999999 !important
.el-select__tags-text
font-size: 12px !important
font-family: PingFangSC-Regular, PingFang SC !important
font-family: PingFangSC-Regular, 微软雅黑 !important
font-weight: 400 !important
color: #666666 !important
line-height: 17px !important
.el-select
.el-input__inner
font-size: 14px !important
font-family: PingFangSC-Regular, PingFang SC !important
font-family: PingFangSC-Regular, 微软雅黑 !important
font-weight: 400 !important
</style>
......@@ -12,6 +12,74 @@
@filter-change="filterChange"
@sort-change="sortChange"
>
<el-table-column type="expand" v-if="doubleTable" class="expend-column">
<!-- eslint-disable-next-line -->
<template slot-scope="props">
<el-table
stripe
:data="props.row.child">
<template
v-for="col in childOptions">
<!-- 插槽 -->
<el-table-column
header-align="left"
align="left"
v-if="col.type === 'slot'"
:key="col.label"
:label="col.label"
:min-width="col.width? col.width : ''"
:column-key="col.filterKey"
:filters="handleFilters(col.filterList)"
:filter-multiple="false"
filter-placement="bottom"
:sortable="!!col.sortable">
<template slot-scope="scope">
<div
v-if="(col.slotName === 'status' || col.slotName === 'state' || col.slotName === 'api_status')&& col.animation &&col.animation(scope.row)"
class="status-icon-animation"
:style="{
background: col.statusColor && col.statusColor(scope.row)
}">
</div>
<div
v-else-if="col.slotName === 'status' || col.slotName === 'state' ||col.slotName === 'api_status'"
class="status-icon"
:style="{
background: col.statusColor && col.statusColor(scope.row)
}">
</div>
<div class="any-slot">
<slot :name="col.slotName" v-bind="scope.row"></slot>
</div>
</template>
</el-table-column>
<el-table-column
v-else-if="col.type === 'check' || col.type === 'selection'"
:key="col.label"
type="selection"
width="37"
:reserve-selection="true"
:selectable="selectable(col)">
</el-table-column>
<!-- 普通列 -->
<el-table-column
header-align="left"
align="left"
v-else-if="!(typeof col.render === 'function')"
:key="col.label"
:label="col.label"
:prop="col.render"
:min-width="col.width? col.width : ''"
:column-key="col.filterKey"
:filters="handleFilters(col.filterList)"
:filter-multiple="false"
filter-placement="bottom"
:sortable="!!col.sortable">
</el-table-column>
</template>
</el-table>
</template>
</el-table-column>
<template
v-for="col in options">
<!-- 多选框 -->
......@@ -133,12 +201,16 @@ export default class seetaTableIndex extends Vue {
}
// 传入遮罩控制
@Prop({ type: Boolean, default: false }) outerLoading
// 是否开启嵌套表格
@Prop({ type: Boolean, default: false }) doubleTable
// 列表参数
@Prop({ type: Array, default: () => [] }) options
// 子表格列表参数
@Prop({ type: Array, default: () => [] }) childOptions
@Prop({ type: Boolean, default: true }) stripe
// 数据加载函数
@Prop({ type: Function, default: () => { return {} } }) loadFunction
@Prop({ type: Number, default: 10 }) pageSize
@Prop({ type: Number, default: 30 }) pageSize
@Prop({ type: Number, default: 1 }) pageIndex
// 手动传入数据
@Prop({ type: Object, default: () => {} }) data
......@@ -158,6 +230,7 @@ export default class seetaTableIndex extends Vue {
@Prop({ type: String, default: 'total, prev, pager, next, sizes, jumper' }) pageLayout
isLoading: boolean = false
tableData: {}[] = []
childTableData: {}[] = []
total: number = 0
// currentPage: number = 1
// currentSize: number = 10
......@@ -227,11 +300,15 @@ export default class seetaTableIndex extends Vue {
this.currentFilters = {}
}, 100)
}
clickCollapse() {
this.getTableHeight()
}
// 计算列表高度
getTableHeight() {
this.$nextTick(() => {
if (this.refTableBox) {
this.tableHeight = this.pagination ? this.refTableBox.getBoundingClientRect().height - 66 : this.refTableBox.getBoundingClientRect().height - 25
// console.log(this.tableHeight)
}
})
}
/**
......@@ -257,6 +334,7 @@ export default class seetaTableIndex extends Vue {
dataChange(val) {
if (!val) return
this.tableData = val.list
this.childTableData = val.list.map(item => item.child)
if (val.total || val.total === 0) {
this.total = val.total
}
......@@ -330,12 +408,14 @@ export default class seetaTableIndex extends Vue {
@import "@/styles/theme.sass"
.table-box
height: 100%
overflow: auto
overflow: hidden
background: #fff
position: relative
.el-table
color: $--color-text-primary
font-size: 14px
::v-deep.el-table__expanded-cell
padding: 0 0
::v-deep .el-table__header
font-size: 14px
font-family: PingFang-SC-Bold, PingFang-SC
......@@ -384,6 +464,8 @@ export default class seetaTableIndex extends Vue {
opacity: 0.6
transform: scale(1)
::v-deep .el-table__row
.status-icon + .any-slot
display: inline-block
.status-icon, .status-icon-animation
width: 6px
height: 6px
......@@ -414,7 +496,7 @@ export default class seetaTableIndex extends Vue {
text-align: left
padding-left: 30px
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #333333
line-height: 20px
......@@ -445,7 +527,7 @@ export default class seetaTableIndex extends Vue {
padding: 2px 5px
color: #333
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
::v-deep .el-pagination__total
font-size: 14px
color: $--color-text-primary
......@@ -467,7 +549,7 @@ export default class seetaTableIndex extends Vue {
background-color: #F5F7FA !important
.el-select-dropdown__item
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
.el-select-dropdown__item, .selected
font-weight: normal !important
......
......@@ -32,7 +32,7 @@ export default class seetaTabs extends Vue {
margin: 0 0 14px
::v-deep .el-tabs__item
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
&.is-active
color: #409EFF
......
......@@ -35,6 +35,16 @@ export default [
name: 'device',
meta: { title: '设备列表' },
component: () => import('@views/DeviceList')
}, {
path: '/device-detail',
name: 'device-detail',
meta: { title: '设备详情' },
component: () => import('@views/DeviceList/detail.vue')
}, {
path: '/device-service',
name: 'device-service',
meta: { title: '设备服务' },
component: () => import('@views/DeviceList/deviceService/deviceServiceIndex')
}]
},
{
......
......@@ -3,7 +3,10 @@ import browserStorage from '@/services/local-storage'
const state = () => ({
lang: browserStorage.getItem('lang') || 'zh-CN',
routerStatus: 0,
currentProduct: {}
currentProduct: {},
currentDevice: '',
currentService: {},
currentTagIndex: 0,
})
const mutations = {
......@@ -16,7 +19,18 @@ const mutations = {
},
changeCurrentProduct(state, item) {
state.currentProduct = JSON.parse(JSON.stringify(item))
}
},
changeCurrentDevice(state, item) {
state.currentDevice = item
},
changeCurrentService(state, item) {
state.currentService = JSON.parse(JSON.stringify(item))
},
changeCurrentTagIndex(state, item) {
state.currentTagIndex = item
sessionStorage.setItem('currentTagIndex', item)
},
}
const actions = {
......@@ -26,7 +40,10 @@ const actions = {
const getters = {
lang: state => state.lang,
routerStatus: state => state.routerStatus,
currentProduct: state => state.currentProduct
currentProduct: state => state.currentProduct,
currentDevice: state => state.currentDevice,
currentService: state => state.currentService,
currentTagIndex: state => state.currentTagIndex,
}
export default {
......
......@@ -85,5 +85,5 @@ body, html
#raw-input::-webkit-input-placeholder
font-size: 14px
color: #999
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
......@@ -33,7 +33,7 @@
background-color: #FFF
margin-top: 14px
display: flex
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
// align-items: center
align-items: flex-start
......@@ -47,7 +47,7 @@
vertical-align: middle
.el-input__inner::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
line-height: 14px
color:#999999
......@@ -56,7 +56,7 @@
display: inline-block
height: 20px
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #666666
line-height: 20px
......@@ -88,7 +88,7 @@
width: 56px
height: 18px
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #FFFFFF
i.iconfont::before
......@@ -103,10 +103,15 @@
height: 100%
.el-range-input
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
.el-date-editor .el-range__close-icon
line-height: 24px
.el-select__input
border: none
padding: 0
appearance: none
background-color: transparent
// 新建页公共样式
.common-create
display: flex
......@@ -181,7 +186,7 @@
color: #409EFF
.operate
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
color: #409EFF
line-height: 20px
......@@ -192,3 +197,9 @@
// 搜索栏禁止输入校验规则之外的字符
.error-border .el-input__inner
border: 1px solid red !important
.mySuccess
width: 122px !important
min-width: 122px
height: 40px
background: #FFFFFF
box-shadow: 0 0 8px 0 rgba(37,38,94,0.20)
......@@ -10,7 +10,7 @@
font-size: 12px
white-space: nowrap
text-align: center
font-family: PingFangSC-Regular, PingFang SC
font-family: PingFangSC-Regular, 微软雅黑
font-weight: 400
line-height: 17px
height: 28px
......
......@@ -6,7 +6,7 @@ export function rTime(date) {
}
// 转换时间格式 精确到分钟
export function rTimeMin(item) {
const json_date = moment(new Date(item)).format('YYYY-MM-DD kk:mm')
const json_date = moment(new Date(item)).format('YYYY-MM-DD HH:mm:ss')
return json_date
// const y = date.getFullYear()
// let m = date.getMonth() + 1
......@@ -62,7 +62,27 @@ export function isArrayEqual(value1 = [], value2 = []) {
}
return false
}
// 复制内容到粘贴板的实现
export function copyText(item) {
if (!item) {
return
}
const transfer = document.createElement('input')
document.body.appendChild(transfer)
transfer.value = item // 这里表示想要复制的内容
transfer.focus()
transfer.select()
if (document.execCommand('copy')) {
document.execCommand('copy')
}
transfer.blur()
this.$message({
message: '复制成功',
type: 'success',
customClass: 'mySuccess',
})
document.body.removeChild(transfer)
}
export function calculateByte(base64) {
if (base64.indexOf('base64,') !== -1) {
base64 = base64.substring(base64.indexOf('base64,') + 7)
......
<template>
<div class="box">
<div class="wrapper">
<div class="content">
<div class="content-item">
<span class="content-item-title">{{'服务参数:'}}</span>
<div class="content-table">
<st-table
ref="vTable"
:options="definitions"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus"
:pagination="false"
>
<div slot='nameSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.name" placement="top">
<span>{{ simplify(row.name, 16) }}</span>
</el-tooltip>
</div>
<div slot='potuidSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.potuid" placement="top">
<span>{{ simplify(row.potuid, 8) }}</span>
</el-tooltip>
</div>
<div slot='portSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.port + ''" placement="top">
<span>{{ simplify(row.port, 6) }}</span>
</el-tooltip>
</div>
<div slot='description' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.description" placement="top">
<span>{{ simplify(row.description, 16) }}</span>
</el-tooltip>
</div>
<div slot='operate'>
<span class="operate-text">{{ '-'}}</span>
</div>
</st-table>
</div>
</div>
<div class="content-item">
<span class="content-item-title">{{'指令:'}}</span>
<st-input type="textarea" placeholder="请输入Json" class="content-item-one" v-model="commandContent"></st-input>
</div>
</div>
<st-button type="primary" width="80px" class="sendBtn" :loading="buttonLoading" @click="send">{{'发送'}}</st-button>
</div>
</div>
</template>
<script>
import { rTimeMin, copyText } from '@/utils/system.js'
import { postServiceCommand } from '@/axios'
export default {
computed: {
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 'online':
return '#67C23A'
case 'offline':
return '#999999'
default:
return '#F56C6C'
}
}
},
// 获取设备状态文字
getStatusText() {
return item => {
switch (item) {
case 'online':
return '在线'
case 'offline':
return '离线'
default:
return '异常'
}
}
},
// 精简文字
simplify() {
return (item, length) => {
if (item && item.length > length) {
return item.substring(0, length) + '...'
}
return item
}
}
},
data() {
return {
commandContent: '',
buttonLoading: false,
dynamicTags: ['标签一', '标签二', '标签三'],
inputVisible: false,
inputValue: '',
tokenList: [],
total: 0,
loadingStatus: false,
activeTab: 'getParams',
tabs: [
{
label: '查看参数',
name: 'getParams',
},
{
label: '发送请求',
name: 'sendRequest',
},
{
label: '发送指令',
name: 'sendOrder',
},
],
definitions: [
{
label: '服务',
type: 'slot',
slotName: 'nameSlot',
}, {
label: '编号',
type: 'slot',
slotName: 'potuidSlot',
}, {
label: '端口',
type: 'slot',
slotName: 'portSlot',
}, {
label: '描述',
type: 'slot',
slotName: 'description'
}, {
label: '操作',
type: 'slot',
slotName: 'operate'
}
],
}
},
mounted() {
this.getData()
},
methods: {
rTimeMin,
async send() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
this.buttonLoading = true
const res = await postServiceCommand({
pots: [currentService.potuid],
command: JSON.parse(this.commandContent)
})
this.buttonLoading = false
if (res && res.data) {
// this.resValue = res.data
}
},
async getData() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
this.tokenList = [{
name: currentService.name,
potuid: currentService.potuid,
port: currentService.port,
description: currentService.description,
}]
this.total = 1
},
handleClose(tag) {
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
},
showInput() {
this.inputVisible = true
this.$nextTick(_ => {
this.$refs.saveTagInput.$refs.input.focus()
})
},
handleInputConfirm() {
const inputValue = this.inputValue
if (inputValue) {
this.dynamicTags.push(inputValue)
}
this.inputVisible = false
this.inputValue = ''
}
}
}
</script>
<style lang="sass" scoped>
::v-deep .el-table__body-wrapper.is-scrolling-none
max-height: 224px !important
.table-box
::v-deep .el-table
max-height: none !important
.box
height: 100%
display: flex
flex-direction: column
justify-content: space-between
min-height: 563px
.wrapper
height: calc(100% - 60px)
display: flex
flex-direction: column
.content-item
margin-bottom: 24px
display: flex
.content-item-one
width: 609px !important
height: 100px
::v-deep.el-textarea__inner
font-size: 14px
color: #333
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
.content-item-title
margin: auto 0
width: 108px
.content-table
width: calc(100% - 108px)
.blue-text
color: #409EFF
.sendBtn
margin-left: 108px
</style>
<template>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'设备列表'}}</span>
</div>
<div class="page-nav">
<div class="page-nav-title">
<span>{{$store.getters.currentService.serviceName}}</span>
</div>
<st-table
ref="vTable"
:options="definitions"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus"
:pagination="false"
>
<div slot='codeSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.deviceid" placement="top">
<span>{{ simplify(row.deviceid, 3) }}</span>
</el-tooltip>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.deviceid)"></i>
</div>
<div slot='status' slot-scope="row" class="status">
<span class="circleStatus" :style="{color: getStatusColor(row.state)}">{{ getStatusText(row.state) }}</span>
</div>
<div slot='structureSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.structure" placement="top">
<span>{{ simplify(row.structure, 6) }}</span>
</el-tooltip>
</div>
<div slot='registerTimeSlot' slot-scope="row">
<span>{{ (row.register_date) }}</span>
</div>
<div slot='tagsSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.tags ? row.tags.join('、') : ''" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.tags">
<el-tag v-if="[0, 1].indexOf(index) !== -1" :key="index" class="label label-primary">{{ simplify(item, 3) }}</el-tag>
</template>
<span v-if="(row.tags && row.tags.length) > 10">共: {{(row.tags && row.tags.length) ? row.tags.length : 0}} 条</span>
</div>
</el-tooltip>
</div>
<div slot='servicesSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="getServiceName(row.services)" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.services">
<span v-if="[0, 1, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item.name, 4) }}</span>
</template>
<span v-if="(row.services && row.services.length) > 10">共: {{(row.services && row.services.length) ? row.services.length : 0}} 条</span>
</div>
</el-tooltip>
</div>
<div slot='systemSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.system" placement="top">
<span>{{ simplify(row.system, 6) }}</span>
</el-tooltip>
</div>
<div slot='operate' slot-scope="row">
<span class="operate-text" @click="detail(row.deviceid)">{{'详情'}}</span>
</div>
</st-table>
</div>
<div class="page-content">
<div class="table-list">
<st-tabs :tabs="tabs" v-model="activeTab" @tab-click="changeTab">
<template v-slot:[activeTab]>
<components :is="activeTab" ref="dataTable"></components>
</template>
</st-tabs>
</div>
</div>
</div>
</template>
<script>
import getParams from './components/GetParams.vue'
import sendRequest from './components/SendRequest.vue'
import sendOrder from './components/SendOrder.vue'
import { rTimeMin, copyText } from '@/utils/system.js'
import { getService, getServiceDevice } from '@/axios'
export default {
components: {
getParams,
sendRequest,
sendOrder
},
computed: {
getServiceName() {
return item => {
return item.map(t1 => t1.name).join()
}
},
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 1:
return '#67C23A'
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
},
// 获取设备状态文字
getStatusText() {
return item => {
switch (item) {
case 1:
return '在线'
case 2:
return '异常'
default:
return '离线'
}
}
},
// 精简文字
simplify() {
return (item, length) => {
if (item && item.length > length) {
return item.substring(0, length) + '...'
}
return item
}
}
},
data() {
return {
tokenList: [
],
total: 0,
loadingStatus: false,
activeTab: 'getParams',
tabs: [
{
label: '查看参数',
name: 'getParams',
},
{
label: '发送请求',
name: 'sendRequest',
},
{
label: '发送指令',
name: 'sendOrder',
},
],
definitions: [
{
label: '编号',
type: 'slot',
slotName: 'codeSlot',
}, {
label: '状态',
type: 'slot',
slotName: 'status',
statusColor: item => {
switch (item.state) {
case 1:
return '#67C23A'
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
}, {
label: '架构',
type: 'slot',
slotName: 'structureSlot'
}, {
label: '系统',
type: 'slot',
slotName: 'systemSlot'
}, {
label: 'IP',
render: 'ip'
}, {
label: '注册时间',
type: 'slot',
slotName: 'registerTimeSlot',
width: 145
}, {
label: '标签',
type: 'slot',
slotName: 'tagsSlot',
width: 95
}, {
label: '服务',
type: 'slot',
slotName: 'servicesSlot',
width: 95
}, {
label: '操作',
type: 'slot',
slotName: 'operate',
},
],
currentDeviceId: '',
}
},
methods: {
rTimeMin,
copyText,
changeTab() {
let tagIndex = 0
if (this.activeTab) {
switch (this.activeTab) {
case 'getParams':
tagIndex = 0
break
case 'sendRequest':
tagIndex = 1
break
case 'sendOrder':
tagIndex = 2
break
}
}
this.$store.commit('changeCurrentTagIndex', tagIndex)
},
async getServiceParams() {
const res = await getServiceParams(this.serviceId)
},
async getData() {
const res = await getServiceDevice({ deviceid: this.currentDeviceId })
if (res && res.data && res.data.device) {
this.tokenList = [JSON.parse(JSON.stringify(res.data.device))]
this.total = 1
} else {
this.tokenList = []
this.total = 0
}
},
// 跳转到设备详情页面
detail(deviceid) {
this.$store.commit('changeCurrentDevice', deviceid)
this.$router.push({ name: 'device-detail' })
},
},
mounted() {
if (this.$store.getters.currentDevice !== '') {
sessionStorage.setItem('currentDevice', this.$store.getters.currentDevice)
}
if (sessionStorage.getItem('currentTagIndex')) {
this.$store.commit('changeCurrentTagIndex', +sessionStorage.getItem('currentTagIndex'))
}
this.currentTagIndex = +sessionStorage.getItem('currentTagIndex')
switch (this.currentTagIndex) {
case 0:
this.activeTab = 'getParams'
break
case 1:
this.activeTab = 'sendRequest'
break
case 2:
this.activeTab = 'sendOrder'
break
}
this.currentDeviceId = sessionStorage.getItem('currentDevice')
this.getData()
},
}
</script>
<style lang="sass" scoped>
.service-item
margin-right: 20px
.circleStatus
margin-left: 6px
.icon-fuzhi-text
margin-left: 6px
color: #409EFF
cursor: pointer
.operate-text
font-family: PingFangSC-Regular
font-size: 14px
color: #409EFF
margin-right: 20px
cursor: pointer
.page-nav
flex-direction: column
.table-box
width: 100%
::v-deep .el-table
max-height: fit-content !important
.page-nav-title
text-align: left
margin-bottom: 10px
font-family: PingFangSC-Regular, 微软雅黑
font-size: 14px
color: #333
font-weight: bold
.page-content
padding-bottom: 0px
margin-top: 22px
flex: 1 0 0
overflow-y: visible
overflow-x: hidden
.page-nav
::v-deep.el-table__body-wrapper
max-height: none !important
::v-deep.pagination
margin-top: 0
margin-bottom: 0
.table-list
flex: 1 0 0 !important
overflow: visible !important
.el-tabs
height: 100%
display: -webkit-box
display: -ms-flexbox
display: flex
-webkit-box-orient: vertical
-webkit-box-direction: normal
-ms-flex-direction: column
flex-direction: column
::v-deep.el-tabs__content
flex: 1 0 0
overflow: visible
.el-tab-pane
height: 100%
overflow: visible
</style>
......@@ -225,9 +225,6 @@ export default {
const binaryObj = {}
const tableObj = {}
for (let i = 0; i < scalarsArr.length; i++) {
scalarsObj[scalarsArr[i].field] = scalarsArr[i].value === null ? null : (scalarsArr[i].type === 'number' ? Number(scalarsArr[i].value) : String(scalarsArr[i].value))
}
for (let j = 0; j < binaryArr.length; j++) {
binaryObj[binaryArr[j].field] = binaryArr[j].value
}
for (let k = 0; k < tableArr.length; k++) {
......
......@@ -441,12 +441,9 @@ export default {
color: #666
background: rgba(0, 0, 0, 0)
height: 32px
.updated
::v-deep input[type=text], ::v-deep input[type=password], ::v-deep input[type=number], ::v-deep textarea
color: #F56C6C !important
::v-deep thead
font-size: 14px
font-family: PingFang-SC-Bold, PingFang-SC
font-weight: bold
color: #333333
line-height: 20px
......
......@@ -78,7 +78,6 @@
</template>
<script>
import { usersApi, codeApi } from '@/http'
export default {
data() {
const validatePassword = (rule, value, callback) => {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!