吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 31|回复: 0
收起左侧

[其他求助] 豆包生成的 不知道怎么打包成exe 麻烦帮忙打包一下

[复制链接]
xiaoyin2018 发表于 2026-6-14 22:00
200吾爱币
1
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>IP Ping监控平台</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        .stat-card-link {
            cursor: pointer;
            text-decoration: none;
        }
        .stat-card-link:hover {
            opacity: 0.85;
        }
        .stat-card-static {
            cursor: default;
        }
    </style>
</head>
<body class="container mt-4">
    <h2 class="text-center mb-4">IP Ping监控平台(仅IPv4)</h2>
    <div class="alert alert-info">提示:仅支持纯IPv4地址,不支持域名、DNS、网关域名;展示格式:乡镇-村落-设备名称(IP);前3张统计卡片可点击下载对应报表,CSV完美支持中文乡镇/村落名称</div>

    <div class="row mb-4">
        <div class="col-md-3">
            <a class="card text-center p-3 bg-secondary text-white stat-card-link" href="http://127.0.0.1:8000/export/all_ip">
                <h5>IP总数量</h5>
                <h3 id="totalIp">0</h3>
            </a>
        </div>
        <div class="col-md-3">
            <a class="card text-center p-3 bg-success text-white stat-card-link" href="http://127.0.0.1:8000/export/online_ip">
                <h5>在线设备</h5>
                <h3 id="onlineIp">0</h3>
            </a>
        </div>
        <div class="col-md-3">
            <a class="card text-center p-3 bg-danger text-white stat-card-link" href="http://127.0.0.1:8000/export/offline_ip">
                <h5>离线/故障</h5>
                <h3 id="offlineIp">0</h3>
            </a>
        </div>
        <div class="col-md-3">
            <div class="card text-center p-3 bg-primary text-white stat-card-static">
                <h5>在线率</h5>
                <h3 id="onlineRate">0%</h3>
            </div>
        </div>
    </div>

    <div class="card p-3 mb-4">
        <h5>IP管理与报表下载</h5>
        <div class="row g-3 align-items-center">
            <div class="col-auto">
                <input type="file" id="importFile" accept=".csv" class="form-control">
            </div>
            <div class="col-auto">
                <button class="btn btn-primary" onclick="importIp()">批量导入IP</button>
            </div>
            <div class="col-auto">
                <a class="btn btn-success" href="http://127.0.0.1:8000/export/all_ip">导出全部IP</a>
            </div>
            <div class="col-auto">
                <a class="btn btn-success" href="http://127.0.0.1:8000/export/online_ip">导出在线IP</a>
            </div>
            <div class="col-auto">
                <a class="btn btn-danger" href="http://127.0.0.1:8000/export/offline_ip">下载离线IP表</a>
            </div>
            <div class="col-auto">
                <a class="btn btn-warning" href="http://127.0.0.1:8000/export/loss_ip">下载丢包IP表</a>
            </div>
        </div>
        <div class="mt-3">
            <span class="text-secondary">导入csv模板字段:ip,town,village,remark,全部支持中文</span>
        </div>
    </div>

    <div class="card p-3 mb-4">
        <h5>新增监控IP(填写乡镇、村落、设备名称)</h5>
        <div class="row g-2 align-items-center">
            <div class="col-auto">
                <input class="form-control" id="ipAddr" placeholder="IPv4地址">
            </div>
            <div class="col-auto">
                <input class="form-control" id="town" placeholder="乡镇(中文)">
            </div>
            <div class="col-auto">
                <input class="form-control" id="village" placeholder="村落(中文)">
            </div>
            <div class="col-auto">
                <input class="form-control" id="ipRemark" placeholder="设备名称(中文)">
            </div>
            <div class="col-auto">
                <button class="btn btn-info" onclick="addIp()">添加</button>
            </div>
        </div>
    </div>

    <div class="mb-3">
        <button class="btn btn-dark" onclick="pingAll()">一键批量Ping所有IP</button>
        <span class="ms-3 text-success">后台每60秒自动巡检全部IP,离线设备每10分钟重试探测</span>
    </div>

    <div id="pingResult"></div>
    <canvas id="delayChart" class="mt-4"></canvas>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        const api = "http://127.0.0.1:8000";
        let chartIns = null;
        let chartRenderLock = false;

        async function addIp(){
            let ip = document.getElementById("ipAddr").value;
            let town = document.getElementById("town").value;
            let village = document.getElementById("village").value;
            let remark = document.getElementById("ipRemark").value;
            let res = await fetch(api+"/ip/add",{
                method:"POST",
                headers:{"Content-Type":"application/json"},
                body:JSON.stringify({ip,town,village,remark})
            })
            let ret = await res.json();
            if (!res.ok) {
                alert(ret.detail);
                return;
            }
            alert(ret.msg);
            document.getElementById("ipAddr").value = "";
            document.getElementById("town").value = "";
            document.getElementById("village").value = "";
            document.getElementById("ipRemark").value = "";
        }

        async function importIp(){
            let file = document.getElementById("importFile").files[0];
            if(!file){
                alert("请选择csv文件");
                return;
            }
            let fd = new FormData();
            fd.append("file", file);
            let res = await fetch(api+"/ip/import",{
                method:"POST",
                body:fd
            })
            let ret = await res.json();
            alert(ret.msg);
        }

        async function pingAll(){
            if(chartRenderLock) return;
            chartRenderLock = true;
            try{
                let res = await fetch(api+"/ping/all");
                let data = await res.json();
                let list = data.data;

                const total = list.length;
                let online = 0;
                let offline = 0;
                list.forEach(item=>{
                    if(item.status === "online") online++;
                    else offline++;
                })
                let rate = total === 0 ? "0.00" : (online / total * 100).toFixed(2);

                document.getElementById("totalIp").innerText = total;
                document.getElementById("onlineIp").innerText = online;
                document.getElementById("offlineIp").innerText = offline;
                document.getElementById("onlineRate").innerText = rate + "%";

                let html = "";
                let labelArr = [];
                let delayArr = [];
                html += `<table class="table table-striped">
                    <tr>
                        <th>乡镇-村落-设备(IP)</th>
                        <th>平均延迟(ms)</th>
                        <th>丢包率(%)</th>
                        <th>在线状态</th>
                        <th>检测时间</th>
                    </tr>`;
                list.forEach(item=>{
                    const fullName = `${item.town}-${item.village}-${item.name}(${item.ip})`;
                    let statusText = "";
                    let trClass = "";
                    if(item.status === "online"){
                        statusText = "正常在线";
                        trClass = "table-success";
                    }else if(item.status === "offline"){
                        statusText = "离线";
                        trClass = "table-danger";
                    }else{
                        statusText = "探测失败";
                        trClass = "table-dark text-white";
                    }
                    html += `<tr class="${trClass}">
                        <td>${fullName}</td>
                        <td>${item.avg_delay}</td>
                        <td>${item.packet_loss}</td>
                        <td>${statusText}</td>
                        <td>${item.time}</td>
                    </tr>`;
                    labelArr.push(fullName);
                    delayArr.push(item.avg_delay);
                })
                html += "</table>";
                document.getElementById("pingResult").innerHTML = html;

                if(chartIns) chartIns.destroy();
                chartIns = new Chart(document.getElementById("delayChart"),{
                    type:"bar",
                    data:{
                        labels:labelArr,
                        datasets:[{
                            label:"延迟 ms",
                            data:delayArr,
                            backgroundColor:"#0d6efd"
                        }]
                    },
                    options:{
                        responsive:true,
                        animation:{duration:0},
                        maintainAspectRatio:true,
                        scales:{
                            x:{
                                ticks:{
                                    maxRotation:45,
                                    autoSkip:true,
                                    maxTicksLimit:30
                                }
                            }
                        },
                        plugins:{
                            tooltip:{
                                animation:false
                            }
                        }
                    }
                })
            }finally{
                chartRenderLock = false;
            }
        }
    </script>
