无人机管理后台前端(已迁走)
linwe
2024-10-12 0b2008314be7ab3d1f0c59aa7ce2a21468a08c7b
新增设备管理
2 files added
575 ■■■■■ changed files
src/api/device/workspaces.js 50 ●●●●● patch | view | raw | blame | history
src/views/device/addDevice.vue 525 ●●●●● patch | view | raw | blame | history
src/api/device/workspaces.js
New file
@@ -0,0 +1,50 @@
import request from '@/axios';
export const getList = (current, size, params) => {
    return request({
        url: '/drone-yw/manage/api/v1/workspaces/page',
        method: 'get',
        params: {
            ...params,
            current,
            size,
        },
    });
};
export const remove = ids => {
    return request({
        url: '/drone-yw/manage/api/v1/workspaces/delete',
        method: 'post',
        params: {
            ids,
        },
    });
};
export const add = row => {
    return request({
        url: '/drone-yw/manage/api/v1/workspaces/add',
        method: 'post',
        data: row,
    });
};
export const update = row => {
    return request({
        url: '/drone-yw/manage/api/v1/workspaces/update',
        method: 'post',
        data: row,
    });
};
export const getDetail = id => {
    return request({
        url: '/drone-yw/manage/api/v1/workspaces/selectById',
        method: 'get',
        params: {
            id,
        },
    });
};
src/views/device/addDevice.vue
New file
@@ -0,0 +1,525 @@
<template>
    <basic-container>
        <avue-crud :option="option" :table-loading="loading" :data="data" v-model:page="page" ref="crud" @row-del="rowDel"
            v-model="form" :permission="permissionList" @row-update="rowUpdate" @row-save="rowSave"
            :before-open="beforeOpen" @search-change="searchChange" @search-reset="searchReset"
            @selection-change="selectionChange" @current-change="currentChange" @size-change="sizeChange"
            @refresh-change="refreshChange" @on-load="onLoad" @tree-load="treeLoad">
            <template #menu="scope">
                <el-button type="primary" text icon="el-icon-plus" @click.stop="copyInfo(scope.row, scope.index)"
                    v-if="userInfo.role_name.includes('admin')">复制信息
                </el-button>
            </template>
        </avue-crud>
    </basic-container>
