Files
jinniu-daikuan/app/views/acceptance_discount_calculator.php
T
梁铭洋 97fea48393 Initial commit: 金牛集团贷款档案管理系统
导入现有代码与文档,排除 data/uploads 运行时数据。
2026-08-29 11:52:22 +08:00

286 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/** @var array $me */
?>
<div class="card fin-tool-page">
<h3 class="section-title">承兑贴现计算器</h3>
<div class="quick-links-col" style="margin-bottom:14px">
<a class="tree-link" href="index.php?action=quick_queries">← 返回便捷查询</a>
</div>
<div class="fin-two-col">
<div class="fin-panel">
<h4>票据信息</h4>
<div class="fin-row">
<label>票据类型</label>
<div>
<label class="inline small"><input type="radio" name="dc_bill" value="bank" checked> 银行承兑汇票</label>
<label class="inline small" style="margin-left:12px"><input type="radio" name="dc_bill" value="commercial"> 商业承兑汇票</label>
<p class="fin-muted" id="dc_risk_hint" style="margin:4px 0 0">银承信用风险相对较低;商承请结合承兑人资信评估。</p>
</div>
</div>
<div class="fin-row">
<label for="dc_face">票面金额(元)</label>
<div>
<input id="dc_face" type="text" inputmode="decimal" style="width:100%;max-width:280px">
<div id="dc_face_fmt" class="fin-muted"></div>
<div id="dc_face_cap" class="fin-cn-cap"></div>
</div>
</div>
<div class="fin-row">
<label for="dc_issue">出票日期</label>
<input id="dc_issue" type="date">
</div>
<div class="fin-row">
<label>到期日</label>
<div>
<label class="inline small"><input type="radio" name="dc_mat_mode" value="date" checked> 指定日期</label>
<label class="inline small" style="margin-left:10px"><input type="radio" name="dc_mat_mode" value="after"> 见票后定期</label>
</div>
</div>
<div class="fin-row" id="dc_row_mat_date">
<label for="dc_maturity">到期日期</label>
<input id="dc_maturity" type="date">
</div>
<div class="fin-row" id="dc_row_mat_after" style="display:none">
<label for="dc_months">期限(月)</label>
<div>
<input id="dc_months" type="number" min="1" max="12" step="1" value="6" style="width:80px">
<button type="button" class="toolbar-btn" id="dc_apply_months" style="margin-left:8px">推算到期日</button>
<span class="fin-muted" id="dc_mat_preview"></span>
</div>
</div>
<div class="fin-row">
<label for="dc_discount">贴现日期</label>
<input id="dc_discount" type="date">
</div>
<div class="fin-row">
<label class="inline"><input type="checkbox" id="dc_holiday"> 到期日遇双休日/法定节假日顺延至下一工作日</label>
</div>
<h4 style="margin:16px 0 10px">贴现参数</h4>
<div class="fin-row">
<label for="dc_rate">贴现年利率 %</label>
<div>
<input id="dc_rate" type="text" inputmode="decimal" style="width:100px">
<button type="button" class="toolbar-btn" data-ref="1.85" style="margin-left:6px">国股参考</button>
<button type="button" class="toolbar-btn" data-ref="2.15">城商参考</button>
<button type="button" class="toolbar-btn" data-ref="2.45">农商参考</button>
</div>
</div>
<div class="fin-row">
<label>计息基准</label>
<span>360 天/年(票据贴现常用)</span>
</div>
<div class="fin-row">
<label class="inline"><input type="checkbox" id="dc_remote"> 异地(+3 天在途)</label>
</div>
<div class="fin-row">
<label for="dc_day_rule">计息方式</label>
<select id="dc_day_rule">
<option value="exclusive" selected>记首不记尾(贴现日至到期前一日)</option>
<option value="inclusive">记首记尾(对比用)</option>
</select>
</div>
<h4 style="margin:16px 0 10px">反向推算(选填其一)</h4>
<div class="fin-row">
<label for="dc_net_in">实付金额(元)</label>
<input id="dc_net_in" type="text" inputmode="decimal" placeholder="反推利率">
</div>
<div class="fin-row">
<label for="dc_per10">每10万扣息(元)</label>
<input id="dc_per10" type="text" inputmode="decimal" placeholder="反推利率">
</div>
<div class="fin-actions">
<button type="button" class="toolbar-btn primary" id="dc_calc">计算</button>
<button type="button" class="toolbar-btn" id="dc_copy">复制结果</button>
<button type="button" class="toolbar-btn" id="dc_save">保存记录</button>
<button type="button" class="btn-gray" id="dc_reset">重置</button>
</div>
</div>
<div>
<div class="fin-result-card" id="dc_result">
<h4 style="margin:0 0 10px">计算结果</h4>
<p id="dc_result_placeholder" class="fin-muted" style="margin:0">填写左侧并点击「计算」</p>
<div id="dc_result_body" style="display:none;font-size:13px;line-height:1.65">
<p style="margin:0"><strong>贴现天数</strong><span id="dc_out_days">—</span> <span id="dc_out_day_note" class="fin-muted"></span></p>
<p style="margin:8px 0 0"><strong>贴现利息</strong><span class="fin-out-num" style="font-size:18px" id="dc_out_int">—</span> 元</p>
<p style="margin:8px 0 0"><strong>实付金额</strong><span id="dc_out_net">—</span> 元</p>
<p style="margin:8px 0 0"><strong>年化成本率</strong><span id="dc_out_ann">—</span></p>
<p style="margin:8px 0 0"><strong>每10万扣息</strong><span id="dc_out_p10">—</span> 元</p>
<p style="margin:8px 0 0" id="dc_rev_line" class="fin-muted"></p>
</div>
</div>
<div class="fin-panel" style="margin-top:12px">
<h4 style="margin:0 0 8px">本地历史记录</h4>
<p class="fin-muted" style="margin:0 0 8px">保存在本浏览器,可对比多次试算。</p>
<ul id="dc_hist_list" style="margin:0;padding-left:18px;font-size:12px;max-height:220px;overflow:auto"></ul>
<button type="button" class="btn-gray" id="dc_hist_clear" style="margin-top:8px">清空历史</button>
</div>
</div>
</div>
</div>
<script>
(function(){
var H2025=['2025-01-01','2025-01-28','2025-01-29','2025-01-30','2025-01-31','2025-02-01','2025-02-02','2025-02-03','2025-02-04','2025-04-04','2025-04-05','2025-04-06','2025-05-01','2025-05-02','2025-05-03','2025-05-04','2025-05-05','2025-05-31','2025-06-01','2025-06-02','2025-10-01','2025-10-02','2025-10-03','2025-10-04','2025-10-05','2025-10-06','2025-10-07','2025-10-08'];
var H2026=['2026-01-01','2026-01-02','2026-01-03','2026-02-15','2026-02-16','2026-02-17','2026-02-18','2026-02-19','2026-02-20','2026-02-21','2026-02-22','2026-02-23','2026-04-04','2026-04-05','2026-04-06','2026-05-01','2026-05-02','2026-05-03','2026-05-04','2026-05-05','2026-06-19','2026-06-20','2026-06-21','2026-09-25','2026-09-26','2026-09-27','2026-10-01','2026-10-02','2026-10-03','2026-10-04','2026-10-05','2026-10-06','2026-10-07'];
var HSET={}; [].concat(H2025,H2026).forEach(function(x){HSET[x]=1;});
function pad(n){return (n<10?'0':'')+n;}
function ymd(d){return d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate());}
function parseYmd(s){
var p=s.split('-'); if(p.length!==3) return null;
var d=new Date(+p[0],+p[1]-1,+p[2]); return isNaN(d.getTime())?null:d;
}
function isWeekend(d){var w=d.getDay(); return w===0||w===6;}
function isHoliday(d){return !!HSET[ymd(d)];}
function isNonWork(d){return isWeekend(d)||isHoliday(d);}
function nextWorkdayFrom(ymdStr){
var d=parseYmd(ymdStr); if(!d) return ymdStr;
for(var i=0;i<20;i++){
if(!isNonWork(d)) return ymd(d);
d.setDate(d.getDate()+1);
}
return ymd(d);
}
function addMonthsKeepDom(y,m,day,addM){
var nm=m-1+addM, ny=y+Math.floor(nm/12), nmo=((nm%12)+12)%12;
var last=new Date(ny,nmo+1,0).getDate();
var nd=Math.min(day,last);
return new Date(ny,nmo,nd);
}
function syncBillHint(){
var v=document.querySelector('input[name="dc_bill"]:checked').value;
document.getElementById('dc_risk_hint').textContent=v==='bank'?'银承:流通性较好,贴现利率通常低于商承。':'商承:请重点评估承兑人信用;贴现利率通常高于银承。';
}
document.querySelectorAll('input[name="dc_bill"]').forEach(function(r){r.addEventListener('change',syncBillHint);});
syncBillHint();
function parseNum(s){s=String(s||'').replace(/,/g,'').trim(); if(s==='')return NaN; var v=parseFloat(s); return isFinite(v)?v:NaN;}
function fmtMoney(n){if(!isFinite(n))return''; var p=(Math.round(n*100)/100).toFixed(2).split('.'); p[0]=p[0].replace(/\B(?=(\d{3})+(?!\d))/g,','); return p.join('.');}
var DIG='零壹贰叁肆伍陆柒捌玖', UNIT=['','拾','佰','仟'];
function sectionFour(n){var s='',str=('0000'+n).slice(-4); for(var i=0;i<4;i++){var d=+str[i]; if(d===0){s+=DIG[0];continue;} s=s.replace(/零+$/,''); s+=DIG[d]+UNIT[3-i];} return (s.replace(/零+/g,'零').replace(/零$/,''))||DIG[0];}
function toRmbUpper(x){if(!isFinite(x)||x<=0)return''; var yi=Math.floor(x/1e8),wan=Math.floor((x%1e8)/1e4),ge=Math.floor(x%1e4); var out=''; if(yi>0)out+=sectionFour(yi)+'亿'; if(wan>0||(yi>0&&ge>0))out+=sectionFour(wan)+'万'; return (out+sectionFour(ge)+'元整').replace(/^壹拾/g,'拾');}
function syncFace(){var v=parseNum(document.getElementById('dc_face').value); document.getElementById('dc_face_fmt').textContent=isFinite(v)&&v>0?('格式化:'+fmtMoney(v)):'';
document.getElementById('dc_face_cap').textContent=isFinite(v)&&v>0?('大写:'+toRmbUpper(Math.floor(v))):'';}
document.getElementById('dc_face').addEventListener('input',syncFace);
document.querySelectorAll('input[name="dc_mat_mode"]').forEach(function(r){
r.addEventListener('change',function(){
var m=document.querySelector('input[name="dc_mat_mode"]:checked').value;
document.getElementById('dc_row_mat_date').style.display=m==='date'?'':'none';
document.getElementById('dc_row_mat_after').style.display=m==='after'?'':'none';
});
});
document.getElementById('dc_apply_months').addEventListener('click',function(){
var iss=document.getElementById('dc_issue').value; if(!iss){alert('请先填出票日');return;}
var mo=parseInt(document.getElementById('dc_months').value,10); if(!(mo>=1&&mo<=12)){alert('期限月数须为1-12');return;}
var p=iss.split('-').map(Number); var d=addMonthsKeepDom(p[0],p[1],p[2],mo);
document.getElementById('dc_maturity').value=ymd(d);
document.getElementById('dc_mat_preview').textContent='推算到期:'+ymd(d);
});
document.querySelectorAll('[data-ref]').forEach(function(btn){
btn.addEventListener('click',function(){ document.getElementById('dc_rate').value=this.getAttribute('data-ref'); });
});
if(!document.getElementById('dc_discount').value){
var t=new Date(); document.getElementById('dc_discount').value=ymd(t);
}
function effectiveMaturity(){
var m=document.querySelector('input[name="dc_mat_mode"]:checked').value;
var mat=document.getElementById('dc_maturity').value;
if(m==='after' && !mat){ alert('请先「推算到期日」或改选指定到期日'); return null; }
if(!mat){ alert('请填写到期日'); return null; }
if(document.getElementById('dc_holiday').checked) return nextWorkdayFrom(mat);
return mat;
}
function discountDays(dis, matEff, rule, remote){
var d0=parseYmd(dis), d1=parseYmd(matEff);
if(!d0||!d1||d1<=d0) return NaN;
var diff=Math.round((d1-d0)/86400000);
var base=rule==='inclusive'?diff+1:diff;
if(base<0) return NaN;
var extra=remote?3:0;
return base+extra;
}
function calcForward(face,ratePct,days){
return face*(ratePct/100)*(days/360);
}
function rateFromNet(face,net,days){
if(!(face>0)||!(net>0)||!(days>0)||net>=face) return NaN;
return (face-net)*360/(face*days)*100;
}
function calc(){
document.getElementById('dc_rev_line').textContent='';
var face=parseNum(document.getElementById('dc_face').value);
var dis=document.getElementById('dc_discount').value;
var matEff=effectiveMaturity();
var rule=document.getElementById('dc_day_rule').value;
var remote=document.getElementById('dc_remote').checked;
var days=discountDays(dis,matEff,rule,remote);
if(!(face>0)){ alert('票面金额须大于0'); return; }
if(!dis||!matEff){ alert('请完善贴现日与到期日'); return; }
if(!isFinite(days)||days<=0){ alert('贴现日须早于到期日,且计息天数须为正'); return; }
var netIn=parseNum(document.getElementById('dc_net_in').value);
var per10=parseNum(document.getElementById('dc_per10').value);
var rate=parseNum(document.getElementById('dc_rate').value);
var intr;
if(isFinite(netIn)&&netIn>0&&netIn<face){
rate=rateFromNet(face,netIn,days);
if(!isFinite(rate)||!(rate>0)){ alert('无法根据实付金额反推利率,请检查天数与金额'); return; }
intr=face-netIn;
document.getElementById('dc_rate').value=rate.toFixed(4);
document.getElementById('dc_rev_line').textContent='已按实付金额反推贴现年利率:'+rate.toFixed(4)+'%';
} else if(isFinite(per10)&&per10>0){
intr=per10*(face/100000);
rate=(intr*360/(face*days))*100;
if(!isFinite(rate)||!(rate>0)){ alert('无法根据每10万扣息反推利率'); return; }
document.getElementById('dc_rate').value=rate.toFixed(4);
document.getElementById('dc_rev_line').textContent='已按每10万扣息反推贴现年利率:'+rate.toFixed(4)+'%';
} else {
if(!(rate>0)){ alert('请输入贴现年利率,或填写反推字段'); return; }
intr=calcForward(face,rate,days);
}
var net=face-intr;
var ann=net>0 ? (intr/net)*(360/days)*100 : NaN;
var p10=face>0? intr/(face/100000):NaN;
document.getElementById('dc_out_days').textContent=String(days);
document.getElementById('dc_out_day_note').textContent=(remote?'(含异地+3天)':'')+(document.getElementById('dc_holiday').checked?';到期日已按工作日顺延':'');
document.getElementById('dc_out_int').textContent=fmtMoney(intr);
document.getElementById('dc_out_net').textContent=fmtMoney(net);
document.getElementById('dc_out_ann').textContent=isFinite(ann)?(ann.toFixed(4)+'%'):'—';
document.getElementById('dc_out_p10').textContent=isFinite(p10)?fmtMoney(p10):'—';
document.getElementById('dc_result_placeholder').style.display='none';
document.getElementById('dc_result_body').style.display='block';
window._dc_last={face:face,intr:intr,net:net,days:days,w:face/10000};
}
function copyRes(){
if(!window._dc_last){ alert('请先计算'); return; }
var w=window._dc_last.w, t='票面'+w.toFixed(2)+'万 | 贴现息'+fmtMoney(window._dc_last.intr)+'元 | 实付'+fmtMoney(window._dc_last.net)+'元 | 天数'+window._dc_last.days+'天';
if(navigator.clipboard) navigator.clipboard.writeText(t).then(function(){alert('已复制');},function(){alert(t);});
else alert(t);
}
function saveHist(){
if(!window._dc_last){ alert('请先计算'); return; }
var key='dc_hist_v1', arr=JSON.parse(localStorage.getItem(key)||'[]');
arr.unshift({t:Date.now(),...window._dc_last,rate:document.getElementById('dc_rate').value});
arr=arr.slice(0,30); localStorage.setItem(key,JSON.stringify(arr)); renderHist();
}
function renderHist(){
var arr=JSON.parse(localStorage.getItem('dc_hist_v1')||'[]');
var ul=document.getElementById('dc_hist_list'); ul.innerHTML='';
arr.forEach(function(r,i){
var li=document.createElement('li');
li.textContent=new Date(r.t).toLocaleString()+' — 实付 '+fmtMoney(r.net)+' / 息 '+fmtMoney(r.intr)+' / '+r.days+'天 / 利率'+r.rate+'%';
ul.appendChild(li);
});
}
document.getElementById('dc_calc').addEventListener('click',calc);
document.getElementById('dc_copy').addEventListener('click',copyRes);
document.getElementById('dc_save').addEventListener('click',saveHist);
document.getElementById('dc_hist_clear').addEventListener('click',function(){ localStorage.removeItem('dc_hist_v1'); renderHist(); });
document.getElementById('dc_reset').addEventListener('click',function(){
document.getElementById('dc_face').value=''; document.getElementById('dc_rate').value='';
document.getElementById('dc_issue').value=''; document.getElementById('dc_maturity').value='';
document.getElementById('dc_net_in').value=''; document.getElementById('dc_per10').value='';
syncFace(); document.getElementById('dc_result_body').style.display='none';
document.getElementById('dc_result_placeholder').style.display='block';
});
renderHist();
})();
</script>