import type { SiteContext } from "./context"; import { escape } from "./render"; export function feedbackPayload(data:FormData,screenshots:string[]=[]) { const value=(key:string)=>String(data.get(key)||'').trim(); const description=value('content'); if(description.length<10||description.length>500)throw new Error('请填写 10–500 字的问题描述'); const labels:Record={category:'问题类型',frequency:'发生频率',province:'所在地区',city:'城市',carrier:'运营商',network:'网络类型',device:'设备类型',model:'设备型号',version:'App 版本'}; const details=Object.entries(labels).filter(([key])=>value(key)).map(([key,label])=>`${label}:${value(key)}`).join('\n'); const category=value('category'); const type=category==='登录异常'?4:category==='其他问题'?5:2; const remaining=500-description.length; const context=remaining>2&&details?'\n\n'+details.slice(0,remaining-2):''; return {type,content:description+context,contact:value('contact'),screenshots}; } export function renderFeedbackPage(app:SiteContext,preserveMarkup=false) { const root=document.getElementById('info-content')!;if(!preserveMarkup)root.innerHTML=feedbackMarkup(); const form=root.querySelector('#feedback-form')!,signal=app.signal; const input=form.querySelector('#feedback-files')!,list=form.querySelector('#feedback-file-list')!,error=form.querySelector('#feedback-file-error')!,status=form.querySelector('#feedback-status')!; let files:File[]=[],previews:string[]=[]; const uploaded=new Map(); const clearPreviews=()=>{previews.forEach(url=>URL.revokeObjectURL(url));previews=[];}; const renderFiles=()=>{ clearPreviews(); list.innerHTML=files.map((file,index)=>{const url=URL.createObjectURL(file);previews.push(url);return ``;}).join(''); }; signal.addEventListener('abort',clearPreviews,{once:true}); input.addEventListener('change',()=>{ if(form.dataset.submitting)return; const selected=Array.from(input.files||[]); const invalid=selected.length>3?'最多上传 3 张图片':selected.some(file=>file.size>5*1024*1024||!['image/jpeg','image/png','image/webp'].includes(file.type))?'请上传 5MB 以内的 JPG、PNG 或 WebP 图片':''; error.textContent=invalid; if(invalid){input.value='';return;} files=selected;renderFiles(); },{signal}); list.addEventListener('click',event=>{ const button=(event.target as Element).closest('[data-remove-feedback-file]');if(!button||form.dataset.submitting)return; files.splice(Number(button.dataset.removeFeedbackFile),1);input.value='';renderFiles(); },{signal}); const content=form.querySelector('[name="content"]')!; content.addEventListener('input',()=>{form.querySelector('#feedback-count')!.textContent=content.value.length+' / 500';},{signal}); form.addEventListener('submit',event=>{ event.preventDefault();if(form.dataset.submitting||!form.reportValidity())return; const data=new FormData(form),attachments=[...files]; try{feedbackPayload(data);}catch(reason){status.textContent=reason instanceof Error?reason.message:'请检查反馈内容';return;} const button=form.querySelector('[type="submit"]')!; button.disabled=true;input.disabled=true;form.dataset.submitting='1';status.textContent='提交中…'; void (async()=>{ const screenshots:string[]=[]; for(const file of attachments){ if(signal.aborted)return; let path=uploaded.get(file); if(!path){const body=new FormData();body.append('file',file);body.append('watermark','0');const result=await app.api.post<{sourceNameFs?:string}>('upload/image',body);if(!result.sourceNameFs)throw new Error('图片上传失败,请重试');path=result.sourceNameFs;uploaded.set(file,path);} screenshots.push(path); } if(signal.aborted)return; await app.api.post('feedback/add',feedbackPayload(data,screenshots)); if(signal.aborted)return; form.reset();files=[];uploaded.clear();renderFiles();error.textContent='';form.querySelector('#feedback-count')!.textContent='0 / 500';status.textContent='反馈已提交,感谢您的反馈!'; })().catch(reason=>{if(!signal.aborted)status.textContent=reason instanceof Error?reason.message:'反馈提交失败,请重试';}).finally(()=>{button.disabled=false;input.disabled=false;delete form.dataset.submitting;}); },{signal}); } export const feedbackMarkup=()=>``;