820 lines
28 KiB
JavaScript
820 lines
28 KiB
JavaScript
|
class UpdateHistory extends HTMLElement {
|
|||
|
constructor() {
|
|||
|
super();
|
|||
|
this.attachShadow({ mode: 'open' });
|
|||
|
this.versions = [];
|
|||
|
this.currentPage = 1;
|
|||
|
this.itemsPerPage = 10; // 每页显示的记录数
|
|||
|
this.accessLevel = 0; // 默认权限级别
|
|||
|
}
|
|||
|
|
|||
|
connectedCallback() {
|
|||
|
this.render();
|
|||
|
this.loadData();
|
|||
|
this.checkUserAccess();
|
|||
|
}
|
|||
|
|
|||
|
// 检查用户权限
|
|||
|
async checkUserAccess() {
|
|||
|
try {
|
|||
|
// 从localStorage获取用户信息
|
|||
|
const userInfo = localStorage.getItem('userInfo');
|
|||
|
|
|||
|
if (userInfo) {
|
|||
|
try {
|
|||
|
const user = JSON.parse(userInfo);
|
|||
|
this.accessLevel = user.access_level || 0;
|
|||
|
} catch (parseError) {
|
|||
|
console.error('解析用户信息失败:', parseError);
|
|||
|
this.accessLevel = 0;
|
|||
|
}
|
|||
|
} else {
|
|||
|
this.accessLevel = 0;
|
|||
|
}
|
|||
|
|
|||
|
this.updateAddButton();
|
|||
|
} catch (error) {
|
|||
|
console.error('获取用户权限失败:', error);
|
|||
|
this.accessLevel = 0;
|
|||
|
this.updateAddButton();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 更新添加按钮显示状态
|
|||
|
updateAddButton() {
|
|||
|
const addButton = this.shadowRoot.querySelector('#addVersionBtn');
|
|||
|
if (addButton) {
|
|||
|
addButton.style.display = this.accessLevel >= 2 ? 'flex' : 'none';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
async loadData() {
|
|||
|
try {
|
|||
|
const response = await fetch('/api/versions');
|
|||
|
if (!response.ok) {
|
|||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|||
|
}
|
|||
|
const data = await response.json();
|
|||
|
|
|||
|
// 按版本号降序排序,然后按日期降序
|
|||
|
this.versions = data.sort((a, b) => {
|
|||
|
const versionA = parseFloat(a.verNum);
|
|||
|
const versionB = parseFloat(b.verNum);
|
|||
|
if (versionA !== versionB) {
|
|||
|
return versionB - versionA;
|
|||
|
}
|
|||
|
const dateA = new Date(a.date + ' ' + a.time);
|
|||
|
const dateB = new Date(b.date + ' ' + b.time);
|
|||
|
return dateB - dateA;
|
|||
|
});
|
|||
|
|
|||
|
this.renderVersions();
|
|||
|
} catch (error) {
|
|||
|
console.error('加载版本信息失败:', error);
|
|||
|
this.showError();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
renderVersions() {
|
|||
|
const contentContainer = this.shadowRoot.querySelector('#content');
|
|||
|
|
|||
|
if (this.versions.length === 0) {
|
|||
|
contentContainer.innerHTML = '<div class="error">暂无更新记录</div>';
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 计算总页数
|
|||
|
const totalPages = Math.ceil(this.versions.length / this.itemsPerPage);
|
|||
|
|
|||
|
// 确保当前页在有效范围内
|
|||
|
if (this.currentPage < 1) this.currentPage = 1;
|
|||
|
if (this.currentPage > totalPages) this.currentPage = totalPages;
|
|||
|
|
|||
|
// 计算当前页显示的记录
|
|||
|
const startIndex = (this.currentPage - 1) * this.itemsPerPage;
|
|||
|
const endIndex = Math.min(startIndex + this.itemsPerPage, this.versions.length);
|
|||
|
const currentPageItems = this.versions.slice(startIndex, endIndex);
|
|||
|
|
|||
|
let html = '<div class="version-timeline">';
|
|||
|
|
|||
|
currentPageItems.forEach(version => {
|
|||
|
const hasNote = Boolean(version.note);
|
|||
|
|
|||
|
html += `
|
|||
|
<div class="version-item" data-version="${version.verNum}">
|
|||
|
<div class="version-header">
|
|||
|
<div class="version-header-left">
|
|||
|
<div class="version-info">
|
|||
|
<span class="version-number">v${version.verNum}</span>
|
|||
|
<span class="version-title">${version.title}</span>
|
|||
|
<span class="version-date">${version.date} ${version.time}</span>
|
|||
|
<span class="version-author">作者: ${version.author || '未知用户'}</span>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
${hasNote ? `
|
|||
|
<button class="expand-btn" aria-label="展开详情">
|
|||
|
<img src="assets/icons/png/chevron-down_b.png" alt="展开">
|
|||
|
</button>
|
|||
|
` : ''}
|
|||
|
</div>
|
|||
|
${hasNote ? `
|
|||
|
<div class="version-description">${version.note}</div>
|
|||
|
` : ''}
|
|||
|
</div>
|
|||
|
`;
|
|||
|
});
|
|||
|
|
|||
|
html += '</div>';
|
|||
|
|
|||
|
// 添加分页控制
|
|||
|
if (totalPages > 1) {
|
|||
|
html += `
|
|||
|
<div class="pagination">
|
|||
|
<div class="pagination-info">第 ${this.currentPage} 页,共 ${totalPages} 页</div>
|
|||
|
<div class="pagination-controls">
|
|||
|
<button class="page-btn" data-action="first" ${this.currentPage === 1 ? 'disabled' : ''}>
|
|||
|
<img src="assets/icons/png/chevron-dleft_b.png" alt="首页">
|
|||
|
</button>
|
|||
|
<button class="page-btn" data-action="prev" ${this.currentPage === 1 ? 'disabled' : ''}>
|
|||
|
<img src="assets/icons/png/chevron-left_b.png" alt="上一页">
|
|||
|
</button>
|
|||
|
<span class="page-indicator">${this.currentPage} / ${totalPages}</span>
|
|||
|
<button class="page-btn" data-action="next" ${this.currentPage === totalPages ? 'disabled' : ''}>
|
|||
|
<img src="assets/icons/png/chevron-right_b.png" alt="下一页">
|
|||
|
</button>
|
|||
|
<button class="page-btn" data-action="last" ${this.currentPage === totalPages ? 'disabled' : ''}>
|
|||
|
<img src="assets/icons/png/chevron-dright_b.png" alt="末页">
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
`;
|
|||
|
}
|
|||
|
|
|||
|
contentContainer.innerHTML = html;
|
|||
|
|
|||
|
// 添加展开/收起事件
|
|||
|
this.addExpandListeners();
|
|||
|
|
|||
|
// 添加分页事件
|
|||
|
this.addPaginationListeners();
|
|||
|
|
|||
|
// 更新添加按钮显示状态
|
|||
|
this.updateAddButton();
|
|||
|
}
|
|||
|
|
|||
|
addExpandListeners() {
|
|||
|
const expandButtons = this.shadowRoot.querySelectorAll('.expand-btn');
|
|||
|
|
|||
|
expandButtons.forEach((button, index) => {
|
|||
|
|
|||
|
// 移除旧事件(如果有)
|
|||
|
button.removeEventListener('click', this.onButtonClick);
|
|||
|
|
|||
|
// 添加新事件
|
|||
|
button.addEventListener('click', (e) => {
|
|||
|
const versionItem = button.closest('.version-item');
|
|||
|
const description = versionItem.querySelector('.version-description');
|
|||
|
|
|||
|
// 切换显示/隐藏状态
|
|||
|
description.classList.toggle('show');
|
|||
|
|
|||
|
// 更新按钮状态
|
|||
|
button.classList.toggle('expanded');
|
|||
|
|
|||
|
// 更新按钮文本和图标
|
|||
|
const img = button.querySelector('img');
|
|||
|
if (description.classList.contains('show')) {
|
|||
|
button.setAttribute('aria-label', '收起详情');
|
|||
|
img.alt = '收起';
|
|||
|
} else {
|
|||
|
button.setAttribute('aria-label', '展开详情');
|
|||
|
img.alt = '展开';
|
|||
|
}
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
addPaginationListeners() {
|
|||
|
const pageButtons = this.shadowRoot.querySelectorAll('.page-btn');
|
|||
|
|
|||
|
pageButtons.forEach(button => {
|
|||
|
button.addEventListener('click', () => {
|
|||
|
const action = button.getAttribute('data-action');
|
|||
|
const totalPages = Math.ceil(this.versions.length / this.itemsPerPage);
|
|||
|
|
|||
|
switch (action) {
|
|||
|
case 'first':
|
|||
|
this.currentPage = 1;
|
|||
|
break;
|
|||
|
case 'prev':
|
|||
|
if (this.currentPage > 1) {
|
|||
|
this.currentPage--;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'next':
|
|||
|
if (this.currentPage < totalPages) {
|
|||
|
this.currentPage++;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 'last':
|
|||
|
this.currentPage = totalPages;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
this.renderVersions();
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
showError() {
|
|||
|
const contentContainer = this.shadowRoot.querySelector('#content');
|
|||
|
contentContainer.innerHTML = '<div class="error">加载失败,请稍后重试</div>';
|
|||
|
}
|
|||
|
|
|||
|
render() {
|
|||
|
this.shadowRoot.innerHTML = `
|
|||
|
<style>
|
|||
|
:host {
|
|||
|
display: block;
|
|||
|
padding: 20px;
|
|||
|
max-width: 1200px;
|
|||
|
margin: 0 auto;
|
|||
|
}
|
|||
|
|
|||
|
.container {
|
|||
|
background: white;
|
|||
|
border-radius: 12px;
|
|||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|||
|
padding: 30px;
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
|
|||
|
.title-container {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: center;
|
|||
|
margin-bottom: 30px;
|
|||
|
padding-bottom: 15px;
|
|||
|
border-bottom: 2px solid #eee;
|
|||
|
}
|
|||
|
|
|||
|
.title {
|
|||
|
font-size: 24px;
|
|||
|
color: #2c3e50;
|
|||
|
margin: 0;
|
|||
|
}
|
|||
|
|
|||
|
#addVersionBtn {
|
|||
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
|||
|
color: white;
|
|||
|
border: none;
|
|||
|
border-radius: 6px;
|
|||
|
padding: 8px 16px;
|
|||
|
font-size: 14px;
|
|||
|
cursor: pointer;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
gap: 6px;
|
|||
|
transition: all 0.3s ease;
|
|||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|||
|
position: absolute;
|
|||
|
right: 30px;
|
|||
|
top: 30px;
|
|||
|
}
|
|||
|
|
|||
|
#addVersionBtn:hover {
|
|||
|
transform: translateY(-2px);
|
|||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
|||
|
}
|
|||
|
|
|||
|
#addVersionBtn img {
|
|||
|
width: 16px;
|
|||
|
height: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.version-timeline {
|
|||
|
position: relative;
|
|||
|
padding-left: 30px;
|
|||
|
}
|
|||
|
|
|||
|
.version-item {
|
|||
|
position: relative;
|
|||
|
margin-bottom: 40px;
|
|||
|
}
|
|||
|
|
|||
|
.version-item::before {
|
|||
|
content: '';
|
|||
|
position: absolute;
|
|||
|
left: -30px;
|
|||
|
top: 0;
|
|||
|
width: 16px;
|
|||
|
height: 16px;
|
|||
|
border-radius: 50%;
|
|||
|
background: #667eea;
|
|||
|
border: 3px solid white;
|
|||
|
box-shadow: 0 0 0 2px #667eea;
|
|||
|
}
|
|||
|
|
|||
|
.version-item::after {
|
|||
|
content: '';
|
|||
|
position: absolute;
|
|||
|
left: -23px;
|
|||
|
top: 20px;
|
|||
|
bottom: -40px;
|
|||
|
width: 2px;
|
|||
|
background: #e2e8f0;
|
|||
|
}
|
|||
|
|
|||
|
.version-item:last-child::after {
|
|||
|
display: none;
|
|||
|
}
|
|||
|
|
|||
|
.version-header {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: center;
|
|||
|
margin-bottom: 10px;
|
|||
|
}
|
|||
|
|
|||
|
.version-header-left {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
|
|||
|
.version-info {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
line-height: 1;
|
|||
|
}
|
|||
|
|
|||
|
.version-number {
|
|||
|
font-size: 18px;
|
|||
|
font-weight: bold;
|
|||
|
color: #667eea;
|
|||
|
margin-right: 15px;
|
|||
|
display: inline-flex;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
|
|||
|
.version-title {
|
|||
|
font-size: 16px;
|
|||
|
font-weight: 500;
|
|||
|
color: #2d3748;
|
|||
|
margin-right: 15px;
|
|||
|
display: inline-flex;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
|
|||
|
.version-date {
|
|||
|
color: #718096;
|
|||
|
font-size: 14px;
|
|||
|
display: inline-flex;
|
|||
|
align-items: center;
|
|||
|
}
|
|||
|
|
|||
|
.version-author {
|
|||
|
color: #718096;
|
|||
|
font-size: 14px;
|
|||
|
display: inline-flex;
|
|||
|
align-items: center;
|
|||
|
margin-left: 15px;
|
|||
|
}
|
|||
|
|
|||
|
.expand-btn {
|
|||
|
background: none;
|
|||
|
border: none;
|
|||
|
cursor: pointer;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
width: 30px;
|
|||
|
height: 30px;
|
|||
|
border-radius: 50%;
|
|||
|
transition: background-color 0.3s;
|
|||
|
padding: 0;
|
|||
|
margin: 0;
|
|||
|
}
|
|||
|
|
|||
|
.expand-btn:hover {
|
|||
|
background-color: rgba(0, 0, 0, 0.05);
|
|||
|
}
|
|||
|
|
|||
|
.expand-btn img {
|
|||
|
width: 20px;
|
|||
|
height: 20px;
|
|||
|
transition: transform 0.3s;
|
|||
|
}
|
|||
|
|
|||
|
.expand-btn.expanded img {
|
|||
|
transform: rotate(180deg);
|
|||
|
}
|
|||
|
|
|||
|
.version-description {
|
|||
|
display: none;
|
|||
|
padding: 10px 15px;
|
|||
|
background-color: #f8f9fa;
|
|||
|
border-radius: 8px;
|
|||
|
margin-top: 10px;
|
|||
|
color: #4a5568;
|
|||
|
line-height: 1.6;
|
|||
|
}
|
|||
|
|
|||
|
.version-description.show {
|
|||
|
display: block;
|
|||
|
}
|
|||
|
|
|||
|
.loading {
|
|||
|
text-align: center;
|
|||
|
padding: 40px;
|
|||
|
color: #718096;
|
|||
|
}
|
|||
|
|
|||
|
.error {
|
|||
|
text-align: center;
|
|||
|
padding: 40px;
|
|||
|
color: #e53e3e;
|
|||
|
}
|
|||
|
|
|||
|
/* 分页样式 */
|
|||
|
.pagination {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: center;
|
|||
|
margin-top: 30px;
|
|||
|
padding-top: 20px;
|
|||
|
border-top: 1px solid #eee;
|
|||
|
}
|
|||
|
|
|||
|
.pagination-info {
|
|||
|
color: #718096;
|
|||
|
font-size: 14px;
|
|||
|
}
|
|||
|
|
|||
|
.pagination-controls {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
gap: 8px;
|
|||
|
}
|
|||
|
|
|||
|
.page-btn {
|
|||
|
background: none;
|
|||
|
border: 1px solid #ddd;
|
|||
|
border-radius: 4px;
|
|||
|
padding: 5px 10px;
|
|||
|
cursor: pointer;
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
transition: all 0.3s;
|
|||
|
}
|
|||
|
|
|||
|
.page-btn:hover:not([disabled]) {
|
|||
|
background-color: #f8f9fa;
|
|||
|
border-color: #667eea;
|
|||
|
}
|
|||
|
|
|||
|
.page-btn:disabled {
|
|||
|
opacity: 0.5;
|
|||
|
cursor: not-allowed;
|
|||
|
}
|
|||
|
|
|||
|
.page-btn img {
|
|||
|
width: 16px;
|
|||
|
height: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.page-indicator {
|
|||
|
padding: 0 10px;
|
|||
|
color: #2d3748;
|
|||
|
font-size: 14px;
|
|||
|
}
|
|||
|
|
|||
|
/* 对话框样式 */
|
|||
|
.modal-overlay {
|
|||
|
position: fixed;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
right: 0;
|
|||
|
bottom: 0;
|
|||
|
background-color: rgba(0, 0, 0, 0.5);
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
justify-content: center;
|
|||
|
z-index: 1000;
|
|||
|
display: none;
|
|||
|
}
|
|||
|
|
|||
|
.modal-overlay.active {
|
|||
|
display: flex;
|
|||
|
}
|
|||
|
|
|||
|
.modal {
|
|||
|
background-color: white;
|
|||
|
border-radius: 12px;
|
|||
|
padding: 24px;
|
|||
|
width: 500px;
|
|||
|
max-width: 90%;
|
|||
|
max-height: 90vh;
|
|||
|
overflow-y: auto;
|
|||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|||
|
}
|
|||
|
|
|||
|
.modal-header {
|
|||
|
display: flex;
|
|||
|
justify-content: space-between;
|
|||
|
align-items: center;
|
|||
|
margin-bottom: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.modal-title {
|
|||
|
font-size: 20px;
|
|||
|
font-weight: bold;
|
|||
|
color: #2c3e50;
|
|||
|
margin: 0;
|
|||
|
}
|
|||
|
|
|||
|
.close-btn {
|
|||
|
background: none;
|
|||
|
border: none;
|
|||
|
font-size: 24px;
|
|||
|
cursor: pointer;
|
|||
|
color: #718096;
|
|||
|
line-height: 1;
|
|||
|
padding: 0;
|
|||
|
}
|
|||
|
|
|||
|
.form-group {
|
|||
|
margin-bottom: 16px;
|
|||
|
}
|
|||
|
|
|||
|
.form-group label {
|
|||
|
display: block;
|
|||
|
margin-bottom: 8px;
|
|||
|
font-weight: 500;
|
|||
|
color: #2d3748;
|
|||
|
}
|
|||
|
|
|||
|
.form-control {
|
|||
|
width: 100%;
|
|||
|
padding: 10px 12px;
|
|||
|
border: 1px solid #ddd;
|
|||
|
border-radius: 6px;
|
|||
|
font-size: 15px;
|
|||
|
transition: border-color 0.3s;
|
|||
|
box-sizing: border-box;
|
|||
|
}
|
|||
|
|
|||
|
.form-control:focus {
|
|||
|
border-color: #667eea;
|
|||
|
outline: none;
|
|||
|
}
|
|||
|
|
|||
|
.form-control:disabled {
|
|||
|
background-color: #f8f9fa;
|
|||
|
}
|
|||
|
|
|||
|
textarea.form-control {
|
|||
|
min-height: 120px;
|
|||
|
resize: vertical;
|
|||
|
}
|
|||
|
|
|||
|
.modal-footer {
|
|||
|
display: flex;
|
|||
|
justify-content: flex-end;
|
|||
|
gap: 12px;
|
|||
|
margin-top: 24px;
|
|||
|
}
|
|||
|
|
|||
|
.btn {
|
|||
|
padding: 10px 16px;
|
|||
|
border-radius: 6px;
|
|||
|
font-size: 15px;
|
|||
|
cursor: pointer;
|
|||
|
transition: all 0.3s;
|
|||
|
}
|
|||
|
|
|||
|
.btn-secondary {
|
|||
|
background-color: #f8f9fa;
|
|||
|
border: 1px solid #ddd;
|
|||
|
color: #718096;
|
|||
|
}
|
|||
|
|
|||
|
.btn-secondary:hover {
|
|||
|
background-color: #edf2f7;
|
|||
|
}
|
|||
|
|
|||
|
.btn-primary {
|
|||
|
background: linear-gradient(135deg, #667eea, #764ba2);
|
|||
|
border: none;
|
|||
|
color: white;
|
|||
|
}
|
|||
|
|
|||
|
.btn-primary:hover {
|
|||
|
opacity: 0.9;
|
|||
|
transform: translateY(-1px);
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<div class="container">
|
|||
|
<div class="title-container">
|
|||
|
<h1 class="title">更新记录</h1>
|
|||
|
</div>
|
|||
|
<button id="addVersionBtn" style="display: none;">
|
|||
|
<img src="assets/icons/png/plus.png" alt="添加">
|
|||
|
提交更新
|
|||
|
</button>
|
|||
|
<div id="content">
|
|||
|
<div class="loading">加载中...</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 提交更新对话框 -->
|
|||
|
<div class="modal-overlay" id="versionModal">
|
|||
|
<div class="modal">
|
|||
|
<div class="modal-header">
|
|||
|
<h2 class="modal-title">提交更新记录</h2>
|
|||
|
<button class="close-btn" id="closeModalBtn">×</button>
|
|||
|
</div>
|
|||
|
<form id="versionForm">
|
|||
|
<div class="form-group">
|
|||
|
<label for="verNum">版本号</label>
|
|||
|
<input type="text" class="form-control" id="verNum" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="date">日期</label>
|
|||
|
<input type="text" class="form-control" id="date" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="time">时间</label>
|
|||
|
<input type="text" class="form-control" id="time" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="title">标题</label>
|
|||
|
<input type="text" class="form-control" id="title" required>
|
|||
|
</div>
|
|||
|
<div class="form-group">
|
|||
|
<label for="note">内容</label>
|
|||
|
<textarea class="form-control" id="note" required></textarea>
|
|||
|
</div>
|
|||
|
<div class="modal-footer">
|
|||
|
<button type="button" class="btn btn-secondary" id="cancelBtn">取消</button>
|
|||
|
<button type="submit" class="btn btn-primary">提交</button>
|
|||
|
</div>
|
|||
|
</form>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
`;
|
|||
|
|
|||
|
// 添加事件监听器
|
|||
|
this.addModalEventListeners();
|
|||
|
}
|
|||
|
|
|||
|
// 添加模态框事件监听器
|
|||
|
addModalEventListeners() {
|
|||
|
const addButton = this.shadowRoot.getElementById('addVersionBtn');
|
|||
|
const closeButton = this.shadowRoot.getElementById('closeModalBtn');
|
|||
|
const cancelButton = this.shadowRoot.getElementById('cancelBtn');
|
|||
|
const modal = this.shadowRoot.getElementById('versionModal');
|
|||
|
const form = this.shadowRoot.getElementById('versionForm');
|
|||
|
|
|||
|
// 点击添加按钮显示模态框
|
|||
|
if (addButton) {
|
|||
|
addButton.addEventListener('click', () => {
|
|||
|
this.prepareModalData();
|
|||
|
modal.classList.add('active');
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// 关闭模态框
|
|||
|
if (closeButton) {
|
|||
|
closeButton.addEventListener('click', () => {
|
|||
|
modal.classList.remove('active');
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// 取消按钮
|
|||
|
if (cancelButton) {
|
|||
|
cancelButton.addEventListener('click', () => {
|
|||
|
modal.classList.remove('active');
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// 表单提交
|
|||
|
if (form) {
|
|||
|
form.addEventListener('submit', (e) => {
|
|||
|
e.preventDefault();
|
|||
|
this.submitVersion();
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 准备模态框数据
|
|||
|
prepareModalData() {
|
|||
|
// 获取表单元素
|
|||
|
const verNumInput = this.shadowRoot.getElementById('verNum');
|
|||
|
const dateInput = this.shadowRoot.getElementById('date');
|
|||
|
const timeInput = this.shadowRoot.getElementById('time');
|
|||
|
|
|||
|
// 设置当前日期和时间
|
|||
|
const now = new Date();
|
|||
|
const formattedDate = now.toLocaleDateString('zh-CN', {
|
|||
|
year: 'numeric',
|
|||
|
month: '2-digit',
|
|||
|
day: '2-digit'
|
|||
|
}).replace(/\//g, '-');
|
|||
|
|
|||
|
const formattedTime = now.toLocaleTimeString('zh-CN', {
|
|||
|
hour: '2-digit',
|
|||
|
minute: '2-digit',
|
|||
|
second: '2-digit',
|
|||
|
hour12: false
|
|||
|
});
|
|||
|
|
|||
|
dateInput.value = formattedDate;
|
|||
|
timeInput.value = formattedTime;
|
|||
|
|
|||
|
// 计算新版本号
|
|||
|
if (this.versions && this.versions.length > 0) {
|
|||
|
const latestVersion = this.versions[0];
|
|||
|
const currentVersionParts = latestVersion.verNum.split('.');
|
|||
|
|
|||
|
// 增加最后一位
|
|||
|
let newVersion;
|
|||
|
if (currentVersionParts.length >= 3) {
|
|||
|
currentVersionParts[2] = (parseInt(currentVersionParts[2]) + 1).toString();
|
|||
|
newVersion = currentVersionParts.join('.');
|
|||
|
} else {
|
|||
|
// 如果版本号格式不是 x.y.z,则简单地加0.0.1
|
|||
|
const versionNum = parseFloat(latestVersion.verNum);
|
|||
|
newVersion = (versionNum + 0.001).toFixed(3);
|
|||
|
}
|
|||
|
|
|||
|
verNumInput.value = newVersion;
|
|||
|
} else {
|
|||
|
// 如果没有现有版本,使用默认的1.0.0
|
|||
|
verNumInput.value = '1.0.0';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 提交版本信息
|
|||
|
async submitVersion() {
|
|||
|
const modal = this.shadowRoot.getElementById('versionModal');
|
|||
|
const verNum = this.shadowRoot.getElementById('verNum').value;
|
|||
|
const date = this.shadowRoot.getElementById('date').value;
|
|||
|
const time = this.shadowRoot.getElementById('time').value;
|
|||
|
const title = this.shadowRoot.getElementById('title').value;
|
|||
|
const note = this.shadowRoot.getElementById('note').value;
|
|||
|
|
|||
|
// 获取当前登录用户名
|
|||
|
let author = '未知用户';
|
|||
|
const userInfo = localStorage.getItem('userInfo');
|
|||
|
if (userInfo) {
|
|||
|
try {
|
|||
|
const user = JSON.parse(userInfo);
|
|||
|
author = user.username || '未知用户';
|
|||
|
} catch (parseError) {
|
|||
|
console.error('解析用户信息失败:', parseError);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
const response = await fetch('/api/versions', {
|
|||
|
method: 'POST',
|
|||
|
headers: {
|
|||
|
'Content-Type': 'application/json'
|
|||
|
},
|
|||
|
body: JSON.stringify({
|
|||
|
verNum,
|
|||
|
date,
|
|||
|
time,
|
|||
|
title,
|
|||
|
note,
|
|||
|
author
|
|||
|
})
|
|||
|
});
|
|||
|
|
|||
|
if (!response.ok) {
|
|||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|||
|
}
|
|||
|
|
|||
|
// 重新加载版本数据
|
|||
|
this.loadData();
|
|||
|
|
|||
|
// 关闭模态框
|
|||
|
modal.classList.remove('active');
|
|||
|
|
|||
|
// 清空表单
|
|||
|
this.shadowRoot.getElementById('title').value = '';
|
|||
|
this.shadowRoot.getElementById('note').value = '';
|
|||
|
|
|||
|
// 显示成功消息
|
|||
|
alert('更新记录提交成功!');
|
|||
|
|
|||
|
} catch (error) {
|
|||
|
console.error('提交更新记录失败:', error);
|
|||
|
alert('提交失败,请重试!');
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
customElements.define('update-history', UpdateHistory);
|