</body>
</html>




2  



from fastapi import FastAPI, Query, Body, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
import pythonping
import sqlite3
import time
import csv
import re
import sys
import os
import threading
from io import StringIO
from datetime import datetime
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.executors.pool import ThreadPoolExecutor

def get_resource_path():
    if hasattr(sys, '_MEIPASS'):
        return os.path.dirname(sys.executable)
    return os.path.abspath(".")

app = FastAPI(title="IP Ping乡镇村落监控平台", docs_url="/docs", redoc_url=None)
import logging
logging.getLogger("uvicorn").setLevel(logging.WARNING)
logging.getLogger("apscheduler").setLevel(logging.ERROR)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

IP_REGEX = re.compile(r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
def is_valid_ip(ip: str) -> bool:
    return bool(IP_REGEX.match(ip.strip()))

def init_db():
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    c = conn.cursor()
    c.execute('''CREATE TABLE IF NOT EXISTS monitor_ip
                 (id INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, town TEXT, village TEXT, remark TEXT)''')
    c.execute('''CREATE TABLE IF NOT EXISTS ping_log
                 (id INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, delay REAL, loss REAL, status TEXT, create_time TEXT)''')
    conn.commit()
    conn.close()

init_db()

class IpItem(BaseModel):
    ip: str
    town: str
    village: str
    remark: str

def ping_target(ip: str, town: str, village: str, remark: str, count=2, timeout=1200):
    try:
        res = pythonping.ping(ip, count=count, timeout=timeout/1000)
        avg_delay = res.rtt_avg_ms
        loss = round(res.packet_loss, 2)
        status = "online" if loss < 100 else "offline"
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        db_path = os.path.join(get_resource_path(), "ping_db.db")
        conn = sqlite3.connect(db_path, check_same_thread=False)
        c = conn.cursor()
        c.execute("INSERT INTO ping_log(ip,delay,loss,status,create_time) VALUES (?,?,?,?,?)",
                  (ip, avg_delay, loss, status, now))
        conn.commit()
        conn.close()
        return {
            "ip": ip,
            "town": town,
            "village": village,
            "name": remark,
            "avg_delay": avg_delay,
            "packet_loss": loss,
            "status": status,
            "time": now
        }
    except Exception as e:
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        db_path = os.path.join(get_resource_path(), "ping_db.db")
        conn = sqlite3.connect(db_path, check_same_thread=False)
        c = conn.cursor()
        c.execute("INSERT INTO ping_log(ip,delay,loss,status,create_time) VALUES (?,?,?,?,?)",
                  (ip, 9999, 100, "error", now))
        conn.commit()
        conn.close()
        return {"ip": ip, "town": town, "village": village, "name": remark, "status": "error", "msg": str(e)}

@app.post("/ip/add")
def add_ip(item: IpItem):
    ip = item.ip.strip()
    if not is_valid_ip(ip):
        raise HTTPException(status_code=400, detail="仅支持纯IPv4地址,不支持域名/DNS/网关域名")
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    c = conn.cursor()
    c.execute("INSERT INTO monitor_ip(ip,town,village,remark) VALUES (?,?,?,?)",
              (ip, item.town.strip(), item.village.strip(), item.remark.strip()))
    conn.commit()
    conn.close()
    return {"code":200, "msg":"IP添加成功"}

@app.get("/ip/list")
def get_ip():
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    data = conn.execute("SELECT * FROM monitor_ip").fetchall()
    conn.close()
    lst = [{"id":d[0],"ip":d[1],"town":d[2],"village":d[3],"remark":d[4]} for d in data]
    return {"code":200, "data":lst}

@app.post("/ip/import")
async def import_ip(file: UploadFile = File(...)):
    content = await file.read()
    text = content.decode("utf-8-sig")
    reader = csv.DictReader(StringIO(text))
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    c = conn.cursor()
    succ_count = 0
    skip_count = 0
    for row in reader:
        ip = row.get("ip", "").strip()
        town = row.get("town", "").strip()
        village = row.get("village", "").strip()
        remark = row.get("remark", "").strip()
        if is_valid_ip(ip):
            c.execute("INSERT INTO monitor_ip(ip,town,village,remark) VALUES (?,?,?,?)", (ip, town, village, remark))
            succ_count += 1
        else:
            skip_count += 1
    conn.commit()
    conn.close()
    return {"code":200, "msg":f"成功导入{succ_count}条合法IP,跳过{skip_count}条域名/非法地址"}

@app.get("/export/all_ip")
def export_all_ip():
    output = StringIO()
    writer = csv.writer(output)
    writer.writerow(["id","ip","乡镇","村落","设备名称"])
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    rows = conn.execute("SELECT * FROM monitor_ip").fetchall()
    for r in rows:
        writer.writerow(r)
    output.seek(0)
    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition":"attachment; filename=全部IP列表.csv"}
    )

