(function () { function parseNum(v) { var n = parseFloat(v); return isNaN(n) ? null : n; } function calcRR(direction, entry, stop, target) { if (!entry || !stop || !target) return ''; var risk, reward; if (direction === 'long') { risk = entry - stop; reward = target - entry; } else if (direction === 'short') { risk = stop - entry; reward = entry - target; } else { return ''; } if (risk <= 0) return ''; return (reward / risk).toFixed(2); } function calcDuration(openVal, closeVal) { if (!openVal || !closeVal) return ''; var o = new Date(openVal); var c = new Date(closeVal); var secs = Math.floor((c - o) / 1000); if (secs < 0) return ''; var h = Math.floor(secs / 3600); var m = Math.floor((secs % 3600) / 60); return h ? h + '小时' + m + '分钟' : m + '分钟'; } function recalc() { var form = document.getElementById('review-form'); if (!form) return; var dir = form.querySelector('[name="direction"]').value; var entry = parseNum(form.querySelector('[name="entry_price"]').value); var sl = parseNum(form.querySelector('[name="stop_loss"]').value); var tp = parseNum(form.querySelector('[name="take_profit"]').value); var close = parseNum(form.querySelector('[name="close_price"]').value); var openT = form.querySelector('[name="open_time"]').value; var closeT = form.querySelector('[name="close_time"]').value; var hold = document.getElementById('holding_duration'); var initR = document.getElementById('initial_rr'); var actR = document.getElementById('actual_rr'); if (hold) hold.value = calcDuration(openT, closeT); if (initR) initR.value = calcRR(dir, entry, sl, tp); if (actR) actR.value = calcRR(dir, entry, sl, close); } function bindForm() { var form = document.getElementById('review-form'); if (!form) return; form.querySelectorAll('input, select').forEach(function (el) { el.addEventListener('input', recalc); el.addEventListener('change', recalc); }); } function showModal(data) { var mask = document.getElementById('review-modal'); var body = document.getElementById('review-modal-body'); if (!mask || !body) return; var html = '