go-via后端ag-grid示例代码

package main

import (
	"encoding/json"
	"math/rand"
	"net/http"
	"sync"
	"time"
	"github.com/go-via/via"
	"github.com/go-via/via/h"
)

type Host struct {
	Name      string `json:"name"`
	Status    string `json:"status"`
	IPAddress string `json:"ip"`
	Version   string `json:"version"`
	CPUs      int    `json:"cpus"`
	MemoryGB  int    `json:"memoryGB"`
	StorageGB int    `json:"storageGB"`
}

var (
	hosts = []Host{
		{Name: "ESXi-01", Status: "运行中", IPAddress: "192.168.1.101", Version: "7.0 U3", CPUs: 32, MemoryGB: 256, StorageGB: 2048},
		{Name: "ESXi-02", Status: "运行中", IPAddress: "192.168.1.102", Version: "7.0 U3", CPUs: 24, MemoryGB: 192, StorageGB: 1536},
		{Name: "ESXi-03", Status: "维护中", IPAddress: "192.168.1.103", Version: "6.7 U3", CPUs: 16, MemoryGB: 128, StorageGB: 1024},
		{Name: "ESXi-04", Status: "运行中", IPAddress: "192.168.1.104", Version: "8.0 U1", CPUs: 48, MemoryGB: 512, StorageGB: 4096},
		{Name: "ESXi-05", Status: "已关机", IPAddress: "192.168.1.105", Version: "7.0 U2", CPUs: 20, MemoryGB: 128, StorageGB: 1024},
	}
	hostsMutex sync.Mutex
	rng        = rand.New(rand.NewSource(time.Now().UnixNano()))
)

type Page struct {
}

func (p *Page) View(ctx *via.CtxR) h.H {
	return h.Div(h.Class("container"),
		h.H1(h.Text("ESXi 主机管理面板")),
		h.Div(h.ID("myGrid"), h.Class("ag-theme-alpine")),
	)
}

func main() {
	app := via.New(
		via.WithTitle("ESXi 主机管理面板"),
		via.WithInsecureCookies(),
	)

	app.AppendToHead(h.StyleEl(h.Raw(`
		body { margin: 0; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
		.container { max-width: 1400px; margin: 0 auto; }
		h1 { color: #333; margin-bottom: 20px; }
		#myGrid { height: 600px; width: 100%; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); }
		.status-running { color: #10b981; font-weight: 600; }
		.status-maintenance { color: #f59e0b; font-weight: 600; }
		.status-offline { color: #ef4444; font-weight: 600; }
	`)))
	app.AppendToHead(h.Link(h.Rel("stylesheet"), h.Href("https://esm.sh/ag-grid-community@36/styles/ag-theme-alpine.min.css")))
	app.AppendToHead(h.Script(h.Type("importmap"), h.Raw(`
		{
			"imports": {
				"ag-grid-community": "https://esm.sh/ag-grid-community@36"
			}
		}
	`)))
	app.AppendToFoot(h.Script(h.Type("module"), h.Raw(`
		import { createGrid, ModuleRegistry, AllCommunityModule } from 'ag-grid-community';

		ModuleRegistry.registerModules([AllCommunityModule]);

		const columnDefs = [
			{ headerName: '主机名', field: 'name', sortable: true, filter: true, width: 120 },
			{ 
				headerName: '状态', 
				field: 'status', 
				sortable: true, 
				filter: true,
				width: 100,
				cellClass: params => {
					if (params.value === '运行中') return 'status-running';
					if (params.value === '维护中') return 'status-maintenance';
					return 'status-offline';
				}
			},
			{ headerName: 'IP 地址', field: 'ip', sortable: true, filter: true, width: 140 },
			{ headerName: '版本', field: 'version', sortable: true, filter: true, width: 100 },
			{ headerName: 'CPU 核心', field: 'cpus', sortable: true, filter: true, width: 100 },
			{ headerName: '内存 (GB)', field: 'memoryGB', sortable: true, filter: true, width: 120 },
			{ headerName: '存储 (GB)', field: 'storageGB', sortable: true, filter: true, width: 120 }
		];

		const gridOptions = {
			columnDefs: columnDefs,
			rowData: [],
			pagination: true,
			paginationPageSize: 10,
			paginationPageSizeSelector: [10, 20, 50, 100],
			rowSelection: 'multiple',
			getRowId: params => params.data.name,
			defaultColDef: {
				resizable: true,
				filter: true,
				sortable: true
			},
			onGridReady: async (params) => {
				let isFirstLoad = true;
				const fetchData = async () => {
					try {
						const response = await fetch('/api/hosts');
						const data = await response.json();
						if (isFirstLoad) {
							params.api.applyTransaction({ add: data });
							isFirstLoad = false;
						} else {
							params.api.applyTransaction({ update: data });
						}
					} catch (error) {}

				};
				await fetchData();
				setInterval(fetchData, 5000);
			}
		};

		createGrid(document.getElementById('myGrid'), gridOptions);
	`)))
	app.HandleFunc("GET /api/hosts", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		hostsMutex.Lock()

		defer hostsMutex.Unlock()

		result := make([]Host, len(hosts))

		for i, host := range hosts {
			result[i] = host

			if rng.Float64() < 0.3 {
				statuses := []string{"运行中", "维护中", "已关机"}
				result[i].Status = statuses[rng.Intn(len(statuses))]
			}

			result[i].CPUs = host.CPUs + rng.Intn(5) - 2

			if result[i].CPUs < 1 {
				result[i].CPUs = 1
			}

			result[i].MemoryGB = host.MemoryGB + rng.Intn(17) - 8

			if result[i].MemoryGB < 1 {
				result[i].MemoryGB = 1
			}

			result[i].StorageGB = host.StorageGB + rng.Intn(101) - 50

			if result[i].StorageGB < 1 {
				result[i].StorageGB = 1
			}
		}

		json.NewEncoder(w).Encode(result)
	})
	via.Mount[Page](app, "/")

	if err := http.ListenAndServe(":8081", app); err != nil {
		panic(err)
	}
}
posted @ 2026-06-26 22:37  卓能文  阅读(6)  评论(0)    收藏  举报