@app.get("/export/online_ip")
def export_online_ip():
    output = StringIO()
    writer = csv.writer(output)
    writer.writerow(["ip","乡镇","村落","设备名称","延迟ms","丢包率%","状态","检测时间"])
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    sql = '''
    SELECT DISTINCT l.ip, m.town, m.village, m.remark, l.delay, l.loss, l.status, l.create_time
    FROM ping_log l
    LEFT JOIN monitor_ip m ON l.ip=m.ip
    WHERE l.status = 'online'
    GROUP BY l.ip
    ORDER BY l.delay ASC
    '''
    rows = conn.execute(sql).fetchall()
    for r in rows:
        writer.writerow(r)
    output.seek(0)
    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition":"attachment; filename=在线IP清单.csv"}
    )

@app.get("/export/offline_ip")
def export_offline_ip():
    output = StringIO()
    writer = csv.writer(output)
    writer.writerow(["ip","乡镇","村落","设备名称","延迟ms","丢包率%","状态","检测时间"])
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    sql = '''
    SELECT DISTINCT l.ip, m.town, m.village, m.remark, l.delay, l.loss, l.status, l.create_time
    FROM ping_log l
    LEFT JOIN monitor_ip m ON l.ip=m.ip
    WHERE l.status IN ('offline','error')
    GROUP BY l.ip
    ORDER BY l.create_time DESC
    '''
    rows = conn.execute(sql).fetchall()
    for r in rows:
        writer.writerow(r)
    output.seek(0)
    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition":"attachment; filename=离线IP清单.csv"}
    )