</template>
<script>
import {
    getList,
    remove,
    update,
    add,
    getDetail,
} from '@/api/device/workspaces';
import { getLazyTree } from '@/api/base/region';
import { mapGetters } from 'vuex';
import { getWebsocketUrl } from '@/websocket/util/config';
import ConnectWebSocket from '@/websocket';
import { $Clipboard } from "@smallwei/avue";
export default {
    components: {
    },
    data() {
        return {
            // 用于记录已经创建的websocket,防止重复创建
            webSocketIdSet: new Set(),
            // 用于保存多组websocket
            websocketMap: new Map(),
            scheduleNum: 0,
            webSocket: '',
            devicePerShareVisible: false,
            remoteDebuggingShow: false,
            curDeviceInfo: {},
            firmwareManageVisible: false,
            percentageNum: 0,
            firmwareBox: false,
            firmwareInfo: {},
            form: {},
            query: {},
            firmwareVersion: '',
            loading: true,
            page: {
                pageSize: 10,
                currentPage: 1,
                total: 0,
            },
            selectionList: [],
            option: {
                lazy: true,
                tree: true,
                height: '460',
                calcHeight: 32,
                dialogWidth: 1050,
                tip: false,
                searchShow: true,
                searchMenuSpan: 6,
                border: true,
                index: true,
                viewBtn: true,
                selection: false,
                excelBtn: false,
                addBtn: true,
                dialogClickModal: false,
                grid: false,
                column: [
                    {
                        label: '工作空间名称',
                        prop: 'workspace_name',
                        editDisabled: true,
                        searchLabelWidth: 130,
                        search: true,
                        // searchSpan: 4,
                        labelWidth: 130,
                        rules: [
                            {
                                required: true,
                                message: '请输入工作空间名称',
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '工作空间描述',
                        prop: 'workspace_desc',
                        labelWidth: 130,
                        // search: true,
                        searchSpan: 4,
                        // editDisabled: true,
                        rules: [
                            {
                                required: true,
                                message: '请输入工作空间描述',
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '平台名称',
                        prop: 'platform_name',
                        labelWidth: 130,
                        editDisabled: true,
                        rules: [
                            {
                                required: false,
                                message: '请输入平台名称',
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '所属单位',
                        prop: 'dept_id',
                        type: 'tree',
                        defaultExpandAll: true,
                        labelWidth: 130,
                        dicUrl: '/blade-system/dept/getTree',
                        props: {
                            label: 'name',
                            value: 'id',
                        },
                        rules: [
                            {
                                required: true,
                                message: '请输入所属单位',
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '绑定编号',
                        prop: 'bind_code',
                        labelWidth: 130,
                        editDisabled: true,
                        rules: [
                            {
                                required: false,
                                message: '请输入绑定编号',
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '创建时间',
                        prop: 'create_time',
                        addDisplay: false,
                        editDisplay: false,
                        type: 'date',
                        labelWidth: 130,
                        width: 160,
                        format: 'YYYY-MM-DD HH:mm:ss',
                    },
                ],
            },
            data: [],
            DeviceFirmwareTypeEnum: {
                // 普通升级
                ToUpgraded: 3,
                // 一致性升级
                ConsistencyUpgrade: 2,
            },
            DeviceFirmwareStatusEnum: {
                None: 1, // 无需升级
                ToUpgraded: 2, // 待升级
                ConsistencyUpgrade: 3, // 一致性升级
                DuringUpgrade: 4, // 升级中
            },
        };
    },
    computed: {
        ...mapGetters(['userInfo', 'permission']),
        permissionList() {
            return {
                addBtn: this.validData(this.permission.airport_add, false),
                viewBtn: this.validData(this.permission.airport_view, true),
                delBtn: this.validData(this.permission.airport_delete, false),
                editBtn: this.validData(this.permission.airport_edit, false),
            };
        },
        ids() {
            let ids = [];
            this.selectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(',');
        },
    },
    destroyed() {
        this.websocketMap.forEach((k, v) => {
            if (null != v) {
                v.close()
                this.websocketMap.delete(k)
                this.webSocketIdSet.delete(k)
            }
        });
    },
    methods: {
        copyInfo(row, index) {
            let params = `host: tcp://139.196.74.78:1883   账号:drone  密码:123456  组织id:${row.bing_id}  设备码:${row.bind_code}  机场名称:${row.workspace_name}   aircrattName:${row.workspace_desc}`;
            $Clipboard({
                text: params,
            }).then(() => {
                this.$message.success("复制成功");
            }).catch(() => {
                this.$message.error("复制失败");
            });
        },
        // 关闭所有的webscoket
        closeAllWebsoket() {
            this.websocketMap.forEach((k, v) => {
                if (null != v) {
                    v.close()
                    this.websocketMap.delete(k)
                    this.webSocketIdSet.delete(k)
                }
            });
        },
        // 连接webSocket
        connectWebSocket(data) {
            const webSocketId = data.workspace_id
            if (!this.webSocketIdSet.has(webSocketId)) {
                // 防止重复连接
                this.webSocketIdSet.add(webSocketId);
                const webSorketUrl = getWebsocketUrl() + '&workspace-id=' + data.workspace_id;
                // 监听ws 消息
                this.useConnectWebSocket(webSocketId, webSorketUrl);
            }
        },
        useConnectWebSocket(webSocketId, url) {
            const websocket = new ConnectWebSocket(url);
            // 加入 webscoket map
            this.websocketMap.set(webSocketId, websocket)
            websocket?.registerMessageHandler(this.messageHandler);
            websocket?.initSocket();
        },
        async messageHandler(payload) {
            console.log(payload, 7777);
            if (!payload) {
                return;
            }
            if (payload.biz_code != "ota_progress") {
                return;
            }
            var data = payload.data;
            this.data.forEach(e => {
                if (e.device_sn == data.sn && data.output.status == 'in_progress') {
                    e.firmware_progress = data.output.progress.percent;
                }
                if (e.device_sn == data.sn && data.output.status == 'ok') {
                    // 升级完成修改状态
                    e.firmware_status = 1
                    const webscoket = this.websocketMap.get(e.workspace_id);
                    // 关闭
                    webscoket?.close();
                    //删除对应的webscoket
                    this.websocketMap.delete(e.workspace_id);
                    this.webSocketIdSet.delete(e.workspace_id);
                }
            });
        },
        init() {
            this.onLoad(this.page);
        },
        // 打开权限分享页面
        handleOpenDevicePerShare(row) {
            var that = this;
            this.devicePerShareVisible = true;
            this.$nextTick(() => {
                that.$refs.devicePerShare.init(row);
            });
        },
        handleOpenRemoteDebugging(row) {
            this.curDeviceInfo = row;
            this.remoteDebuggingShow = true;
        },
        // 打开固件管理页面
        handleOpenFirmwarm(row) {
            var that = this;
            this.firmwareManageVisible = true;
            this.$nextTick(() => {
                that.$refs.firmwareManage.init(row);
            });
        },
        // 升级固件按钮事件
        updateFirmware(row) {
            if (row.status == 0) {
                this.$message({
                    type: 'warning',
                    message: '设备不在线!',
                });
                return;
            }
            var that = this;
            this.firmwareBox = true;
            const param = {
                device_name: row.device_name,
            };
            // 获取固件最新版本信息
            getDeviceUpgradeInfo(param).then(res => {
                const data = res.data.data;
                if (data.length === 0) {
                    return;
                }
                that.firmwareVersion = data[0].product_version;
                that.firmwareInfo['device_name'] = row.device_name;
                that.firmwareInfo['sn'] = row.device_sn;
                that.firmwareInfo['product_version'] = data[0].product_version;
                // 1-普通升级,2-一致性升级;
                that.firmwareInfo['firmware_upgrade_type'] =
                    row.firmware_status === that.DeviceFirmwareStatusEnum.ToUpgraded
                        ? that.DeviceFirmwareTypeEnum.ToUpgraded
                        : that.DeviceFirmwareTypeEnum.ConsistencyUpgrade;
                that.firmwareInfo['workspaceId'] = row.workspace_id;
            });
        },
        // 确定升级固件版本
        updateFirmwareConfirm() {
            var that = this;
            var arr = [];
            arr.push(that.firmwareInfo);
            ota(that.firmwareInfo.workspaceId, arr).then(res => {
                that.firmwareVersion = '';
                that.firmwareInfo = {};
                that.firmwareBox = false;
                this.$message({
                    type: 'success',
                    message: '操作成功!',
                });
                this.onLoad(this.page);
                done();
            });
        },
        rowSave(row, done, loading) {
            add(row).then(
                () => {
                    this.onLoad(this.page);
                    this.$message({
                        type: 'success',
                        message: '操作成功!',
                    });
                    done();
                },
                error => {
                    window.console.log(error);
                    loading();
                }
            );
        },
        rowUpdate(row, index, done, loading) {
            update(row).then(
                () => {
                    this.onLoad(this.page);
                    this.$message({
                        type: 'success',
                        message: '操作成功!',
                    });
                    done();
                },
                error => {
                    window.console.log(error);
                    loading();
                }
            );
        },
        rowDel(row) {
            this.$confirm('确定将选择数据删除?', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            })
                .then(() => {
                    return remove(row.id);
                })
                .then(() => {
                    this.onLoad(this.page);
                    this.$message({
                        type: 'success',
                        message: '操作成功!',
                    });
                });
        },
        searchReset() {
            this.query = {};
            this.onLoad(this.page);
        },
        searchChange(params, done) {
            this.query = params;
            this.page.currentPage = 1;
            this.onLoad(this.page, params);
            done();
        },
        selectionChange(list) {
            this.selectionList = list;
        },
        selectionClear() {
            this.selectionList = [];
            this.$refs.crud.toggleSelection();
        },
        handleDelete() {
            if (this.selectionList.length === 0) {
                this.$message.warning('请选择至少一条数据');
                return;
            }
            this.$confirm('确定将选择数据删除?', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            })
                .then(() => {
                    return remove(this.ids);
                })
                .then(() => {
                    this.onLoad(this.page);
                    this.$message({
                        type: 'success',
                        message: '操作成功!',
                    });
                    this.$refs.crud.toggleSelection();
                });
        },
        beforeOpen(done, type) {
            if (['edit', 'view'].includes(type)) {
                getDetail(this.form.id).then(res => {
                    this.form = res.data.data;
                });
            }
            done();
        },
        currentChange(currentPage) {
            this.page.currentPage = currentPage;
        },
        sizeChange(pageSize) {
            this.page.pageSize = pageSize;
        },
        refreshChange() {
            this.onLoad(this.page, this.query);
        },
        onLoad(page, params = {}) {
            this.closeAllWebsoket()
            const { releaseTimeRange } = this.query;
            let values = {
                ...params,
                ...this.query,
            };
            if (releaseTimeRange) {
                values = {
                    ...values,
                    releaseTime_datege: releaseTimeRange[0],
                    releaseTime_datelt: releaseTimeRange[1],
                };
                values.releaseTimeRange = null;
            }
            values['type'] = 1;
            this.loading = true;
            getList(page.currentPage, page.pageSize, values).then(res => {
                const data = res.data.data;
                this.page.total = data.total;
                data.records.forEach(e => {
                    e['hasChildren'] = e.has_children;
                    if (e.firmware_status == 4) {
                        this.connectWebSocket(e);
                    }
                });
                this.data = data.records;
                this.loading = false;
                this.selectionClear();
            });
        },
        treeLoad(tree, treeNode, resolve) {
            var params = {
                childSn: tree.child_sn,
            };
            getList(1, 10, params).then(res => {
                const data = res.data.data.records;
                resolve(data);
            });
        },
    },
};
</script>
<style lang="scss" scoped>
.firmware_status {
    background-color: aqua;
    border-radius: 4px;
}
.firmware_status:hover {
    cursor: pointer;
    /* color: aqua; */
}
.active-element {
    cursor: pointer;
    &:hover {
        background-color: #409eff;
        border-color: #409eff;
    }
}
</style>