Initial commit: 金牛集团贷款档案管理系统

导入现有代码与文档,排除 data/uploads 运行时数据。
This commit is contained in:
梁铭洋
2026-08-29 11:52:22 +08:00
commit 97fea48393
14 changed files with 5478 additions and 0 deletions
@@ -0,0 +1,285 @@
<?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>