@app.get("/export/loss_ip")
def export_loss_ip():
    output = StringIO()
    writer = csv.writer(output)
    writer.writerow(["ip","乡镇","村落","设备名称","延迟ms","丢包率%","状态","检测时间"])
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    sql = '''
    SELECT DISTINCT l.ip, m.town, m.village, m.remark, l.delay, l.loss, l.status, l.create_time
    FROM ping_log l
    LEFT JOIN monitor_ip m ON l.ip=m.ip
    WHERE l.loss > 0
    GROUP BY l.ip
    ORDER BY l.loss DESC
    '''
    rows = conn.execute(sql).fetchall()
    for r in rows:
        writer.writerow(r)
    output.seek(0)
    return StreamingResponse(
        iter([output.getvalue()]),
        media_type="text/csv",
        headers={"Content-Disposition":"attachment; filename=存在丢包IP清单.csv"}
    )

@app.get("/ping/single")
def ping_single(ip:str=Query(...)):
    ip = ip.strip()
    if not is_valid_ip(ip):
        raise HTTPException(status_code=400, detail="仅支持纯IPv4,禁止域名/DNS")
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    row = conn.execute("SELECT town,village,remark FROM monitor_ip WHERE ip=?", (ip,)).fetchone()
    conn.close()
    town = row[0] if row else ""
    village = row[1] if row else ""
    name = row[2] if row else "未知设备"
    return ping_target(ip, town, village, name)

