/** * config-ui.ts 集成补丁 * * 此文件包含需要添加到 config-ui.ts 的代码片段 * 由于 config-ui.ts 文件太大(3800+ 行),这里提供独立的补丁代码 */ /* ===================================================== 1. 文件顶部导入 ===================================================== */ import { generateDashboardHtml, getDashboardCss, getDashboardJs, type DashboardData } from './dashboard-ui.js'; import { registerDashboardApiRoutes } from '../api/dashboard.js'; /* ===================================================== 2. PaymentRow 接口定义(添加到其他接口旁边) ===================================================== */ interface PaymentRow { id: string; company_id: string; direction: string; counterparty: string; amount: number; paid_amount: number; status: string; due_date: string; paid_date: string; invoice_id: string; contract_id: string; category: string; payment_method: string; notes: string; created_at: string; updated_at: string; } /* ===================================================== 3. handleCompanyDetail 函数中添加 payments 查询 ===================================================== */ // 在 handleCompanyDetail 函数的查询部分添加: const payments = db.query( `SELECT * FROM opc_payments WHERE company_id = ? ORDER BY CASE status WHEN 'overdue' THEN 0 WHEN 'pending' THEN 1 WHEN 'partial' THEN 2 ELSE 3 END, due_date ASC`, companyId, ) as PaymentRow[]; // 在返回对象中添加: return { // ... 其他字段 payments, }; /* ===================================================== 4. registerConfigUiRoutes 函数中注册 Dashboard API ===================================================== */ export function registerConfigUiRoutes(api: OpenClawPluginApi, db: OpcDatabase, gatewayToken?: string): void { // 注册 Dashboard API 路由 registerDashboardApiRoutes(api, db); // 添加收付款相关 API 端点 // GET /opc/admin/api/payments/:id api.registerHttpRoute({ path: '/opc/admin/api/payments', handler: async (req, res) => { const match = req.url?.match(/^\/opc\/admin\/api\/payments\/([^/]+)$/); if (!match) { sendJson(res, { error: 'Invalid payment ID' }, 400); return true; } const paymentId = match[1]; const payment = db.queryOne('SELECT * FROM opc_payments WHERE id = ?', paymentId); if (!payment) { sendJson(res, { error: 'Payment not found' }, 404); return true; } sendJson(res, payment); return true; }, }); // POST /opc/admin/api/payments - 创建收付款 api.registerHttpRoute({ path: '/opc/admin/api/payments', handler: async (req, res) => { if (req.method !== 'POST') return false; try { const body = await readBody(req); const data = JSON.parse(body); const id = 'PAY-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9).toUpperCase(); const now = new Date().toISOString(); db.execute( `INSERT INTO opc_payments ( id, company_id, direction, counterparty, amount, due_date, category, payment_method, notes, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, id, data.company_id, data.direction, data.counterparty, parseFloat(data.amount) || 0, data.due_date, data.category || '', data.payment_method || '', data.notes || '', now, now, ); sendJson(res, { ok: true, id }); return true; } catch (err) { sendJson(res, { ok: false, error: err instanceof Error ? err.message : String(err) }, 500); return true; } }, }); // PUT /opc/admin/api/payments/:id - 更新收付款 api.registerHttpRoute({ path: '/opc/admin/api/payments', handler: async (req, res) => { if (req.method !== 'PUT') return false; const match = req.url?.match(/^\/opc\/admin\/api\/payments\/([^/]+)$/); if (!match) { sendJson(res, { error: 'Invalid payment ID' }, 400); return true; } const paymentId = match[1]; try { const body = await readBody(req); const data = JSON.parse(body); const now = new Date().toISOString(); db.execute( `UPDATE opc_payments SET direction = ?, counterparty = ?, amount = ?, due_date = ?, category = ?, payment_method = ?, notes = ?, updated_at = ? WHERE id = ?`, data.direction, data.counterparty, parseFloat(data.amount) || 0, data.due_date, data.category || '', data.payment_method || '', data.notes || '', now, paymentId, ); sendJson(res, { ok: true }); return true; } catch (err) { sendJson(res, { ok: false, error: err instanceof Error ? err.message : String(err) }, 500); return true; } }, }); // POST /opc/admin/api/payments/:id/record - 记账 api.registerHttpRoute({ path: '/opc/admin/api/payments', handler: async (req, res) => { if (req.method !== 'POST') return false; const match = req.url?.match(/^\/opc\/admin\/api\/payments\/([^/]+)\/record$/); if (!match) { sendJson(res, { error: 'Invalid payment ID' }, 400); return true; } const paymentId = match[1]; try { const body = await readBody(req); const data = JSON.parse(body); const paidAmount = parseFloat(data.paid_amount) || 0; // 获取当前记录 const payment = db.queryOne('SELECT * FROM opc_payments WHERE id = ?', paymentId) as PaymentRow | null; if (!payment) { sendJson(res, { error: 'Payment not found' }, 404); return true; } const newPaidAmount = payment.paid_amount + paidAmount; const now = new Date().toISOString(); // 更新状态 let newStatus = payment.status; if (newPaidAmount >= payment.amount) { newStatus = 'paid'; } else if (newPaidAmount > 0) { newStatus = 'partial'; } db.execute( `UPDATE opc_payments SET paid_amount = ?, status = ?, paid_date = ?, updated_at = ? WHERE id = ?`, newPaidAmount, newStatus, now.slice(0, 10), now, paymentId, ); sendJson(res, { ok: true }); return true; } catch (err) { sendJson(res, { ok: false, error: err instanceof Error ? err.message : String(err) }, 500); return true; } }, }); // ... 原有路由注册代码继续 } /* ===================================================== 5. getCss() 函数中添加 Dashboard 和 Modal 样式 ===================================================== */ // 在 getCss() 返回值末尾添加: + getDashboardCss() + "\n.modal{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px}" + "\n.modal-content{background:var(--card);border-radius:var(--r);max-width:800px;width:100%;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04)}" + "\n.modal-header{padding:20px 24px;border-bottom:1px solid var(--bd);display:flex;justify-content:space-between;align-items:center}" + "\n.modal-header h3{font-size:18px;font-weight:600;margin:0}" + "\n.modal-close{font-size:28px;font-weight:300;line-height:1;cursor:pointer;color:var(--tx3);transition:color .15s}" + "\n.modal-close:hover{color:var(--tx)}" + "\n.modal-body{padding:24px;overflow-y:auto}" + "\n.modal-actions{display:flex;gap:12px;justify-content:flex-end;padding-top:16px;border-top:1px solid var(--bd);margin-top:16px}" + "\n.form-group{margin-bottom:16px}" + "\n.form-group label{display:block;font-size:13px;font-weight:500;margin-bottom:6px;color:var(--tx)}" + "\n.form-group input,.form-group select,.form-group textarea{width:100%;padding:9px 14px;border:1px solid var(--bd);border-radius:var(--r);font-size:13px;font-family:var(--font);background:var(--card);color:var(--tx)}" + "\n.form-group input:focus,.form-group select:focus,.form-group textarea:focus{outline:none;border-color:var(--tx3)}" + "\n.btn-link{background:none;border:none;color:var(--tx);cursor:pointer;font-size:13px;text-decoration:underline;padding:0}" + "\n.btn-link:hover{color:var(--tx2)}" + "\n.btn-primary{padding:9px 18px;background:var(--tx);color:white;border:none;border-radius:var(--r);font-size:13px;font-weight:500;cursor:pointer;font-family:var(--font);transition:all .15s}" + "\n.btn-primary:hover{background:var(--pri-l)}" + "\n.btn-secondary{padding:9px 18px;background:var(--bg);color:var(--tx);border:1px solid var(--bd);border-radius:var(--r);font-size:13px;font-weight:500;cursor:pointer;font-family:var(--font);transition:all .15s}" + "\n.btn-secondary:hover{background:#f3f4f6}" /* ===================================================== 6. getBodyHtml() 函数修改 ===================================================== */ // 在侧边栏部分,将原来的 monitoring 改为 dashboard-monitor: + ' 监控中心' // 在 main 区域添加新的 dashboard-monitor 视图: + '
一屏看清公司运营状态、风险预警、今日待办
暂无数据
加载失败: '+e.message+'
| 方向 | 对方 | 金额 | 已付 | 状态 | 到期日 | 类别 | 操作 |
|---|---|---|---|---|---|---|---|
| '+directionBadge+' | '+esc(p.counterparty)+' | '+fmt(p.amount)+' 元 | '+fmt(p.paid_amount)+' 元 | '+statusBadge+' | '+fmtDate(p.due_date)+' | '+esc(p.category||'--')+' | ';" + "h+='
暂无收付款记录