2025-11-17 12:56:43 +08:00
|
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block title %}导出卡密 - 软件授权管理系统{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block page_title %}导出卡密{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block page_actions %}
|
|
|
|
|
|
<a href="{{ url_for('web.licenses') }}" class="btn btn-outline-secondary">
|
|
|
|
|
|
<i class="fas fa-arrow-left me-2"></i>
|
|
|
|
|
|
返回列表
|
|
|
|
|
|
</a>
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<div class="col-lg-8">
|
|
|
|
|
|
<div class="card shadow">
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<form id="export-form">
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="product_id" class="form-label">选择产品</label>
|
|
|
|
|
|
<select class="form-select" id="product_id" name="product_id">
|
|
|
|
|
|
<option value="">全部产品</option>
|
|
|
|
|
|
{% for product in products %}
|
|
|
|
|
|
<option value="{{ product.product_id }}">{{ product.product_name }}</option>
|
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="status" class="form-label">卡密状态</label>
|
|
|
|
|
|
<select class="form-select" id="status" name="status">
|
|
|
|
|
|
<option value="">全部状态</option>
|
|
|
|
|
|
<option value="0">未激活</option>
|
|
|
|
|
|
<option value="1">已激活</option>
|
|
|
|
|
|
<option value="2">已过期</option>
|
|
|
|
|
|
<option value="3">已禁用</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="type" class="form-label">卡密类型</label>
|
|
|
|
|
|
<select class="form-select" id="type" name="type">
|
|
|
|
|
|
<option value="">全部类型</option>
|
|
|
|
|
|
<option value="1">正式卡密</option>
|
|
|
|
|
|
<option value="0">试用卡密</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
|
<label for="format" class="form-label">导出格式 *</label>
|
|
|
|
|
|
<select class="form-select" id="format" name="format" required>
|
|
|
|
|
|
<option value="excel">Excel (.xlsx)</option>
|
|
|
|
|
|
<option value="csv">CSV (.csv)</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="btn btn-success" id="submit-btn">
|
|
|
|
|
|
<i class="fas fa-file-export me-2"></i>
|
|
|
|
|
|
<span id="submit-text">导出卡密</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<a href="{{ url_for('web.licenses') }}" class="btn btn-secondary">取消</a>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="col-lg-4">
|
|
|
|
|
|
<div class="card shadow">
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<h6 class="mb-0">导出说明</h6>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
|
<ul class="list-unstyled">
|
|
|
|
|
|
<li class="mb-2">
|
|
|
|
|
|
<i class="fas fa-info-circle text-primary me-2"></i>
|
|
|
|
|
|
<small>可以选择特定产品、状态和类型的卡密进行导出</small>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="mb-2">
|
|
|
|
|
|
<i class="fas fa-info-circle text-primary me-2"></i>
|
|
|
|
|
|
<small>导出格式支持Excel和CSV两种</small>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="mb-2">
|
|
|
|
|
|
<i class="fas fa-info-circle text-primary me-2"></i>
|
|
|
|
|
|
<small>导出的文件包含卡密、产品、状态、有效期等详细信息</small>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
<li class="mb-2">
|
|
|
|
|
|
<i class="fas fa-info-circle text-primary me-2"></i>
|
|
|
|
|
|
<small>导出操作可能需要一些时间,请耐心等待</small>
|
|
|
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endblock %}
|
|
|
|
|
|
|
|
|
|
|
|
{% block extra_js %}
|
|
|
|
|
|
<script>
|
|
|
|
|
|
// 页面加载完成后初始化
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
initEventListeners();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化事件监听器
|
|
|
|
|
|
function initEventListeners() {
|
|
|
|
|
|
// 表单提交
|
|
|
|
|
|
document.getElementById('export-form').addEventListener('submit', function(e) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
exportLicenses();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 导出卡密
|
|
|
|
|
|
function exportLicenses() {
|
|
|
|
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
|
|
|
|
const submitText = document.getElementById('submit-text');
|
|
|
|
|
|
|
|
|
|
|
|
// 获取表单数据
|
|
|
|
|
|
const formData = {
|
|
|
|
|
|
product_id: document.getElementById('product_id').value || null,
|
|
|
|
|
|
status: document.getElementById('status').value ? parseInt(document.getElementById('status').value) : null,
|
|
|
|
|
|
type: document.getElementById('type').value ? parseInt(document.getElementById('type').value) : null,
|
|
|
|
|
|
format: document.getElementById('format').value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载状态
|
|
|
|
|
|
submitBtn.disabled = true;
|
|
|
|
|
|
submitText.textContent = '导出中...';
|
|
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
// 使用apiRequest函数处理API请求,确保域名配置正确
|
|
|
|
|
|
const apiUrl = '/api/v1/licenses/export';
|
2025-11-17 12:56:43 +08:00
|
|
|
|
|
2025-11-22 16:48:45 +08:00
|
|
|
|
apiRequest(apiUrl, {
|
2025-11-17 12:56:43 +08:00
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify(formData)
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(response => {
|
|
|
|
|
|
// 隐藏加载动画
|
|
|
|
|
|
hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
// 处理错误响应
|
|
|
|
|
|
if (response.status === 401) {
|
|
|
|
|
|
showNotification('会话已过期,请重新登录', 'warning');
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
window.location.href = '/login';
|
|
|
|
|
|
}, 1500);
|
|
|
|
|
|
throw new Error('未授权访问');
|
|
|
|
|
|
} else if (response.status === 403) {
|
|
|
|
|
|
return response.json().then(errorData => {
|
|
|
|
|
|
showNotification(errorData.message || '权限不足,无法执行此操作', 'error');
|
|
|
|
|
|
throw new Error(`403: ${errorData.message || '权限不足'}`);
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return response.json().then(errorData => {
|
|
|
|
|
|
throw new Error(`${response.status}: ${errorData.message || response.statusText}`);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文件名
|
|
|
|
|
|
const contentDisposition = response.headers.get('Content-Disposition');
|
|
|
|
|
|
let filename = 'licenses.xlsx';
|
|
|
|
|
|
if (contentDisposition) {
|
|
|
|
|
|
const filenameMatch = contentDisposition.match(/filename="?([^"]+)"?/);
|
|
|
|
|
|
if (filenameMatch && filenameMatch.length === 2) {
|
|
|
|
|
|
filename = filenameMatch[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 下载文件
|
|
|
|
|
|
return response.blob().then(blob => {
|
|
|
|
|
|
const url = window.URL.createObjectURL(blob);
|
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
|
a.href = url;
|
|
|
|
|
|
a.download = filename;
|
|
|
|
|
|
document.body.appendChild(a);
|
|
|
|
|
|
a.click();
|
|
|
|
|
|
a.remove();
|
|
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
|
|
|
|
|
|
|
|
showNotification('导出成功', 'success');
|
|
|
|
|
|
});
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
// 隐藏加载动画
|
|
|
|
|
|
hideLoading();
|
|
|
|
|
|
console.error('Failed to export licenses:', error);
|
|
|
|
|
|
showNotification(error.message || '导出失败', 'error');
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
// 恢复按钮状态
|
|
|
|
|
|
submitBtn.disabled = false;
|
|
|
|
|
|
submitText.textContent = '导出卡密';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
{% endblock %}
|