@app.get("/ping/all")
def ping_all():
    db_path = os.path.join(get_resource_path(), "ping_db.db")
    conn = sqlite3.connect(db_path, check_same_thread=False)
    rows = conn.execute("SELECT ip, town, village, remark FROM monitor_ip").fetchall()
    conn.close()
    result = []
    for ip, town, village, remark in rows:
        result.append(ping_target(ip, town, village, remark))
        time.sleep(0.08)
    return {"code":200, "data":result}

task_running_lock = threading.Lock()
offline_task_lock = threading.Lock()
executors = {"default": ThreadPoolExecutor(max_workers=2)}
scheduler = BackgroundScheduler(executors=executors)

def base_60s_task():
    if not task_running_lock.acquire(blocking=False):
        return
    try:
        db_path = os.path.join(get_resource_path(), "ping_db.db")
        conn = sqlite3.connect(db_path, check_same_thread=False)
        all_rows = conn.execute("SELECT ip, town, village, remark FROM monitor_ip").fetchall()
        conn.close()
        for ip, town, village, remark in all_rows:
            ping_target(ip, town, village, remark)
            time.sleep(0.08)
    except Exception:
        pass
    finally:
        task_running_lock.release()

def offline_retry_10min_task():
    if not offline_task_lock.acquire(blocking=False):
        return
    try:
        db_path = os.path.join(get_resource_path(), "ping_db.db")
        conn = sqlite3.connect(db_path, check_same_thread=False)
        sql = '''
        SELECT DISTINCT m.ip, m.town, m.village, m.remark
        FROM monitor_ip m
        INNER JOIN (
            SELECT ip, MAX(create_time) as max_time FROM ping_log GROUP BY ip
        ) last_log ON m.ip = last_log.ip
        INNER JOIN ping_log l ON l.ip = last_log.ip AND l.create_time = last_log.max_time
        WHERE l.status IN ('offline','error')
        '''
        offline_rows = conn.execute(sql).fetchall()
        conn.close()
        for ip, town, village, remark in offline_rows:
            ping_target(ip, town, village, remark)
            time.sleep(0.08)
    except Exception:
        pass
    finally:
        offline_task_lock.release()

scheduler.add_job(base_60s_task, "interval", seconds=60, max_instances=1)
scheduler.add_job(offline_retry_10min_task, "interval", seconds=600, max_instances=1)
scheduler.start()

if __name__ == "__main__":
    import uvicorn
    import webbrowser
    def open_page():
        time.sleep(1.2)
        webbrowser.open("http://127.0.0.1:8000/index.html")
    threading.Thread(target=open_page, daemon=True).start()
    uvicorn.run(app, host="127.0.0.1", port=8000, log_level="warning", access_log=False, workers=1)


3
@echo off
chcp 65001
echo ==================== IP Ping监控平台打包工具 ====================
echo 正在安装依赖库...
pip install fastapi uvicorn pythonping apscheduler pyinstaller
echo 依赖安装完成,开始打包单文件exe
pyinstaller ^
-F ^
-c ^
--name=乡镇村落IP监控平台 ^
--hidden-import=pythonping ^
--hidden-import=apscheduler ^
--hidden-import=uvicorn.logging ^
--hidden-import=uvicorn.lifespan ^
--hidden-import=uvicorn.loops ^
--hidden-import=uvicorn.protocols ^
--add-data="index.html;." ^
main.py
echo ======================================================
echo 打包完成!exe文件在【dist】文件夹内
echo 使用方法:双击exe自动启动后台服务并弹出监控网页
pause


发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-15 05:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表