dpl/public/admin-custom/telegram-tickets.js

23 lines
5.4 KiB
JavaScript
Vendored

const fieldClass='flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm';
const buttonClass='inline-flex items-center justify-center rounded-md text-sm font-medium bg-primary text-primary-foreground shadow h-9 px-4 py-2 disabled:opacity-50';
function el(tag,text,cls){const n=document.createElement(tag);if(text)n.textContent=text;if(cls)n.className=cls;return n;}
async function api(action,payload){let token;try{token=JSON.parse(localStorage.getItem('XBOARD_ACCESS_TOKEN')||'null');}catch{}if(!token?.value)throw new Error('请重新登录后台');
const base=new URL(window.settings?.base_url||'/',location.origin);if(base.origin!==location.origin)throw new Error('接口必须同源');
const r=await fetch(base.pathname.replace(/\/$/,'')+'/api/v2/'+encodeURIComponent(window.settings.secure_path)+'/config/'+action,{method:payload?'POST':'GET',credentials:'same-origin',headers:{Authorization:token.value,'Content-Type':'application/json'},...(payload?{body:JSON.stringify(payload)}:{})});const j=await r.json();if(!r.ok||j.status==='fail')throw new Error(j.message||'保存失败');return j.data;
}
async function render(host){try{const data=await api('telegramTicket');if(!host.isConnected)return;host.replaceChildren();
host.append(el('h3','工单通知与回复','font-semibold text-lg'),el('p','管理员私聊接收工单;直接回复通知即可写回网站。邮件沿用原有渠道与 30 分钟提醒间隔。','text-sm text-muted-foreground'));
const status=el('p',data.bot_configured?(data.bot_enabled?'机器人已配置并启用':'机器人已配置,尚未启用'):'请先在上方配置客服机器人。','text-sm');host.append(status);const connect=el('button','连接机器人并启用回调',buttonClass);connect.type='button';connect.disabled=!data.bot_configured;connect.addEventListener('click',async()=>{connect.disabled=true;try{await api('setTelegramWebhook',{});await render(host);}catch(e){status.textContent=e.message;connect.disabled=false;}});host.append(connect);
const form=el('form',null,'space-y-4');const fields={};for(const [key,label]of[['notify_enabled','向管理员推送新工单和用户追加内容'],['reply_enabled','允许管理员在 Telegram 回复工单']]){const wrap=el('label',null,'flex items-center gap-3 text-sm');const input=el('input');input.type='checkbox';input.checked=!!data.settings[key];fields[key]=input;wrap.append(input,el('span',label));form.append(wrap);}
form.append(el('p','接收管理员(不选则使用全部已绑定管理员;禁用账号不接收)','text-sm text-muted-foreground'));const admins=[];
for(const a of data.admins){const wrap=el('label',null,'flex items-center gap-3 text-sm');const i=el('input');i.type='checkbox';i.checked=data.settings.receiver_user_ids.map(Number).includes(a.id);wrap.append(i,el('span',a.email+' · '+(a.bound?'已绑定':'未绑定')));admins.push([a.id,i]);form.append(wrap);}
const save=el('button','保存工单设置',buttonClass);save.type='submit';const feedback=el('p',null,'text-sm');form.append(save,feedback);form.addEventListener('submit',async e=>{e.preventDefault();save.disabled=true;try{await api('telegramTicket',{notify_enabled:fields.notify_enabled.checked,reply_enabled:fields.reply_enabled.checked,receiver_user_ids:admins.filter(([,n])=>n.checked).map(([id])=>id)});feedback.textContent='已保存';}catch(e){feedback.textContent=e.message;}finally{save.disabled=false;}});host.append(form);
const bind=el('button','绑定我的 Telegram',buttonClass);bind.type='button';bind.disabled=!data.bot_configured;const command=el('input',null,fieldClass);command.readOnly=true;command.hidden=true;const hint=el('p',null,'text-sm text-muted-foreground');bind.addEventListener('click',async()=>{bind.disabled=true;try{const r=await api('telegramTicketBind',{});command.value=r.command;command.hidden=false;hint.textContent='请在 10 分钟内将这条命令私聊发送给客服机器人。绑定完成后刷新本页;绑定码不要转发。';setTimeout(()=>{if(command.isConnected){command.value='';command.hidden=true;hint.textContent='绑定码已过期,请重新获取。';}},r.expires_in*1000);}catch(e){hint.textContent=e.message;}finally{bind.disabled=false;}});host.append(bind,command,hint);
const counts=data.delivery_counts||{};host.append(el('p','工单推送:待发送 '+(counts.pending||0)+',已发送 '+(counts.sent||0)+',失败 '+(counts.failed||0)+',结果未知 '+(counts.unknown||0)+'。结果未知不会自动重发,避免重复通知。','text-sm text-muted-foreground'));
}catch(e){host.replaceChildren(el('p',e.message,'text-sm text-destructive'));const retry=el('button','重新读取',buttonClass);retry.addEventListener('click',()=>render(host));host.append(retry);}}
let queued=false;function mount(){queued=false;const old=document.getElementById('telegram-ticket-settings');if(!location.hash.startsWith('#/config/system/telegram')){old?.remove();return;}if(old)return;
const heading=[...document.querySelectorAll('h3')].find(n=>n.textContent.trim()==='Telegram设置');const panel=heading?.parentElement?.parentElement;if(!panel)return;
const host=el('section',null,'space-y-4 rounded-xl border bg-card text-card-foreground p-6 mt-6');host.id='telegram-ticket-settings';panel.append(host);render(host);
}
function schedule(){if(!queued){queued=true;requestAnimationFrame(mount);}}new MutationObserver(schedule).observe(document.body,{childList:true,subtree:true});window.addEventListener('hashchange',schedule);schedule();