123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Card Waterfall</title>
- <link rel="stylesheet" href="./static/styles.css">
- <script src="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/3.2.31/vue.global.min.js"></script>
- <style>
-
- </style>
- </head>
- <body>
- <div id="app">
- <div class="card-container">
- <div v-for="(card, index) in cards" :key="index" class="card" @click="showCardDetails(card)">
- <img :src="card.image" alt="Card Image">
- <div class="title">{{ card.title }}</div>
- <div class="content">{{ card.content }}</div>
- <div class="date">{{ card.date }}</div>
- </div>
- <!-- Default Add Card -->
- <div class="card add-card" @click="openAddCardModal">
- <div class="add-icon">+</div>
- </div>
- </div>
- <!--card Modal -->
- <div class="card-modal" :class="{ active: showModal }">
- <div class="card-modal-container">
- <div class="card-modal-left">
- <button class="card-modal-close-button" @click="showModal = false">关闭</button>
-
- </div>
-
- <div class="card-modal-right">
- <h3>{{ modalTitle }}</h3>
- <div v-if="modalCard">
- <div v-for="(group, groupIndex) in modalCard.groups" :key="groupIndex" class="card-modal-group-box-container">
- <!-- 循环展示 conn_info 里的信息 -->
- <div v-for="(conn, connIndex) in group.conn_info" :key="connIndex" class="card-modal-group-box">
-
- <div class="state-box">节点状态</div>
- <div class="title"> <strong>节点 {{ connIndex + 1 }}</strong></div>
-
- <div class="content">{{ conn.ssh_info.host }} <strong>端口:</strong> {{ conn.ssh_info.port }}</div>
-
- <p><strong>用户:</strong> {{ conn.ssh_info.username }} <strong>密码:</strong> {{ conn.ssh_info.password }}</p>
-
- <p><strong>数据库:</strong> {{ conn.db_info.database }} <strong></strong>端口:</strong> {{ conn.db_info.port }}</p>
-
- <p><strong>用户:</strong> {{ conn.db_info.user }} <strong>密码:</strong> {{ conn.db_info.password }}</p>
-
- <div class="menu-bar">
- <button @click="modifyGroup(connIndex)">修改</button>
- <button @click="groupNodeDetail(conn,group.base_filename)">详情</button>
- <button @click="setSystemInfo(conn,group.base_filename)">获取系统信息</button>
- </div>
- </div>
- </div>
- </div>
- <div v-else>
- <div v-for="(group, index) in formGroups" :key="index" class="group-box">
- <input v-model="group.ssh_ip" placeholder="服务器 IP 地址(必选项)">
- <input v-model="group.ssh_port" placeholder="服务器 SSH 端口 默认 22">
- <input v-model="group.ssh_username" placeholder="服务器 登录用户名">
- <input v-model="group.ssh_password" placeholder="服务器 登录密码">
- <input v-model="group.db_port" placeholder="数据库 端口">
- <input v-model="group.db_database" placeholder="数据库 库名">
- <input v-model="group.db_user" placeholder="数据库 用户名">
- <input v-model="group.db_password" placeholder="数据库 密码">
- </div>
- <div class="modal-buttons">
- <button @click="addGroup">新增一组</button>
- <button @click="removeGroup" v-if="formGroups.length > 1">删除一组</button>
- </div>
- <div class="modal-buttons">
- <button @click="addNewCard">添加</button>
- <button @click="showModal = false">取消</button>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- Group Node Detail Modal 组里节点的模态框-->
- <div class="group-node-modal" :class="{ active: showGroupModal }">
- <div class="group-node-modal-container">
- <div class="group-node-modal-content">
- <button class="group-node-modal-close-button" @click="showGroupModal = false">关闭</button>
- <h3>组详细信息</h3>
- <div v-if="currentGroup && currentGroup.systemInfo">
- <p><strong>节点状态:</strong> <span>{{ currentGroup.systemInfo.status }}</span></p>
-
- <p><strong>SSH 信息:</strong></p>
- <p><strong>Host:</strong> <span>{{ currentGroup.systemInfo.host }}</span></p>
- <p><strong>Port:</strong> <span>{{ currentGroup.systemInfo.port }}</span></p>
- <p><strong>Username:</strong> <span>{{ currentGroup.systemInfo.username }}</span></p>
- <p><strong>Password:</strong> <span>{{ currentGroup.systemInfo.password }}</span></p>
-
- <p><strong>系统信息:</strong></p>
- <p><strong>操作系统 (OS):</strong> <span>{{ currentGroup.systemInfo.os || '再刷新' }}</span></p>
- <p><strong>CPU:</strong> <span>{{ currentGroup.systemInfo.cpu || '再刷新' }}</span></p>
- <p><strong>内存 (Memory):</strong> <span>{{ currentGroup.systemInfo.memory || '再刷新' }}</span></p>
- <p><strong>磁盘 (Disk):</strong> <span>{{ currentGroup.systemInfo.disk || '再刷新' }}</span></p>
- <p><strong>磁盘速度 (DiskSpeed):</strong> <span>{{ currentGroup.systemInfo.diskSpeed || '再刷新' }}</span></p>
- <p><strong>网络 (Network):</strong> <span>{{ currentGroup.systemInfo.network || '再刷新' }}</span></p>
- <p><strong>网络速度 (NetworkSpeed):</strong> <span>{{ currentGroup.systemInfo.networkSpeed || '再刷新' }}</span></p>
- <p><strong>错误 (Error):</strong> <span>{{ currentGroup.systemInfo.error || '再刷新' }}</span></p>
-
- <!-- 添加 "获取最新系统信息" 按钮 -->
- <button @click="setSystemInfo(currentGroup, group.base_filename)">获取最新系统信息</button>
- </div>
- </div>
- </div>
- </div>
- </div>
- <script>
- const app = Vue.createApp({
- data() {
- return {
- cards: [],
- showModal: false,
- formGroups: [
- {
- db_database: '',
- db_password: '',
- db_port: '',
- db_user: '',
- ssh_ip: '',
- ssh_password: '',
- ssh_port: '',
- ssh_username: ''
- }
- ],
- modalCard: null,
- modalTitle: '',
- showGroupModal: false,
- currentGroup: null
- };
- },
- mounted() {
- this.fetchCardData();
- },
- methods: {
- openAddCardModal() {
- this.modalCard = null;
- this.modalTitle = '添加新节点';
- this.showModal = true;
- },
- addGroup() {
- const lastGroup = this.formGroups[this.formGroups.length - 1];
- this.formGroups.push(Object.assign({}, lastGroup));
- },
- removeGroup() {
- if (this.formGroups.length > 1) {
- this.formGroups.pop();
- }
- },
- addNewCard() {
- console.log('开始添加新卡片,准备发送数据...');
- const groupsContent = this.formGroups.map(group => `数据库: ${group.db_database}, 用户: ${group.db_user}, 端口: ${group.db_port}`).join('; ');
- const newCardData = {
- image: 'https://via.placeholder.com/300',
- title: '数据库连接信息',
- content: groupsContent,
- date: new Date().toISOString().split('T')[0]
- };
- // 添加卡片到UI
- this.cards.push(newCardData);
- // 准备发送到服务器的数据
- const dataToSend = this.formGroups.map(group => ({
- ssh_info: {
- username: group.ssh_username,
- password: group.ssh_password,
- host: group.ssh_ip,
- port: group.ssh_port
- },
- db_info: {
- user: group.db_user,
- password: group.db_password,
- database: group.db_database,
- port: group.db_port
- }
- }));
- // 发送数据到服务器
- console.log('正在发送数据:', JSON.stringify(dataToSend));
- fetch('http://127.0.0.1:8080/api/AddConnectInfo', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(dataToSend)
- })
- .then(response => {
- if (!response.ok) {
- throw new Error('网络响应不正常');
- }
- return response.json();
- })
- .then(data => {
- console.log('数据发送成功:', data);
- })
- .catch(error => {
- console.error('发送数据时出错:', error);
- });
- // 关闭模态框并重置表单
- this.showModal = false;
- this.resetFormData();
- },
- resetFormData() {
- this.formGroups = [
- {
- db_database: '',
- db_password: '',
- db_port: '',
- db_user: '',
- ssh_ip: '',
- ssh_password: '',
- ssh_port: '',
- ssh_username: ''
- }
- ];
- },
- fetchCardData() {
- fetch('http://127.0.0.1:8080/api/GetConnectInfo')
- .then(response => response.json())
- .then(data => {
- const connectInfo = data.data;
- console.log("connectInfo :", connectInfo);
- for (let host in connectInfo) {
- if (Object.keys(connectInfo[host]).length === 0) continue;
- const groupData = connectInfo[host];
- const groups = [];
- for (let group in groupData) {
- groups.push(groupData[group]);
- }
- const cardData = {
- image: 'https://via.placeholder.com/300',
- title: `连接信息 - ${host}`,
- groups: groups,
- content: `共 ${groups.length} 组连接信息`,
- date: new Date().toISOString().split('T')[0]
- };
- this.cards.push(cardData);
- }
- })
- .catch(error => {
- console.error('Error fetching connect info:', error);
- });
- },
- showCardDetails(card) {
- console.log("showCardDetails(card) :", card);
- this.modalCard = card;
- this.modalTitle = card.title;
- this.showModal = true;
- },
- modifyGroup(index) {
- alert(`修改组 ${index + 1} 的信息`);
- },
- groupNodeDetail(groups, base_filename) {
-
- console.log("groupNodeDetail(groups) :", groups);
- this.currentGroup = groups; // 设置当前组为选中的组
- this.showGroupModal = true; // 显示组详情模态框
- // 构建要发送的数据
- const dataToSend = {
- base_filename: base_filename || "default_filename", // 如果没有提供 base_filename,可以使用默认值
- username: groups.ssh_info.username,
- password: groups.ssh_info.password,
- host: groups.ssh_info.host,
- port: groups.ssh_info.port
- };
- console.log('发送的数据:', JSON.stringify(dataToSend));
- // 发送 POST 请求到后端接口
- fetch('http://127.0.0.1:8080/api/GetSingleSystemInfo', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(dataToSend)
- })
- .then(response => {
- if (!response.ok) {
- throw new Error('网络响应不正常');
- }
- return response.json();
- })
- .then(data => {
- console.log('接收到的系统信息:', data);
- // 将返回的数据保存到 currentGroup 对象中
- this.currentGroup.systemInfo = {
- os: data.data.Os,
- cpu: data.data.Cpu,
- memory: data.data.Memory,
- disk: data.data.Disk,
- diskSpeed: data.data.DiskSpeed,
- network: data.data.Network,
- networkSpeed: data.data.NetworkSpeed,
- error: data.data.Error
- };
- })
- .catch(error => {
- console.error('获取系统信息时出错:', error);
- });
- },
- setSystemInfo(groups, base_filename) {
- console.log('正在获取系统信息,groups:', groups);
- const connection = groups;
- const dataToSend = [{
- base_filename: base_filename,
- username: connection.ssh_info.username,
- password: connection.ssh_info.password,
- host: connection.ssh_info.host,
- port: connection.ssh_info.port
- }];
- console.log('正在获取系统信息,发送的数据:', JSON.stringify(dataToSend));
- // 1. 发送 POST 请求启动任务
- fetch('http://127.0.0.1:8080/api/SetSystemInfo', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(dataToSend)
- })
- .then(response => {
- console.log('/api/SetSystemInfo POST发送的数据:', JSON.stringify(dataToSend));
- if (!response.ok) {
- throw new Error('网络响应不正常');
- }
- return response.json(); // 假设返回 JSON 格式数据,其中包含 progressID
- })
- .then(data => {
- const progressID = data.progressID;
- console.log('收到的 progressID:', progressID, data);
- // 2. 建立 SSE 长连接,发送 progressID 并接收进度更新
- const eventSource = new EventSource(`http://127.0.0.1:8080/api/GetSystemInfoProgress?progressID=${progressID}`);
- eventSource.addEventListener('progress', (event) => {
- const progressData = JSON.parse(event.data);
- console.log("进度更新:", progressData.message);
- // 获取字段名称 (name) 和数据 (output)
- const [name, server, output] = progressData.message.split(": ");
- // 更新 currentGroup.systemInfo 的相应字段
- if (this.currentGroup.systemInfo.hasOwnProperty(name)) {
- this.$set(this.currentGroup.systemInfo, name, output || '再刷新');
- }
- });
- eventSource.onerror = (event) => {
- console.error("EventSource failed:", event);
- eventSource.close(); // 出错时关闭连接
- };
- })
- .catch(error => {
- console.error('获取系统信息时出错:', error);
- });
- }
- }
- });
- app.mount('#app');
- </script>
- </body>
- </html>
|