const API = 'http://localhost:8080'; let token = null; let currentView = 'MINE'; const $ = (id) => document.getElementById(id); function toast(msg) { const t = $('toast'); t.textContent = msg; t.classList.remove('hidden'); clearTimeout(t._h); t._h = setTimeout(() => t.classList.add('hidden'), 2500); } function authHeaders(extra = {}) { const h = { ...extra }; if (token) h['Authorization'] = 'Bearer ' + token; return h; } const STATUS_TEXT = { 1: '待领取', 2: '推进中', 3: '暂缓中', 4: '已关闭', 5: '已转项目' }; // ---- 登录(调试 token)---- async function login() { const userId = $('userId').value.trim(); try { const res = await fetch(`${API}/api/auth/debug/token?userId=${encodeURIComponent(userId)}`); const body = await res.json(); if (body.success && body.data) { token = body.data; $('tokenState').textContent = '已登录 uid=' + userId; $('tokenState').className = 'pill pill-on'; toast('登录成功'); loadList(); } else { toast('登录失败: ' + (body.message || res.status)); } } catch (e) { toast('登录请求异常: ' + e.message); } } // ---- 列表 ---- async function loadList() { if (!token) { toast('请先签发调试 Token'); return; } const params = new URLSearchParams({ viewType: currentView, current: '1', size: '20' }); try { const res = await fetch(`${API}/api/opportunity/page`, { method: 'POST', headers: authHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }), body: params.toString(), }); const body = await res.json(); if (!body.success) { renderRows([]); $('listMeta').textContent = '错误: ' + body.message; return; } const page = body.data || {}; renderRows(page.content || []); $('listMeta').textContent = `视图 ${currentView} · 共 ${page.total ?? 0} 条`; } catch (e) { toast('列表加载异常: ' + e.message); } } function renderRows(rows) { const tbody = $('oppRows'); if (!rows.length) { tbody.innerHTML = '无数据'; return; } tbody.innerHTML = rows.map((r) => ` ${r.id ?? ''} ${esc(r.oppName)} ${esc(r.oppSourceName || r.oppSource || '')} ${STATUS_TEXT[r.oppStatus] || r.oppStatus || ''} ${esc(r.currentStageName || '')} ${esc(r.ownerNameSnapshot || '')} ${esc(r.primaryCustomerNameSnapshot || '')} ${r.projectAmount ?? ''} `).join(''); } function esc(s) { return String(s ?? '').replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); } // ---- 新建商机 ---- async function openNewModal() { if (!token) { toast('请先签发调试 Token'); return; } $('newForm').reset(); $('formMsg').textContent = ''; onSourceChange(); $('newModal').classList.remove('hidden'); } function closeNewModal() { $('newModal').classList.add('hidden'); } async function onSourceChange() { const isLead = $('f_oppSource').value === 'opp_source_01'; $('leadRow').classList.toggle('hidden', !isLead); if (isLead) await loadConvertibleLeads(); } async function loadConvertibleLeads() { const sel = $('f_sourceLeadId'); sel.innerHTML = ''; try { const res = await fetch(`${API}/api/opportunity/convertible-leads`, { headers: authHeaders() }); const body = await res.json(); const list = (body.success && body.data) || []; sel.innerHTML = '' + list.map((l) => ``).join(''); if (!list.length) sel.innerHTML = ''; } catch (e) { sel.innerHTML = ''; } } async function submitNew(ev) { ev.preventDefault(); const msg = $('formMsg'); msg.textContent = '提交中…'; msg.className = 'msg'; const payload = { oppSource: $('f_oppSource').value, opportunityName: $('f_oppName').value.trim(), partyA: $('f_partyA').value.trim() || null, customerName: $('f_customerName').value.trim() || null, remark: $('f_remark').value.trim() || null, sourceLeadId: $('f_sourceLeadId').value ? Number($('f_sourceLeadId').value) : null, }; try { const res = await fetch(`${API}/api/opportunity`, { method: 'POST', headers: authHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(payload), }); const body = await res.json(); if (body.success) { msg.textContent = '创建成功 id=' + body.data; msg.className = 'msg ok'; toast('商机已创建 id=' + body.data); setTimeout(() => { closeNewModal(); loadList(); }, 700); } else { msg.textContent = '失败: ' + (body.message || res.status); msg.className = 'msg err'; } } catch (e) { msg.textContent = '异常: ' + e.message; msg.className = 'msg err'; } } // ---- 事件绑定 ---- $('btnLogin').addEventListener('click', login); $('btnRefresh').addEventListener('click', loadList); $('btnNew').addEventListener('click', openNewModal); $('btnCancel').addEventListener('click', closeNewModal); $('f_oppSource').addEventListener('change', onSourceChange); $('newForm').addEventListener('submit', submitNew); document.querySelectorAll('#viewTabs button').forEach((b) => { b.addEventListener('click', () => { document.querySelectorAll('#viewTabs button').forEach((x) => x.classList.remove('active')); b.classList.add('active'); currentView = b.dataset.view; loadList(); }); });