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();
});
});