Files
MC_Report/public/js/pages/ticket-create.js

168 lines
8.0 KiB
JavaScript
Raw 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.
const TicketCreate = {
files: [],
render(container, { type, prefill, backLink }) {
const user = Auth.user();
const isReport = type === 'report';
const isSuggestion = type === 'suggestion';
const isAppeal = type === 'appeal';
const typeLabel = isReport ? '举报' : isAppeal ? '申诉' : '建议';
this.files = [];
container.innerHTML = `
<div class="tab-nav" id="type-tabs">
<button class="${isReport?'active':''}" data-type="report">举报</button>
<button class="${isSuggestion?'active':''}" data-type="suggestion">建议</button>
<button class="${isAppeal?'active':''}" data-type="appeal">申诉</button>
</div>
<form id="ticket-form" enctype="multipart/form-data">
<input type="hidden" name="type" value="${type}">
<div class="card">
<div class="card-h">提交${typeLabel}</div>
<div class="card-b">
<div class="form-group">
<label>${typeLabel}标题 *</label>
<input name="title" required placeholder="${isReport ? '如:玩家破坏建筑' : isAppeal ? '如:申请解除封禁' : '如:增加领地保护功能'}">
</div>
<div class="grid-2">
<div class="form-group">
<label>您的游戏名称 *</label>
<input name="reporter_game_name" required placeholder="Minecraft ID" value="${U.esc(prefill?.game_name || user?.game_name || '')}" ${prefill?.game_name ? 'readonly' : ''}>
</div>
<div class="form-group">
<label>您的游戏UID *</label>
<input name="reporter_game_uid" required placeholder="游戏UID" value="${U.esc(prefill?.game_uid || user?.game_uid || '')}" ${prefill?.game_uid ? 'readonly' : ''}>
</div>
</div>
${isReport ? `
<div class="grid-2">
<div class="form-group"><label>对方游戏名称 (至少一项)</label><input name="target_game_name" placeholder="被举报者Minecraft ID"></div>
<div class="form-group"><label>对方游戏UID (至少一项)</label><input name="target_game_uid" placeholder="被举报者UID"></div>
</div>
<div class="form-group"><label>举报原因 *</label>
<input name="reason" list="reason-list" required placeholder="选择或自行输入举报原因">
<datalist id="reason-list">
<option value="破坏建筑"><option value="盗窃物品"><option value="外挂作弊">
<option value="语言骚扰"><option value="恶意PVP"><option value="利用漏洞">
<option value="其他违规"><option value="诈骗"><option value="恶意辱骂">
</datalist>
</div>
<div class="form-group"><label>详细描述</label><textarea name="description" rows="4" placeholder="请详细描述事件经过..."></textarea></div>
<div class="form-group" style="display:flex;align-items:center;gap:8px;margin-top:12px">
<input type="checkbox" name="is_admin_complaint" value="1" id="cb-admin" style="width:auto">
<label for="cb-admin" style="margin:0;font-weight:500;text-transform:none;letter-spacing:0;color:var(--d)"><i class="fas fa-exclamation-triangle"></i> 投诉管理员(仅服主可见)</label>
</div>
` : isAppeal ? `
<div class="form-group"><label>申诉理由 *</label><input name="reason" required placeholder="如:误封、证据不足被封、违规行为已纠正等"></div>
<div class="form-group"><label>详细说明 *</label><textarea name="description" rows="5" placeholder="请详细说明情况,包括被封时间、可能原因、为什么应解封等..." required></textarea></div>
` : `
<div class="form-group"><label>建议内容 *</label><textarea name="description" rows="5" placeholder="请详细描述您的建议..." required></textarea></div>
`}
</div>
</div>
<div class="card">
<div class="card-h">上传文件 (图片/视频每个最大20MB)</div>
<div class="card-b">
<div class="file-upload" id="file-drop">
<i class="fas fa-cloud-upload-alt"></i>
<p>点击选择文件或拖拽到此处</p>
<p class="help">支持: JPG/PNG/GIF/WebP/MP4/WebM &nbsp; 每个最大50MB</p>
</div>
<input type="file" id="file-input" multiple accept="image/jpeg,image/png,image/gif,image/webp,video/mp4,video/webm" style="display:none">
<div class="file-list" id="file-list"></div>
</div>
</div>
<div style="display:flex;gap:8px;justify-content:flex-end">
${backLink ? `<button type="button" class="btn btn-o" onclick="${backLink}">返回</button>` : ''}
<button type="submit" class="btn btn-p btn-lg"><i class="fas fa-paper-plane"></i> 提交</button>
</div>
</form>
`;
this.bindFileUpload(container);
this.bindSubmit(container, type);
container.querySelectorAll('#type-tabs button').forEach(btn => {
btn.addEventListener('click', () => {
TicketCreate.render(container, { type: btn.dataset.type, prefill, backLink });
});
});
},
bindFileUpload(container) {
const drop = container.querySelector('#file-drop');
const input = container.querySelector('#file-input');
const list = container.querySelector('#file-list');
drop.onclick = () => input.click();
input.onchange = () => this.addFiles(input.files, list);
drop.ondragover = e => { e.preventDefault(); drop.style.borderColor = 'var(--p)'; };
drop.ondragleave = () => { drop.style.borderColor = 'var(--g300)'; };
drop.ondrop = e => {
e.preventDefault();
drop.style.borderColor = 'var(--g300)';
this.addFiles(e.dataTransfer.files, list);
};
},
addFiles(fileList, listEl) {
const allowed = ['image/jpeg','image/png','image/gif','image/webp','video/mp4','video/webm'];
for (const f of fileList) {
if (!allowed.includes(f.type)) { alert(`不支持的文件类型: ${f.name}`); continue; }
if (f.size > 50 * 1024 * 1024) { alert(`文件过大: ${f.name}`); continue; }
if (this.files.length >= 5) { alert('最多5个文件'); break; }
this.files.push(f);
}
this.refreshFileList(listEl);
},
refreshFileList(listEl) {
listEl.innerHTML = this.files.map((f, i) => `
<div class="file-item">
<i class="fas fa-${f.type.startsWith('video') ? 'video' : 'image'}"></i>
${U.esc(f.name)} (${(f.size / 1024 / 1024).toFixed(2)}MB)
<button type="button" onclick="TicketCreate.removeFile(${i})"><i class="fas fa-times"></i></button>
</div>`).join('');
},
removeFile(i) { this.files.splice(i, 1); this.refreshFileList(document.getElementById('file-list')); },
async bindSubmit(container, type) {
const form = container.querySelector('#ticket-form');
form.addEventListener('submit', async e => {
e.preventDefault();
const fd = new FormData(form);
if (type === 'report') {
const tgn = fd.get('target_game_name');
const tgu = fd.get('target_game_uid');
if (!tgn && !tgu) { return alert('举报需至少填写对方游戏名或UID之一'); }
}
for (const f of this.files) fd.append('files', f);
const btn = form.querySelector('[type="submit"]');
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 提交中...';
try {
const res = await API.req('POST', '/tickets', fd);
if (res.tracking_token) {
document.cookie = `tracking_token=${res.tracking_token};path=/;max-age=${365*24*3600};SameSite=Lax`;
}
alert('提交成功!工单编号: #' + res.id);
if (Auth.logged()) App.navigate('tickets');
else App.navigate('home');
} catch (ex) {
alert(ex.message);
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-paper-plane"></i> 提交';
}
});
}
};