<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="UTF-8">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<title>Word URL转PDF - 在线测试工具</title>
|
<style>
|
* {
|
margin: 0;
|
padding: 0;
|
box-sizing: border-box;
|
}
|
|
body {
|
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
min-height: 100vh;
|
padding: 20px;
|
}
|
|
.container {
|
max-width: 900px;
|
margin: 0 auto;
|
background: white;
|
border-radius: 10px;
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
overflow: hidden;
|
}
|
|
.header {
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
color: white;
|
padding: 30px;
|
text-align: center;
|
}
|
|
.header h1 {
|
font-size: 32px;
|
margin-bottom: 10px;
|
}
|
|
.header p {
|
font-size: 16px;
|
opacity: 0.9;
|
}
|
|
.content {
|
padding: 30px;
|
}
|
|
.section {
|
margin-bottom: 30px;
|
}
|
|
.section-title {
|
font-size: 20px;
|
color: #333;
|
margin-bottom: 15px;
|
padding-bottom: 10px;
|
border-bottom: 2px solid #667eea;
|
}
|
|
.form-group {
|
margin-bottom: 20px;
|
}
|
|
.form-group label {
|
display: block;
|
margin-bottom: 8px;
|
color: #555;
|
font-weight: bold;
|
}
|
|
.form-group input {
|
width: 100%;
|
padding: 12px;
|
border: 1px solid #ddd;
|
border-radius: 5px;
|
font-size: 14px;
|
}
|
|
.form-group input:focus {
|
outline: none;
|
border-color: #667eea;
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
}
|
|
.form-group .hint {
|
margin-top: 5px;
|
font-size: 12px;
|
color: #999;
|
}
|
|
.btn-group {
|
display: flex;
|
gap: 10px;
|
margin-top: 20px;
|
}
|
|
.btn {
|
flex: 1;
|
padding: 12px 24px;
|
border: none;
|
border-radius: 5px;
|
font-size: 16px;
|
cursor: pointer;
|
transition: all 0.3s;
|
font-weight: bold;
|
}
|
|
.btn-primary {
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
color: white;
|
}
|
|
.btn-primary:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
}
|
|
.btn-secondary {
|
background: #6c757d;
|
color: white;
|
}
|
|
.btn-secondary:hover {
|
background: #5a6268;
|
}
|
|
.btn:disabled {
|
opacity: 0.5;
|
cursor: not-allowed;
|
}
|
|
.status-box {
|
background: #f8f9fa;
|
border-left: 4px solid #667eea;
|
padding: 15px;
|
margin-top: 15px;
|
border-radius: 5px;
|
display: none;
|
}
|
|
.status-box.show {
|
display: block;
|
}
|
|
.status-box p {
|
margin: 5px 0;
|
color: #555;
|
}
|
|
.status-box .label {
|
font-weight: bold;
|
color: #333;
|
}
|
|
.alert {
|
padding: 12px 20px;
|
border-radius: 5px;
|
margin-top: 15px;
|
}
|
|
.alert-success {
|
background: #d4edda;
|
color: #155724;
|
border: 1px solid #c3e6cb;
|
}
|
|
.alert-error {
|
background: #f8d7da;
|
color: #721c24;
|
border: 1px solid #f5c6cb;
|
}
|
|
.alert-info {
|
background: #d1ecf1;
|
color: #0c5460;
|
border: 1px solid #bee5eb;
|
}
|
|
.alert-warning {
|
background: #fff3cd;
|
color: #856404;
|
border: 1px solid #ffeaa7;
|
}
|
|
.examples {
|
background: #f8f9fa;
|
padding: 15px;
|
border-radius: 5px;
|
margin-top: 15px;
|
}
|
|
.examples h4 {
|
margin-bottom: 10px;
|
color: #333;
|
}
|
|
.examples ul {
|
list-style: none;
|
padding-left: 0;
|
}
|
|
.examples li {
|
padding: 8px 0;
|
border-bottom: 1px solid #e0e0e0;
|
cursor: pointer;
|
transition: all 0.2s;
|
}
|
|
.examples li:hover {
|
background: #e9ecef;
|
padding-left: 10px;
|
}
|
|
.examples li:last-child {
|
border-bottom: none;
|
}
|
|
.examples code {
|
background: #e9ecef;
|
padding: 2px 6px;
|
border-radius: 3px;
|
font-size: 12px;
|
color: #e83e8c;
|
}
|
|
.loading {
|
display: inline-block;
|
width: 20px;
|
height: 20px;
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
border-radius: 50%;
|
border-top-color: white;
|
animation: spin 1s ease-in-out infinite;
|
}
|
|
@keyframes spin {
|
to { transform: rotate(360deg); }
|
}
|
|
.progress-bar {
|
width: 100%;
|
height: 30px;
|
background: #f0f0f0;
|
border-radius: 15px;
|
overflow: hidden;
|
margin-top: 15px;
|
display: none;
|
}
|
|
.progress-bar.show {
|
display: block;
|
}
|
|
.progress-bar-fill {
|
height: 100%;
|
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
transition: width 0.3s;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
color: white;
|
font-weight: bold;
|
}
|
|
.info-box {
|
background: #e7f3ff;
|
border-left: 4px solid #2196F3;
|
padding: 15px;
|
margin-top: 15px;
|
border-radius: 5px;
|
}
|
|
.info-box h4 {
|
margin-bottom: 10px;
|
color: #1976D2;
|
}
|
|
.info-box ul {
|
margin-left: 20px;
|
}
|
|
.info-box li {
|
margin: 5px 0;
|
color: #555;
|
}
|
</style>
|
</head>
|
<body>
|
<div class="container">
|
<div class="header">
|
<h1>📄 Word URL转PDF</h1>
|
<p>在线测试工具 - 通过Word文档URL直接转换为PDF</p>
|
</div>
|
|
<div class="content">
|
<!-- 输入表单 -->
|
<div class="section">
|
<h2 class="section-title">1️⃣ 输入参数</h2>
|
|
<div class="form-group">
|
<label for="serverUrl">服务器地址:</label>
|
<input type="text" id="serverUrl" value="http://localhost:8080" placeholder="http://localhost:8080">
|
<div class="hint">服务器的基础URL地址</div>
|
</div>
|
|
<div class="form-group">
|
<label for="wordUrl">Word文档URL: *</label>
|
<input type="text" id="wordUrl" placeholder="http://example.com/report.docx">
|
<div class="hint">Word文档的完整URL地址(必填)</div>
|
</div>
|
|
<div class="form-group">
|
<label for="fileName">文件名(可选):</label>
|
<input type="text" id="fileName" placeholder="项目报告">
|
<div class="hint">下载的PDF文件名,不含扩展名</div>
|
</div>
|
|
<div class="btn-group">
|
<button class="btn btn-primary" onclick="downloadPdf()">
|
<span id="btnText">开始转换并下载</span>
|
</button>
|
<button class="btn btn-secondary" onclick="clearForm()">清空表单</button>
|
</div>
|
|
<!-- 进度条 -->
|
<div class="progress-bar" id="progressBar">
|
<div class="progress-bar-fill" id="progressBarFill" style="width: 0%;">0%</div>
|
</div>
|
|
<!-- 状态显示 -->
|
<div class="status-box" id="statusBox">
|
<p><span class="label">状态:</span> <span id="statusText">-</span></p>
|
<p><span class="label">请求URL:</span> <span id="requestUrl">-</span></p>
|
<p><span class="label">开始时间:</span> <span id="startTime">-</span></p>
|
<p><span class="label">耗时:</span> <span id="duration">-</span></p>
|
</div>
|
</div>
|
|
<!-- 示例URL -->
|
<div class="section">
|
<h2 class="section-title">2️⃣ 示例URL</h2>
|
<div class="examples">
|
<h4>点击使用示例URL:</h4>
|
<ul>
|
<li onclick="useExample('http://example.com/report.docx', '示例报告')">
|
<code>http://example.com/report.docx</code> - 示例报告
|
</li>
|
<li onclick="useExample('https://file-examples.com/wp-content/uploads/2017/02/file-sample_100kB.docx', '测试文档')">
|
<code>https://file-examples.com/.../file-sample_100kB.docx</code> - 测试文档
|
</li>
|
<li onclick="useExample('http://your-domain.com/files/report.docx', '项目评估报告')">
|
<code>http://your-domain.com/files/report.docx</code> - 项目评估报告
|
</li>
|
</ul>
|
</div>
|
</div>
|
|
<!-- 使用说明 -->
|
<div class="section">
|
<h2 class="section-title">3️⃣ 使用说明</h2>
|
<div class="info-box">
|
<h4>功能特性:</h4>
|
<ul>
|
<li>✅ 支持HTTP/HTTPS协议的Word文档URL</li>
|
<li>✅ 自动下载Word文档并转换为PDF</li>
|
<li>✅ 保留Word文档中的图表和格式</li>
|
<li>✅ 支持自定义PDF文件名</li>
|
<li>✅ 完善的错误处理和日志记录</li>
|
</ul>
|
|
<h4 style="margin-top: 15px;">注意事项:</h4>
|
<ul>
|
<li>⚠️ Word文档URL必须可公开访问</li>
|
<li>⚠️ 大文件转换可能需要较长时间</li>
|
<li>⚠️ 确保服务器可以访问目标URL</li>
|
<li>⚠️ 建议文件大小不超过50MB</li>
|
</ul>
|
</div>
|
</div>
|
|
<!-- 消息提示 -->
|
<div id="messageContainer"></div>
|
</div>
|
</div>
|
|
<script>
|
let startTimestamp = 0;
|
|
// 显示消息
|
function showMessage(message, type = 'info') {
|
const container = document.getElementById('messageContainer');
|
const alert = document.createElement('div');
|
alert.className = `alert alert-${type}`;
|
alert.textContent = message;
|
container.appendChild(alert);
|
|
setTimeout(() => {
|
alert.remove();
|
}, 5000);
|
}
|
|
// 使用示例
|
function useExample(url, fileName) {
|
document.getElementById('wordUrl').value = url;
|
document.getElementById('fileName').value = fileName;
|
showMessage('已填充示例URL', 'success');
|
}
|
|
// 清空表单
|
function clearForm() {
|
document.getElementById('wordUrl').value = '';
|
document.getElementById('fileName').value = '';
|
document.getElementById('statusBox').classList.remove('show');
|
document.getElementById('progressBar').classList.remove('show');
|
showMessage('表单已清空', 'info');
|
}
|
|
// 更新进度
|
function updateProgress(percent, text) {
|
const progressBar = document.getElementById('progressBar');
|
const progressBarFill = document.getElementById('progressBarFill');
|
|
progressBar.classList.add('show');
|
progressBarFill.style.width = percent + '%';
|
progressBarFill.textContent = text || (percent + '%');
|
}
|
|
// 更新状态
|
function updateStatus(status, requestUrl) {
|
const statusBox = document.getElementById('statusBox');
|
const statusText = document.getElementById('statusText');
|
const requestUrlElem = document.getElementById('requestUrl');
|
const startTimeElem = document.getElementById('startTime');
|
const durationElem = document.getElementById('duration');
|
|
statusBox.classList.add('show');
|
statusText.textContent = status;
|
requestUrlElem.textContent = requestUrl || '-';
|
|
if (startTimestamp > 0) {
|
const duration = ((Date.now() - startTimestamp) / 1000).toFixed(2);
|
durationElem.textContent = duration + '秒';
|
}
|
|
const now = new Date();
|
startTimeElem.textContent = now.toLocaleTimeString();
|
}
|
|
// 下载PDF
|
async function downloadPdf() {
|
const serverUrl = document.getElementById('serverUrl').value.trim();
|
const wordUrl = document.getElementById('wordUrl').value.trim();
|
const fileName = document.getElementById('fileName').value.trim();
|
|
// 验证输入
|
if (!serverUrl) {
|
showMessage('请输入服务器地址', 'error');
|
return;
|
}
|
|
if (!wordUrl) {
|
showMessage('请输入Word文档URL', 'error');
|
return;
|
}
|
|
// 验证URL格式
|
try {
|
new URL(wordUrl);
|
} catch (e) {
|
showMessage('Word文档URL格式不正确', 'error');
|
return;
|
}
|
|
// 禁用按钮
|
const btn = document.querySelector('.btn-primary');
|
const btnText = document.getElementById('btnText');
|
btn.disabled = true;
|
btnText.innerHTML = '<span class="loading"></span> 转换中...';
|
|
startTimestamp = Date.now();
|
|
try {
|
// 构建请求URL
|
let apiUrl = `${serverUrl}/admin/stat/report/fuzzyReportPdfNew?wordUrl=${encodeURIComponent(wordUrl)}`;
|
if (fileName) {
|
apiUrl += `&fileName=${encodeURIComponent(fileName)}`;
|
}
|
|
updateStatus('正在下载Word文档...', apiUrl);
|
updateProgress(20, '下载中...');
|
|
// 发送请求
|
const response = await fetch(apiUrl);
|
|
updateProgress(60, '转换中...');
|
updateStatus('正在转换为PDF...', apiUrl);
|
|
if (!response.ok) {
|
throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);
|
}
|
|
updateProgress(80, '生成PDF...');
|
|
// 获取blob
|
const blob = await response.blob();
|
|
updateProgress(90, '准备下载...');
|
|
// 创建下载链接
|
const downloadUrl = window.URL.createObjectURL(blob);
|
const a = document.createElement('a');
|
a.href = downloadUrl;
|
a.download = fileName ? `${fileName}.pdf` : 'report.pdf';
|
document.body.appendChild(a);
|
a.click();
|
document.body.removeChild(a);
|
window.URL.revokeObjectURL(downloadUrl);
|
|
updateProgress(100, '完成!');
|
updateStatus('✅ 转换成功,PDF已下载', apiUrl);
|
|
showMessage('PDF转换成功并已开始下载!', 'success');
|
|
} catch (error) {
|
console.error('转换失败:', error);
|
updateStatus('❌ 转换失败: ' + error.message, '');
|
showMessage('转换失败: ' + error.message, 'error');
|
} finally {
|
// 恢复按钮
|
btn.disabled = false;
|
btnText.textContent = '开始转换并下载';
|
}
|
}
|
|
// 页面加载完成
|
window.onload = function() {
|
showMessage('系统已就绪,请输入Word文档URL', 'info');
|
};
|
</script>
|
</body>
|
</html>
|