• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Go Wails Docker图形界面管理工具 (1)

武飞扬头像
LeoForBest
帮助1

1.背景

市面上已有很多顶级Docker 图形界面管理工具,出于学习容器开发目的,计划动手写个简单的界面管理工具

2. 技术选型

2.1 Wails

使用 Go 和 Web 技术编写桌面应用的项目,类似于ElectronJS 。

官方网站 https://wails.io/zh-Hans/docs/introduction/

2.2 Go

Docker本身采用Go编写,官网SDK如下

官方网站 https://docs.docker.com/engine/api/sdk/

2.3 Ant Design Vue

开箱即用的高质量 Vue 组件,使用方便

官方网站 https://www.antdv.com/docs/vue/introduce-cn

3. 当前功能

项目地址 https://github.com/LeoBest2/my-docker-gui

  • 容器查看、创建、启动、删除功能
  • 其他待研究

4. 效果图

学新通
学新通

5. 踩的坑备忘

JS异步处理问题:
版本1中调用的ContainerStop是异步执行的,调用最后的handleRefresh刷新界面时实际执行的容器可能操作没完成,导致界面操作完成后不变

参考: https://blog.csdn.net/weixin_39629679/article/details/111261923 修改为版本2得以解决

版本1

   <script setup>
   const handleStop = () => {
    spinning.value = true;
    selectedRows.value.forEach((row) => {
        ContainerStop(row.ID).then(() => { message.success(`容器${row.Names[0].substring(1)}停止成功!`); }).catch((e) => message.error(`容器${row.Names[0].substring(1)}停止失败: ${e}!`));
    });
    handleRefresh();
};

</script>

版本2

   <script setup>
   const handleStop = () => {
    spinning.value = true;
    let promises = [];
    selectedRows.value.forEach((row) => {
        let p = ContainerStop(row.ID)
        p.then(() => { message.success(`容器${row.Names[0].substring(1)}停止成功!`); }).catch((e) => message.error(`容器${row.Names[0].substring(1)}停止失败: ${e}!`));
        promises.push(p);
    });
    Promise.all(promises).finally(() => { spinning.value = false; handleRefresh() });
};

</script>

总代码

<template>
    <a-spin :spinning="spinning">
        <div>
            <div class="table-operations">
                <a-button @click="handleRefresh">刷新容器</a-button>
                <a-popconfirm :title="'确定启动已选的 '   selectedRows.length   ' 个容器?'" ok-text="确定" cancel-text="取消"
                    @confirm="handleStart">
                    <a-button>启动容器</a-button>
                </a-popconfirm>

                <a-popconfirm :title="'确定停止已选的 '   selectedRows.length   ' 个容器?'" ok-text="确定" cancel-text="取消"
                    @confirm="handleStop">
                    <a-button>停止容器</a-button>
                </a-popconfirm>

                <a-popconfirm :title="'确定删除已选的 '   selectedRows.length   ' 个容器?'" ok-text="确定" cancel-text="取消"
                    @confirm="handleDelete">
                    <a-button type="danger">删除容器</a-button>
                </a-popconfirm>
            </div>
            <a-table :row-selection="{ onChange: (selectedRowKeys, _selectedRows) => selectedRows = _selectedRows }"
                row-key="ID" :columns="columns" :data-source="data" :scroll="{ x: 'max-content' }">
                <template #bodyCell="{ column, record }">
                    <template v-if="column.dataIndex === 'Names'">
                        <a-tag v-for="name in record.Names" color="geekblue">{{ name.substring(1) }}</a-tag>
                    </template>
                    <template v-else-if="column.dataIndex === 'State'">
                        <a-tag :color="record.State == 'running' ? 'green' : 'volcano'">{{ record.State }}</a-tag>
                    </template>
                    <template v-else-if="column.dataIndex === 'Ports'">
                        <a-tag v-for="port in record.Ports">
                            {{ port.IP }}:{{ port.PublicPort }}->{{ port.PrivatePort }}/{{ port.Type }}
                        </a-tag>
                    </template>
                </template>
            </a-table>
        </div>
    </a-spin>
</template>
<script setup>
import { ref } from 'vue';
import { ContainerList, ContainerStop, ContainerStart, ContainerDelete } from "../../wailsjs/go/main/App";
import { message } from "ant-design-vue";

const spinning = ref(false);

const columns = [{
    title: 'ID',
    dataIndex: 'ID',
    fixed: 'left',
}, {
    title: 'NAMES',
    dataIndex: 'Names',
    fixed: 'left',
}, {
    title: 'STATE',
    dataIndex: 'State',
    fixed: 'left',
}, {
    title: 'IMAGE',
    dataIndex: 'Image',
}, {
    title: 'COMMAND',
    dataIndex: 'Command',
}, {
    title: 'CREATED',
    dataIndex: 'Created',
}
    , {
    title: 'STATUS',
    dataIndex: 'Status',
}, {
    title: 'PORTS',
    dataIndex: 'Ports',
}];

const data = ref([]);
const selectedRows = ref([]);

const handleRefresh = () => {
    ContainerList()
        .then((containers) => {
            data.value = containers;
        })
        .catch(e => message.error(e));
};

const handleStart = () => {
    spinning.value = true;
    let promises = [];
    selectedRows.value.forEach((row) => {
        let p = ContainerStart(row.ID)
        p.then(() => message.success(`容器${row.Names[0].substring(1)}启动成功!`)).catch((e) => message.error(`容器${row.Names[0].substring(1)}启动失败: ${e}!`));
        promises.push(p);
    });
    Promise.all(promises).finally(() => { spinning.value = false; handleRefresh() });
};

const handleStop = () => {
    spinning.value = true;
    let promises = [];
    selectedRows.value.forEach((row) => {
        let p = ContainerStop(row.ID)
        p.then(() => { message.success(`容器${row.Names[0].substring(1)}停止成功!`); }).catch((e) => message.error(`容器${row.Names[0].substring(1)}停止失败: ${e}!`));
        promises.push(p);
    });
    Promise.all(promises).finally(() => { spinning.value = false; handleRefresh() });
};

const handleDelete = () => {
    spinning.value = true;
    let promises = [];
    selectedRows.value.forEach((row) => {
        let p = ContainerDelete(row.ID)
        p.then(() => { message.success(`容器${row.Names[0].substring(1)}停止成功!`); }).catch((e) => message.error(`容器${row.Names[0].substring(1)}停止失败: ${e}!`));
        promises.push(p);
    });
    Promise.all(promises).finally(() => { spinning.value = false; handleRefresh() });
};

</script>

<style scoped>
.table-operations {
    margin-bottom: 16px;
}

.table-operations>button {
    margin-right: 8px;
}
</style>
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfiahj
系列文章
更多 icon
同类精品
更多 icon
继续加载