| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- <template>
- <a-card title="设备统计" >
- <a-row justify="center">
- <a-col
- v-for="item in state.deviceCount"
- :key="item.key"
- :xs="12" :sm="12" :md="6" :lg="8" :xl="4"
- >
- <div class="statistic" >
- <span class="count" :style="{color: item.color}" >{{item.value}}</span>
- <span>台</span>
- </div>
- <div class="label" >
- {{item.label}}
- </div>
- </a-col>
- </a-row>
- </a-card>
- <a-card style="margin-top: 20px;">
- <a-row justify="space-between" >
- <a-col :span="20" >
- <a-form layout="inline" >
- <a-form-item >
- <a-select allowClear style="width: 176px;" v-model:value="searchState.deviceStatus" placeholder="请输入设备状态">
- <a-select-option
- v-for="item in DeviceContriller.deviceStatus"
- :key="item.key"
- :value="item.key"
- >{{item.name}}</a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item style="width: 400px;">
- <a-input-group compact >
- <a-select allowClear v-model:value="searchState.searchKey" style="width: 150px;" >
- <a-select-option v-for="item in searchList" :key="item.key" :value="item.key">{{item.name}}</a-select-option>
- </a-select>
- <a-input allowClear v-model:value="searchState.searchValue" style="width: 176px" placeholder="请输入查询值"/>
- </a-input-group>
- </a-form-item>
- <a-form-item><a-button @click="resetFields([])">重置</a-button></a-form-item>
- <a-form-item><a-button type="primary" @click="getDevicePage">搜索</a-button> </a-form-item>
- </a-form>
- </a-col>
- <a-col :span="2" >
- <a-button type="primary" @click="openModal('add', {})"> + 新增设备</a-button>
- </a-col>
- </a-row>
- <a-table
- style="margin-top: 20px;width: 100%;"
- :columns="columns"
- :data-source="state.dataSource"
- :loading="state.loading"
- :pagination="searchState"
- @change="changePage"
- >
- <template #bodyCell="{column, record}">
- <template v-if="column.key === 'id'" >
- <a @click="goDetailPage(record.id)">{{record.id}}</a>
- </template>
- <template v-if="column.key === 'deviceStatus'" >
- <a-tag :color="record.deviceStatus.color" >{{record.deviceStatus.name}}</a-tag>
- </template>
- <template v-if="column.key === 'deviceNodeType'" >
- <a-tag>{{record.deviceNodeType == 'GATEWAY'?'直连类型':'非直连类型'}}</a-tag>
- </template>
- <template v-if="column.key === 'rtsUrl'" >
- {{record.rtsUrl ? '支持': '否'}}
- </template>
- <template v-if="column.key === 'action'">
- <a-space>
- <a @click="goDetailPage(record.id)">查看</a>
- <a @click="goDebugPage(record.id)" >调试</a>
- <a @click="goAnalysisPage(record.id)">分析</a>
- <a-popconfirm
- title="确实要删除吗?"
- ok-text="确定"
- cancel-text="取消"
- @confirm="delDevice(record.id)"
- >
- <a href="#">删除</a>
- </a-popconfirm>
- </a-space>
- </template>
- </template>
- </a-table>
- </a-card>
- <a-modal
- title="单设备注册"
- :open="state.visible"
- @cancel="state.visible = false"
- @ok="ok"
- >
- <a-form :labelCol="{span: 6}" :wrapperCol="{span: 14}" >
- <a-form-item label="所属产品" v-bind="validateInfosDeviceState.modelId" >
- <a-select allowClear v-model:value="deviceState.modelId" >
- <a-select-option
- v-for="item in state.modelList"
- :key="item.id"
- :value="item.id"
- >
- {{item.modelLabel}}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item label="设备标识码" v-bind="validateInfosDeviceState.deviceCode" >
- <a-input allowClear v-model:value="deviceState.deviceCode" />
- </a-form-item>
- <a-form-item label="设备名称" >
- <a-input allowClear v-model:value="deviceState.deviceLabel" />
- </a-form-item>
- <a-form-item label="设备认证类型" >
- <a-radio-group v-model:value="deviceState.deviceAuthType">
- <a-radio value="SECRET">密钥认证</a-radio>
- <a-radio value="X509CERT">x509证书</a-radio>
- </a-radio-group>
- </a-form-item>
- <a-form-item label="密匙" v-if="deviceState.deviceAuthType === DeviceAuthTypeEnum.SECRET " >
- <a-input-password allowClear v-model:value="deviceState.deviceSecret" />
- </a-form-item>
- <a-form-item label="确认密匙" v-if="deviceState.deviceAuthType === DeviceAuthTypeEnum.SECRET ">
- <a-input-password allowClear v-model:value="deviceState.confirmSecret" />
- </a-form-item>
- </a-form>
- </a-modal>
- </template>
- <script lang="ts" setup >
- import { DeviceContriller, ModelController } from '@/controller/index'
- import { onMounted, reactive, ref, toRefs, nextTick, computed, watch } from 'vue'
- import { Form, message } from 'ant-design-vue'
- import { DeviceAuthTypeEnum } from '@/enum/common'
- import { useRoute, useRouter } from 'vue-router'
- import { DownOutlined } from '@ant-design/icons-vue'
- const useForm = Form.useForm
- const router = useRouter()
- const modelId = (useRoute().query.modelId || '') as string
- console.log('modelId:', modelId)
- const columns = [
- {
- title: '设备ID',
- dataIndex: 'id',
- key: 'id',
- ellipsis: true
- },
- {
- title: '设备名称',
- dataIndex: 'deviceLabel',
- ellipsis: true
- },
- {
- title: '设备标识码',
- dataIndex: 'deviceCode',
- ellipsis: true
- },
- {
- title: '设备描述',
- dataIndex: 'deviceDescription',
- ellipsis: true
- },
- {
- title: '节点类型',
- dataIndex: 'deviceNodeType',
- key: 'deviceNodeType',
- width: 100
- },
- {
- title: '所属产品',
- dataIndex: 'modelLabel',
- ellipsis: true
- },
- {
- title: '支持live',
- dataIndex: 'rtsUrl',
- key: 'rtsUrl',
- width: 100
- },
- {
- title: '状态',
- dataIndex: 'deviceStatus',
- key: 'deviceStatus',
- ellipsis: true,
- width: 80
- },
- {
- title: '操作',
- key: 'action'
- }
- ]
- const searchList = [
- { name: '设备id', key: 'deviceId' },
- { name: '设备名称', key: 'deviceLabel' },
- { name: '设备标识码', key: 'deviceCode' }
- ]
- const analysisList = [
- { label: '上下线分析', key: 'session' },
- { label: '属性分析', key: 'attr' }
- ]
- const state = reactive<{
- modelId: string,
- deviceCount: any,
- dataSource: IOT.API.DEVICE.Device[],
- loading: boolean,
- visible: boolean,
- opraState: 'add' | 'update',
- modelList: IOT.API.MODEL.ModelDot[]
- analysisVisible: boolean
- analysisType: 'session' | 'attr' | ''
- }>({
- modelId: modelId,
- deviceCount: [],
- dataSource: [],
- modelList: [],
- loading: false,
- visible: false,
- analysisVisible: false,
- analysisType: '',
- opraState: 'add'
- })
- const searchState = reactive({
- page: 1,
- pageSize: 10,
- total: 0,
- deviceStatus: null,
- modelId: modelId,
- searchKey: 'deviceId',
- searchValue: '',
- showSizeChanger: false
- })
- const deviceState = reactive({
- id: '',
- modelId: '',
- deviceLabel: '',
- deviceCode: '',
- deviceDescription: '',
- deviceAuthType: DeviceAuthTypeEnum.SECRET,
- modelLabel: '',
- deviceSecret: '',
- confirmSecret: ''
- })
- const { resetFields, validate, validateInfos } = useForm(searchState, {})
- const { resetFields: resetFieldsDevice, validate: validateDevice, validateInfos: validateInfosDeviceState } = useForm(deviceState, reactive({
- modelId: [{ required: true, message: '请选择所属产品' }],
- deviceCode: [{ required: true, message: '请填写设备码' }]
- }))
- const changePage = ({ current }) => {
- searchState.page = current
- getDevicePage()
- }
- const goDebugPage = (id: string) => {
- router.push({ path: '/devOps/onlineTest', query: { id } })
- }
- const goDetailPage = (id: string) => {
- router.push({ path: '/device/detail', query: { id } })
- }
- const delDevice = async (id: string) => {
- await DeviceContriller.del(id)
- getDevicePage()
- }
- const goAnalysisPage = (id: string) => {
- router.push({ path: '/device/analysis', query: { id } })
- }
- const ok = () => {
- if (deviceState.deviceAuthType === DeviceAuthTypeEnum.SECRET && deviceState.deviceSecret !== deviceState.confirmSecret) {
- message.warn('两次密匙输入不同')
- return
- }
- validateDevice().then(async (r) => {
- await DeviceContriller.post(deviceState)
- state.visible = false
- getDevicePage()
- })
- }
- const getModelList = async () => {
- const { data } = await ModelController.list()
- state.modelList = data
- }
- const openModal = (opraState: 'add' | 'update', record:Partial<IOT.API.DEVICE.Device> = {}) => {
- state.visible = true
- state.opraState = opraState
- getModelList()
- resetFieldsDevice({})
- }
- const getDevicePage = async () => {
- state.loading = true
- const { data, sum } = await DeviceContriller.page(searchState)
- state.loading = false
- state.dataSource = data
- searchState.total = sum
- }
- const getDeviceStatistics = async () => {
- const data = await DeviceContriller.statistics({ modelId: state.modelId })
- state.deviceCount = data as any
- }
- onMounted(() => {
- getDeviceStatistics()
- getDevicePage()
- })
- </script>
- <style lang="less" scoped >
- @import '~@/styles/theme.less';
- .statistic {
- color: @sublabel-color;
- .count {
- font-size: 48px;
- margin-right: 10px;
- }
- }
- .label {
- font-size: 18px;
- color: @sublabel-color;
- }
- </style>
|