Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cb0abcf41 | ||
|
|
c3e0e9a496 | ||
|
|
b626de53ca |
+21
-14
@@ -7,11 +7,14 @@ function renderHome() {
|
|||||||
// 回款提醒
|
// 回款提醒
|
||||||
const yrRev = m.revenue_annual || 0, yrPay = m.payment_annual || 0, yrUnpaid = yrRev - yrPay;
|
const yrRev = m.revenue_annual || 0, yrPay = m.payment_annual || 0, yrUnpaid = yrRev - yrPay;
|
||||||
const yrPayRate = yrRev > 0 ? Math.round(yrPay / yrRev * 100) : 0;
|
const yrPayRate = yrRev > 0 ? Math.round(yrPay / yrRev * 100) : 0;
|
||||||
const yrUnpaidWan = Math.round(yrUnpaid / 10000);
|
const yrUnpaidWan = Math.round(Math.abs(yrUnpaid) / 10000);
|
||||||
const payRateCls = yrPayRate < 30 ? 'text-red-600' : yrPayRate < 80 ? 'text-amber-600' : 'text-green-600';
|
const payRateCls = yrPayRate < 30 ? 'text-red-600' : yrPayRate < 80 ? 'text-amber-600' : 'text-green-600';
|
||||||
|
const unpaidLabel = yrUnpaid >= 0
|
||||||
|
? '你还有 <strong class=\"text-red-600\">' + yrUnpaidWan + '万</strong> 未回款'
|
||||||
|
: '超额回款 <strong class=\"text-green-600\">' + yrUnpaidWan + '万</strong>';
|
||||||
const payReminder = yrRev > 0 ? '<div class=\"flex items-center gap-3 px-4 py-3 rounded-lg border\" style=\"background:linear-gradient(135deg,#fef3c7,#fde68a);border-color:#f59e0b\">' +
|
const payReminder = yrRev > 0 ? '<div class=\"flex items-center gap-3 px-4 py-3 rounded-lg border\" style=\"background:linear-gradient(135deg,#fef3c7,#fde68a);border-color:#f59e0b\">' +
|
||||||
'<i data-lucide=\"bell-ring\" class=\"text-amber-600 flex-shrink-0\" style=\"width:18px;height:18px\"></i>' +
|
'<i data-lucide=\"bell-ring\" class=\"text-amber-600 flex-shrink-0\" style=\"width:18px;height:18px\"></i>' +
|
||||||
'<span class=\"text-sm text-amber-900\"><strong>回款提醒:</strong>本年度确收 <strong>' + moneyInt(yrRev) + '</strong>,回款 <strong>' + moneyInt(yrPay) + '</strong>,你还有 <strong class=\"text-red-600\">' + yrUnpaidWan + '万</strong> 未回款,当前回款率:<strong class=\"' + payRateCls + '\">' + yrPayRate + '%</strong></span>' +
|
'<span class=\"text-sm text-amber-900\"><strong>回款提醒:</strong>本年度确收 <strong>' + moneyInt(yrRev) + '</strong>,回款 <strong>' + moneyInt(yrPay) + '</strong>,' + unpaidLabel + ',当前回款率:<strong class=\"' + payRateCls + '\">' + yrPayRate + '%</strong></span>' +
|
||||||
'</div>' : '';
|
'</div>' : '';
|
||||||
const rows1 = [
|
const rows1 = [
|
||||||
["年度累计", moneyInt(m.signed_annual || m.signed_amount)],
|
["年度累计", moneyInt(m.signed_annual || m.signed_amount)],
|
||||||
@@ -123,7 +126,6 @@ function renderHome() {
|
|||||||
].map(([label, value, tab]) => `<button class="metric-card" onclick="switchTab('${tab}')"><span class="flex items-center gap-2 text-xs text-slate-500"><i data-lucide="gauge"></i>${label}</span><strong class="mt-2 block text-2xl">${value}</strong></button>`).join("")}
|
].map(([label, value, tab]) => `<button class="metric-card" onclick="switchTab('${tab}')"><span class="flex items-center gap-2 text-xs text-slate-500"><i data-lucide="gauge"></i>${label}</span><strong class="mt-2 block text-2xl">${value}</strong></button>`).join("")}
|
||||||
</div>`}
|
</div>`}
|
||||||
${payReminder}
|
${payReminder}
|
||||||
${card(`<h3 class="text-sm font-bold text-slate-700 mb-3">部门经营情况</h3><div class="overflow-x-auto"><table class="w-full text-sm"><thead><tr class="border-b border-slate-200"><th class="py-2 text-left text-slate-500">指标</th><th class="py-2 text-right font-semibold text-slate-700">年度累计</th><th class="py-2 text-right font-semibold text-slate-700">上季度累计</th><th class="py-2 text-right font-semibold text-slate-700">上月累计</th><th class="py-2 text-right font-semibold text-slate-700">本季度累计</th><th class="py-2 text-right font-semibold text-slate-400">季环比</th><th class="py-2 text-right font-semibold text-slate-700">本月累计</th><th class="py-2 text-right font-semibold text-slate-400">月环比</th></tr></thead><tbody>
|
|
||||||
${(() => {
|
${(() => {
|
||||||
var d = [
|
var d = [
|
||||||
['项目毛利', [m.profit_annual||0, m.profit_q2||0, m.profit_month||0, m.profit_prev_q||0, m.profit_prev_month||0],
|
['项目毛利', [m.profit_annual||0, m.profit_q2||0, m.profit_month||0, m.profit_prev_q||0, m.profit_prev_month||0],
|
||||||
@@ -140,27 +142,32 @@ function renderHome() {
|
|||||||
]],
|
]],
|
||||||
['项目现金流', [m.cashflow_annual||0, m.cashflow_q2||0, m.cashflow_month||0, m.cashflow_prev_q||0, m.cashflow_prev_month||0],
|
['项目现金流', [m.cashflow_annual||0, m.cashflow_q2||0, m.cashflow_month||0, m.cashflow_prev_q||0, m.cashflow_prev_month||0],
|
||||||
[m.cashflow_q2||0,m.cashflow_prev_q||0], [m.cashflow_month||0,m.cashflow_prev_month||0]],
|
[m.cashflow_q2||0,m.cashflow_prev_q||0], [m.cashflow_month||0,m.cashflow_prev_month||0]],
|
||||||
['部门费用(已付)', [m.expense_paid_annual||0, m.expense_paid_q2||0, m.expense_paid_month||0, m.expense_paid_prev_q||0, m.expense_paid_prev_month||0],
|
['部门费用现金流', [m.expense_paid_annual||0, m.expense_paid_q2||0, m.expense_paid_month||0, m.expense_paid_prev_q||0, m.expense_paid_prev_month||0],
|
||||||
[m.expense_paid_q2||0,m.expense_paid_prev_q||0], [m.expense_paid_month||0,m.expense_paid_prev_month||0]],
|
[m.expense_paid_q2||0,m.expense_paid_prev_q||0], [m.expense_paid_month||0,m.expense_paid_prev_month||0]],
|
||||||
['部门现金流', [m.dept_cf_annual||0, m.dept_cf_q2||0, m.dept_cf_month||0, m.dept_cf_prev_q||0, m.dept_cf_prev_month||0],
|
['部门现金流', [m.dept_cf_annual||0, m.dept_cf_q2||0, m.dept_cf_month||0, m.dept_cf_prev_q||0, m.dept_cf_prev_month||0],
|
||||||
[m.dept_cf_q2||0,m.dept_cf_prev_q||0], [m.dept_cf_month||0,m.dept_cf_prev_month||0]]
|
[m.dept_cf_q2||0,m.dept_cf_prev_q||0], [m.dept_cf_month||0,m.dept_cf_prev_month||0]]
|
||||||
];
|
];
|
||||||
|
var buildDeptTable = function(title, dataRows) {
|
||||||
var h = '';
|
var h = '';
|
||||||
var netCls = function(di, raw) { if (di === 2 || di === 5) return raw >= 0 ? 'text-green-600' : 'text-red-600'; if (di === 3) return raw >= 0 ? 'text-green-600' : 'text-red-600'; return 'text-slate-800'; };
|
for (var di = 0; di < dataRows.length; di++) {
|
||||||
for (var di = 0; di < 6; di++) {
|
var r = dataRows[di];
|
||||||
var r = d[di];
|
var rawNet = r[1][0];
|
||||||
|
var isNet = r[0] === '部门净利' || r[0] === '部门现金流';
|
||||||
|
var isCF = r[0] === '项目现金流';
|
||||||
|
var cls = isNet ? (rawNet >= 0 ? 'text-green-600' : 'text-red-600') : isCF ? (rawNet >= 0 ? 'text-green-600' : 'text-red-600') : 'text-slate-800';
|
||||||
h += '<tr class="border-b border-slate-100 last:border-0"><td class="py-2 text-left font-semibold text-slate-700">' + r[0] + '</td>' +
|
h += '<tr class="border-b border-slate-100 last:border-0"><td class="py-2 text-left font-semibold text-slate-700">' + r[0] + '</td>' +
|
||||||
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][0]) + '">' + moneyInt(r[1][0]) + '</td>' +
|
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt(r[1][0]) + '</td>' +
|
||||||
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][3]) + '">' + moneyInt(r[1][3]) + '</td>' +
|
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt(r[1][3]) + '</td>' +
|
||||||
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][4]) + '">' + moneyInt(r[1][4]) + '</td>' +
|
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt(r[1][4]) + '</td>' +
|
||||||
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][1]) + '">' + moneyInt(r[1][1]) + '</td>' +
|
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt(r[1][1]) + '</td>' +
|
||||||
'<td class="py-2 text-right">' + qoq(r[2][0], r[2][1]) + '</td>' +
|
'<td class="py-2 text-right">' + qoq(r[2][0], r[2][1]) + '</td>' +
|
||||||
'<td class="py-2 text-right font-semibold ' + netCls(di, r[1][2]) + '">' + moneyInt(r[1][2]) + '</td>' +
|
'<td class="py-2 text-right font-semibold ' + cls + '">' + moneyInt(r[1][2]) + '</td>' +
|
||||||
'<td class="py-2 text-right">' + qoq(r[3][0], r[3][1]) + '</td></tr>';
|
'<td class="py-2 text-right">' + qoq(r[3][0], r[3][1]) + '</td></tr>';
|
||||||
}
|
}
|
||||||
return h;
|
return card('<h3 class="text-sm font-bold text-slate-700 mb-3">' + title + '</h3><div class="overflow-x-auto"><table class="w-full text-sm"><thead><tr class="border-b border-slate-200"><th class="py-2 text-left text-slate-500">指标</th><th class="py-2 text-right font-semibold text-slate-700">年度累计</th><th class="py-2 text-right font-semibold text-slate-700">上季度累计</th><th class="py-2 text-right font-semibold text-slate-700">上月累计</th><th class="py-2 text-right font-semibold text-slate-700">本季度累计</th><th class="py-2 text-right font-semibold text-slate-400">季环比</th><th class="py-2 text-right font-semibold text-slate-700">本月累计</th><th class="py-2 text-right font-semibold text-slate-400">月环比</th></tr></thead><tbody>' + h + '</tbody></table></div>', 'p-4');
|
||||||
|
};
|
||||||
|
return buildDeptTable('部门经营情况', d.slice(0, 3)) + buildDeptTable('部门现金流', d.slice(3, 6));
|
||||||
})()}
|
})()}
|
||||||
</tbody></table></div>`, "p-4")}
|
|
||||||
${card(`<h3 class="text-sm font-bold text-slate-700">业务(项目)财务概览</h3><p class="text-xs text-slate-400 mb-3">合同 → 确收 → 毛利 → 成本 → 项目利润 → 回款 → 已付 → 现金流</p><div class="overflow-x-auto"><table class="w-full text-sm"><thead>${thead}</thead><tbody>${tbody}</tbody></table></div>`, "p-4")}
|
${card(`<h3 class="text-sm font-bold text-slate-700">业务(项目)财务概览</h3><p class="text-xs text-slate-400 mb-3">合同 → 确收 → 毛利 → 成本 → 项目利润 → 回款 → 已付 → 现金流</p><div class="overflow-x-auto"><table class="w-full text-sm"><thead>${thead}</thead><tbody>${tbody}</tbody></table></div>`, "p-4")}
|
||||||
<div class="grid grid-cols-4 gap-5">
|
<div class="grid grid-cols-4 gap-5">
|
||||||
${card(`<div class="mb-3 flex items-center justify-between"><h2 class="text-sm font-bold text-slate-600">月度签约趋势</h2><span class="text-xs text-slate-400">2026</span></div><div style="position:relative;height:200px"><canvas id="chartSign"></canvas></div>`, "p-4")}
|
${card(`<div class="mb-3 flex items-center justify-between"><h2 class="text-sm font-bold text-slate-600">月度签约趋势</h2><span class="text-xs text-slate-400">2026</span></div><div style="position:relative;height:200px"><canvas id="chartSign"></canvas></div>`, "p-4")}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<header class="topbar border-b border-slate-200 bg-white px-8 py-5">
|
<header class="topbar border-b border-slate-200 bg-white px-8 py-5">
|
||||||
<div class="flex items-center gap-3 w-full">
|
<div class="flex items-center gap-3 w-full">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<p class="eyebrow text-xs font-semibold uppercase tracking-[0.18em] text-blue-700">OPC Manager <span class="ml-2 text-xs font-normal text-slate-400 tracking-normal">v1.0.0.8</span></p>
|
<p class="eyebrow text-xs font-semibold uppercase tracking-[0.18em] text-blue-700">OPC Manager <span class="ml-2 text-xs font-normal text-slate-400 tracking-normal">v1.0.0.11</span></p>
|
||||||
<div class="flex items-center gap-4 mt-1">
|
<div class="flex items-center gap-4 mt-1">
|
||||||
<h1 class="text-2xl font-semibold" id="workspaceTitle">科普 OPC 工作台</h1>
|
<h1 class="text-2xl font-semibold" id="workspaceTitle">科普 OPC 工作台</h1>
|
||||||
<div class="hidden sm:flex items-center gap-1.5 bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-100 rounded-full px-4 py-1.5">
|
<div class="hidden sm:flex items-center gap-1.5 bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-100 rounded-full px-4 py-1.5">
|
||||||
|
|||||||
Reference in New Issue
Block a user