qr-scanner/static/index.html

167 lines
6.8 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>二维码批量识别工具</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/static/style.css" rel="stylesheet" />
</head>
<body class="bg-light">
<main class="container py-4 app-shell" id="app">
<header class="d-flex align-items-center justify-content-between mb-3">
<h1 class="h4 mb-0">二维码批量识别工具 v1.0</h1>
<div class="text-muted small" id="statusText">就绪</div>
</header>
<section class="card mb-3" id="viewUpload">
<div class="card-body">
<details class="mb-3">
<summary class="fw-semibold">使用说明</summary>
<div class="small text-muted mt-2">
<div>1选择文件ZIP 或图片,可多选/拖拽)</div>
<div>2按需设置并发数与单张超时</div>
<div>3点击“开始处理”等待完成</div>
<div>4下载 Excel 结果,失败项可在页面查看原因</div>
</div>
</details>
<div class="mb-3">
<div id="dropzone" class="dropzone">
<div class="fw-semibold">拖拽压缩包或图片到此处</div>
<div class="text-muted small">或点击选择文件ZIP / PNG / JPG / JPEG / BMP</div>
<input id="fileInput" type="file" class="d-none" multiple accept=".zip,.png,.jpg,.jpeg,.bmp,image/png,image/jpeg,image/bmp" />
</div>
<div class="text-muted small mt-2">限制ZIP≤100MB图片≤10MB/张;非图片会被忽略</div>
</div>
<div class="border rounded-3 p-3 bg-white">
<div class="d-flex align-items-center justify-content-between mb-2">
<div class="fw-semibold">上传的文件</div>
<button class="btn btn-sm btn-outline-secondary" id="btnClear">清空列表</button>
</div>
<div id="fileList" class="file-list text-muted">暂无文件</div>
</div>
</div>
<div class="card-footer d-flex gap-2 justify-content-end">
<button class="btn btn-sm btn-outline-secondary me-auto" id="btnSettings">设置</button>
<button class="btn btn-primary" id="btnStart" disabled>开始处理</button>
</div>
</section>
<div class="settings-overlay d-none" id="settingsOverlay" role="dialog" aria-modal="true">
<div class="settings-panel">
<div class="d-flex align-items-center justify-content-between mb-2">
<div class="fw-semibold">高级设置</div>
<button class="btn btn-sm btn-outline-secondary" id="btnSettingsClose">关闭</button>
</div>
<div class="mb-2">
<label class="form-label small text-muted mb-1" for="concurrencyInput">并发数</label>
<input class="form-control form-control-sm" id="concurrencyInput" type="number" min="1" max="32" value="4" />
</div>
<div class="mb-0">
<label class="form-label small text-muted mb-1" for="timeoutInput">单张超时(秒)</label>
<input class="form-control form-control-sm" id="timeoutInput" type="number" min="1" max="60" value="30" />
</div>
</div>
</div>
<section class="card mb-3 d-none" id="viewProgress">
<div class="card-body">
<div class="d-flex align-items-center justify-content-between">
<div class="fw-semibold">处理中…</div>
<div class="text-muted small" id="progressPercent">0%</div>
</div>
<div class="progress mt-2" role="progressbar" aria-label="处理进度">
<div class="progress-bar" id="progressBar" style="width:0%"></div>
</div>
<div class="row mt-3 g-3">
<div class="col-6 col-lg-3">
<div class="stat">
<div class="stat-label">总计</div>
<div class="stat-value" id="statTotal">0</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="stat">
<div class="stat-label">已处理</div>
<div class="stat-value" id="statProcessed">0</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="stat">
<div class="stat-label">成功</div>
<div class="stat-value text-success" id="statSuccess">0</div>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="stat">
<div class="stat-label">失败</div>
<div class="stat-value text-danger" id="statFailed">0</div>
</div>
</div>
</div>
<div class="mt-3 text-muted small">
<div>当前处理:<span id="currentFile">-</span></div>
<div>速度:<span id="speed">-</span> 张/秒 预计剩余:<span id="remaining">-</span></div>
</div>
</div>
<div class="card-footer d-flex gap-2 justify-content-end">
<button class="btn btn-outline-danger" id="btnCancel">取消</button>
</div>
</section>
<section class="card mb-3 d-none" id="viewResult">
<div class="card-body">
<div class="d-flex align-items-center justify-content-between">
<div class="fw-semibold" id="resultTitle">处理完成!</div>
<div class="text-muted small" id="taskMeta">-</div>
</div>
<div class="row mt-3 g-3">
<div class="col-6">
<div class="stat">
<div class="stat-label">成功</div>
<div class="stat-value text-success" id="resultSuccess">0</div>
</div>
</div>
<div class="col-6">
<div class="stat">
<div class="stat-label">失败</div>
<div class="stat-value text-danger" id="resultFailed">0</div>
</div>
</div>
</div>
<div class="d-flex gap-2 mt-3 flex-wrap">
<button class="btn btn-primary" id="btnDownloadExcel">下载Excel结果</button>
<button class="btn btn-outline-secondary" id="btnBack">返回首页</button>
</div>
<div class="mt-4 d-none" id="failuresWrap">
<div class="fw-semibold mb-2">失败文件列表</div>
<div class="table-responsive">
<table class="table table-sm table-striped align-middle mb-0">
<thead>
<tr>
<th style="width:72px">序号</th>
<th>图片路径</th>
<th style="width:260px">失败原因</th>
</tr>
</thead>
<tbody id="failuresBody"></tbody>
</table>
</div>
</div>
</div>
</section>
<div class="alert alert-danger d-none" id="errorAlert" role="alert"></div>
</main>
<script src="/static/app.js"></script>
</body>
</html>