diff --git a/yuthon_account_report/controllers/controllers.py b/yuthon_account_report/controllers/controllers.py index b7e52e004..233da80cb 100644 --- a/yuthon_account_report/controllers/controllers.py +++ b/yuthon_account_report/controllers/controllers.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from odoo import http from odoo.http import request -import json +from odoo.exceptions import ValidationError +import datetime class Statement(http.Controller): @@ -29,10 +30,125 @@ class Statement(http.Controller): {'id': 203, 'name': "增幅", 'fieldType': "%"}, {'id': 204, 'name': "说明"} ] + }, + { + 'id': 3, + 'groupName': "物管公司", + 'items': [ + {'id': 201, 'name': "本期数", 'fieldType': "万元"}, + {'id': 202, 'name': "上年同期", 'fieldType': "万元"}, + {'id': 203, 'name': "增幅", 'fieldType': "%"}, + {'id': 204, 'name': "说明"} + ] + }, + { + 'id': 4, + 'groupName': "粮储公司", + 'items': [ + {'id': 201, 'name': "本期数", 'fieldType': "万元"}, + {'id': 202, 'name': "上年同期", 'fieldType': "万元"}, + {'id': 203, 'name': "增幅", 'fieldType': "%"}, + {'id': 204, 'name': "说明"} + ] } ] return companyGroups + @http.route('/get/account/project', auth='user', type='json', methods=['POST']) + def getAccountProject(self, **kw): + data = kw.get('data', '') + values = { + '101': "10000.00", + '102': "2000.00", + '103': "1500.00", + '104': "说明1", + '201': "8000.00", + '202': "1000.00", + '203': "800.00", + '204': "说明2" + } + rawRows = [] + cons = request.env['sheet.collection.setting'].search([]) + for con in cons: + result = con.check_today() + if isinstance(result, str): + raise ValidationError(result) + else: + if result: + one = { + 'id': con.sequence, + 'name': con.name, + 'values': values + } + rawRows.append(one) + rawRows.sort(key=lambda x: int(x['id'])) + return rawRows + + @http.route('/financial/single/get/data', type='json', auth='user', methods=['POST']) + def get_financial_data(self, filters=None, **kwargs): + """获取财务数据""" + try: + # 解析筛选条件 + date = filters.get('date', + datetime.date.today().isoformat()) if filters else datetime.date.today().isoformat() + company = filters.get('company', '') + department = filters.get('department', '') + + data = { + 'headers': [ + {'id': 1, 'title': "去年底", 'subtitle': ""}, + {'id': 2, 'title': "本年当月", 'subtitle': ""}, + {'id': 3, 'title': "去年同月", 'subtitle': ""}, + {'id': 4, 'title': "同比增长", 'subtitle': "%"}, + {'id': 5, 'title': "说明", 'subtitle': ""}, + {'id': 6, 'title': "天河公司", 'subtitle': ""}, + {'id': 7, 'title': "天河物管", 'subtitle': ""}, + {'id': 8, 'title': "天河粮储", 'subtitle': ""}, + ], + 'filters': { + 'date': date, + 'company': company, + 'department': department + } + } + + # 这里应该从数据库中获取实际数据 + values = {'1': 100, '2': 200, '3': 300, '4': 400, '5': 500, '6': 600, '7': 700, '8': 800} + # 暂时返回演示数据 + cons = request.env['summary.table.setting'].search([]) + rows = [] + for con in cons: + result = con.check_today() + if isinstance(result, str): + raise ValidationError(result) + else: + if result: + one = { + 'id': con.sequence, + 'name': con.name, + 'values': values + } + if ':' in con.name or ':' in con.name: + one['indent'] = 1 + elif '、' in con.name: + one['indent'] = 0 + else: + one['indent'] = 2 + rows.append(one) + rows.sort(key=lambda x: int(x['id'])) + + data['rows'] = rows + + return data + + except Exception as e: + + return { + 'headers': [], + 'rows': [] + } + + # @http.route('/statement/statement/objects', auth='public') # def list(self, **kw): # return http.request.render('statement.listing', { diff --git a/yuthon_account_report/models/table_setting.py b/yuthon_account_report/models/table_setting.py index 07f8b9c62..448607ad3 100644 --- a/yuthon_account_report/models/table_setting.py +++ b/yuthon_account_report/models/table_setting.py @@ -48,6 +48,19 @@ class SheetCollectionSetting(models.Model): 'context': {'default_financial_ids': collection_ids.ids} } + def check_today(self): + self.ensure_one() + today = fields.Date.today() + if self.start_date and self.end_date: + return self.start_date <= today <= self.end_date + elif self.start_date and not self.end_date: + return self.start_date <= today + elif not self.start_date and self.end_date: + return today <= self.end_date + else: + return '缺少参数' + + class SummaryTableSetting(models.Model): _name = 'summary.table.setting' _description = '信息汇总表项目配置' @@ -92,3 +105,15 @@ class SummaryTableSetting(models.Model): 'target': 'new', 'context': {'default_information_ids': table_ids.ids} } + + def check_today(self): + self.ensure_one() + today = fields.Date.today() + if self.start_date and self.end_date: + return self.start_date <= today <= self.end_date + elif self.start_date and not self.end_date: + return self.start_date <= today + elif not self.start_date and self.end_date: + return today <= self.end_date + else: + return '缺少参数' diff --git a/yuthon_account_report/static/src/css/financial.css b/yuthon_account_report/static/src/css/financial.css index 477e6e5d8..cf575c7c0 100644 --- a/yuthon_account_report/static/src/css/financial.css +++ b/yuthon_account_report/static/src/css/financial.css @@ -1,7 +1,3 @@ -/** - * Financial Page Component Styles - * 财务页面组件样式 - 独立CSS文件,使用.financial-container命名空间避免污染 - */ /* 主容器 */ .financial-container { @@ -19,27 +15,35 @@ border: 1px solid #dee2e6; } -/* 固定表头 */ .financial-container .sticky-header th { position: sticky; top: 0; background: white; - z-index: 100; + z-index: 90; /* 降低z-index */ box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.1); } -/* 固定第一列 */ .financial-container .sticky-column { position: sticky; left: 0; background: white; - z-index: 99; + z-index: 100; /* 提高z-index */ box-shadow: 2px 0 2px -1px rgba(0, 0, 0, 0.1); min-width: 200px; max-width: 300px; } -/* 表格样式 */ +/* 对角线表头特殊处理 - 最高优先级 */ +.financial-container .diagonal-header { + z-index: 110 !important; /* 最高z-index */ + position: sticky; + left: 0; + top: 0; + background: #f8f9fa !important; + padding: 0 !important; + width: 200px; +} + .financial-container .financial-table { margin: 0; border-collapse: separate; @@ -59,21 +63,13 @@ text-overflow: ellipsis; } -/* 对角线表头 - 修正方向:左上到右下,公司在上,项目在下 */ -.financial-container .diagonal-header { - position: relative; - text-align: center; - padding: 0 !important; - width: 200px; - background: #f8f9fa !important; -} - .financial-container .diagonal-text-container { position: relative; width: 100%; height: 100%; min-height: 80px; padding: 8px; + z-index: 1; } .financial-container .diagonal-line { @@ -82,7 +78,6 @@ left: 0; width: 100%; height: 100%; - /* 修正:左上到右下(from top-left to bottom-right) */ background: linear-gradient(to bottom left, transparent calc(50% - 1px), #333 calc(50% - 1px), @@ -113,7 +108,6 @@ text-align: left; } -/* 表头样式 */ .financial-container .group-header { background: linear-gradient(to bottom, #4e73df, #224abe) !important; color: white !important; @@ -121,6 +115,7 @@ text-transform: uppercase; font-size: 11px; min-width: 80px; + z-index: 90; /* 确保不会超过对角线表头 */ } .financial-container .item-header { @@ -135,7 +130,6 @@ border-right: 2px solid #1a237e !important; } -/* 表格内容样式 */ .financial-container .project-cell { background: #f8f9fa !important; font-weight: 600; @@ -155,7 +149,6 @@ background: #f0f8ff !important; } -/* 表头标题样式 */ .financial-container .group-title { padding: 5px; text-align: center; @@ -179,7 +172,6 @@ font-size: 12px; } -/* 斑马纹效果 */ .financial-container .financial-table tbody tr:nth-child(even) { background-color: #f9f9f9; } @@ -189,7 +181,7 @@ transition: background-color 0.2s; } -/* 加载状态 */ + .financial-container .loading-overlay { position: fixed; top: 0; @@ -212,14 +204,12 @@ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2); } -/* 空状态 */ .financial-container .empty-state { padding: 40px; color: #6c757d; text-align: center; } -/* 响应式调整 */ @media (max-width: 768px) { .financial-container { padding: 10px; @@ -263,7 +253,6 @@ } } -/* 合计行特殊样式 */ .financial-container .financial-table tbody tr:last-child { background: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%) !important; font-weight: 700; @@ -273,7 +262,6 @@ background: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%) !important; } -/* 预算行特殊样式 */ .financial-container .financial-table tbody tr:nth-last-child(2) { background: linear-gradient(to right, #d4fc79 0%, #96e6a1 100%) !important; } @@ -282,7 +270,6 @@ background: linear-gradient(to right, #d4fc79 0%, #96e6a1 100%) !important; } -/* 滚动条样式 */ .financial-container .table-responsive-container::-webkit-scrollbar { width: 10px; height: 10px; @@ -302,7 +289,6 @@ background: #555; } -/* 卡片样式优化 */ .financial-container .card { border: none; border-radius: 10px; @@ -321,7 +307,6 @@ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; } -/* 按钮样式优化 */ .financial-container .btn-sm { padding: 4px 10px; font-size: 12px; @@ -332,7 +317,6 @@ border: none; } -/* 筛选区域优化 */ .financial-container .form-label { font-weight: 600; margin-bottom: 3px; @@ -351,7 +335,6 @@ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); } -/* 信息行样式 */ .financial-container .bg-light { background-color: #f8f9fa !important; } @@ -360,7 +343,6 @@ border-bottom: 1px solid #dee2e6 !important; } -/* 工具按钮组 */ .financial-container .btn-group { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } @@ -374,7 +356,6 @@ background-color: #f8f9fa; } -/* 图标样式 */ .financial-container .fa { font-size: 14px; } @@ -383,7 +364,6 @@ font-size: 18px; } -/* 自适应调整 */ @media (min-width: 1200px) { .financial-container .sticky-column { min-width: 250px; @@ -433,9 +413,7 @@ } } -/* 确保不污染其他样式 - 严格的命名空间 */ .financial-container *:not(.financial-container) { - /* 重置所有非金融容器内的样式影响 */ box-sizing: border-box; } @@ -445,7 +423,6 @@ font-family: inherit; } -/* 高度自适应 */ .financial-container .row { margin-left: 0; margin-right: 0; diff --git a/yuthon_account_report/static/src/css/information.css b/yuthon_account_report/static/src/css/information.css new file mode 100644 index 000000000..21e4d2a1d --- /dev/null +++ b/yuthon_account_report/static/src/css/information.css @@ -0,0 +1,363 @@ +/* 财务单一报表专用样式 - 独立作用域 */ +.financial-single-container * { + box-sizing: border-box; +} + +/* 表格容器 */ +.financial-single-container .table-responsive-container { + overflow-x: auto; + max-height: 600px; + overflow-y: auto; + position: relative; +} + +/* 表格样式 - 使用更具体的选择器 */ +.financial-single-container .financial-single-table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + margin-bottom: 0; +} + +.financial-single-container .financial-single-table th, +.financial-single-container .financial-single-table td { + border: 1px solid #dee2e6; + padding: 8px 12px; + vertical-align: middle; + font-size: 13px; +} + +/* 固定表头 */ +.financial-single-container .sticky-header { + position: sticky; + top: 0; + z-index: 10; +} + +/* 固定第一列 */ +.financial-single-container .sticky-column { + position: sticky; + left: 0; + background-color: white; + z-index: 5; + border-right: 2px solid #dee2e6 !important; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05); +} + +.financial-single-container .project-header { + min-width: 250px; + background-color: #f8f9fa !important; + font-weight: 600; + position: relative; + height: 80px; +} + +.financial-single-container .project-cell { + min-width: 250px; + background-color: white; + font-weight: normal; +} + +/* 对角线表头样式 - 修复斜线 */ +.financial-single-container .diagonal-header { + background-color: #f8f9fa; + border-bottom: 2px solid #dee2e6; +} + +.financial-single-container .diagonal-text-container { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.financial-single-container .diagonal-line { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(to bottom left, + transparent calc(50% - 1px), + #333 calc(50% - 1px), + #333 calc(50% + 1px), + transparent calc(50% + 1px)); + z-index: 1; +} + +.financial-single-container .diagonal-company { + position: absolute; + top: 10px; + right: 25px; + font-size: 11px; + color: #666; + transform: translateX(50%); +} + +.financial-single-container .diagonal-project { + position: absolute; + bottom: 10px; + left: 10px; + font-size: 11px; + color: #666; + transform: translateX(-50%); +} + +/* 表头样式 */ +.financial-single-container .single-header { + min-width: 120px; + text-align: center; + font-weight: 600; + color: white !important; + border-bottom: 2px solid #dee2e6; +} + +.financial-single-container .header-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; +} + +.financial-single-container .header-title { + font-size: 14px; + font-weight: bold; + margin-bottom: 2px; +} + +.financial-single-container .header-subtitle { + font-size: 11px; + opacity: 0.9; + font-weight: normal; +} + +/* 数据行样式 */ +.financial-single-container .main-row { + font-weight: 600; + background-color: #f8f9fa !important; +} + +.financial-single-container .sub-row-1 { + font-weight: 500; + background-color: #fff !important; +} + +.financial-single-container .sub-row-2 { + font-weight: 400; + background-color: #fff !important; + color: #666; +} + +.financial-single-container .sub-row-1 .project-name { + padding-left: 20px; + position: relative; +} + +.financial-single-container .sub-row-1 .project-name::before { + content: ""; + position: absolute; + left: 8px; + top: 50%; + transform: translateY(-50%); + width: 6px; + height: 6px; + background-color: #666; + border-radius: 50%; +} + +.financial-single-container .sub-row-2 .project-name { + padding-left: 40px; + position: relative; +} + +.financial-single-container .sub-row-2 .project-name::before { + content: ""; + position: absolute; + left: 28px; + top: 50%; + transform: translateY(-50%); + width: 4px; + height: 4px; + background-color: #999; + border-radius: 50%; +} + +.financial-single-container .data-cell { + min-width: 100px; + text-align: center !important; +} + +/* 卡片标题样式 - 白色字体 */ +.financial-single-container .card-header.bg-primary { + background-color: #667eea !important; + border-bottom: 1px solid #5569d6; +} + +.financial-single-container .card-header.bg-primary .card-title { + color: white; + font-size: 18px; + font-weight: 600; +} + +.financial-single-container .card-header.bg-primary .card-title small { + color: rgba(255, 255, 255, 0.85) !important; + font-weight: 400; + font-size: 14px; +} + +.financial-single-container .card-header.bg-primary .card-title i { + color: white !important; +} + +.financial-single-container .card-header.bg-primary .btn-group .btn-light { + background-color: rgba(255, 255, 255, 0.9) !important; + border-color: rgba(255, 255, 255, 0.2); + color: #667eea !important; +} + +.financial-single-container .card-header.bg-primary .btn-group .btn-light:hover { + background-color: white !important; +} + +/* 筛选区域样式 */ +.financial-single-container .filter-card { + border: 1px solid #e3e6f0; + border-radius: 0.35rem; +} + +.financial-single-container .form-label { + font-size: 13px; + font-weight: 600; + margin-bottom: 4px; + color: #5a5c69; +} + +.financial-single-container .form-control-sm, +.financial-single-container .form-select-sm { + font-size: 13px; + padding: 4px 8px; + height: 32px; +} + +/* 按钮样式 */ +.financial-single-container .btn-sm { + padding: 4px 12px; + font-size: 13px; + height: 32px; +} + +.financial-single-container .btn-primary { + background-color: #667eea; + border-color: #667eea; +} + +.financial-single-container .btn-primary:hover { + background-color: #5a6fd8; + border-color: #5a6fd8; +} + +.financial-single-container .btn-outline-secondary { + color: #858796; + border-color: #d1d3e2; +} + +.financial-single-container .btn-outline-secondary:hover { + background-color: #eaecf4; + border-color: #d1d3e2; + color: #5a5c69; +} + +/* 加载状态 */ +.financial-single-container .loading-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.85); + display: flex; + justify-content: center; + align-items: center; + z-index: 9999; +} + +.financial-single-container .spinner-container { + text-align: center; + background: white; + padding: 30px; + border-radius: 8px; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); + border: 1px solid #e3e6f0; +} + +/* 空状态 */ +.financial-single-container .empty-state { + padding: 40px 0; + color: #6c757d; +} + +.financial-single-container .empty-state i { + color: #d1d3e2; +} + +/* 卡片脚注 */ +.financial-single-container .card-footer { + background-color: #f8f9fa !important; + border-top: 1px solid #e3e6f0; + font-size: 12px; +} + +.financial-single-container .card-footer .text-muted { + color: #858796 !important; +} + +/* 响应式调整 */ +@media (max-width: 768px) { + .financial-single-container .project-header, + .financial-single-container .project-cell { + min-width: 200px; + } + + .financial-single-container .single-header { + min-width: 100px; + } + + .financial-single-container .card-title { + font-size: 16px; + } + + .financial-single-container .card-title small { + font-size: 12px; + } +} + +/* 打印样式 */ +@media print { + .financial-single-container .card-header.bg-primary { + background-color: #667eea !important; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + + .financial-single-container .card-title, + .financial-single-container .card-title small, + .financial-single-container .card-title i { + color: white !important; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + + .financial-single-container .sticky-column { + position: static; + box-shadow: none; + } + + .financial-single-container .table-responsive-container { + overflow: visible; + max-height: none; + } +} diff --git a/yuthon_account_report/static/src/js/financial.js b/yuthon_account_report/static/src/js/financial.js index d527ca43e..e0c1dc34e 100644 --- a/yuthon_account_report/static/src/js/financial.js +++ b/yuthon_account_report/static/src/js/financial.js @@ -1,9 +1,9 @@ /** @odoo-module **/ -import { registry } from "@web/core/registry"; -import { useService } from "@web/core/utils/hooks"; +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; -const { Component, useState, onWillStart, onMounted } = owl; +const {Component, useState, onWillStart, onMounted} = owl; class FinancialPage extends Component { setup() { @@ -35,21 +35,65 @@ class FinancialPage extends Component { employeeName: "所有员工" }, pageTitle: "各公司主要财务数据", - setting: { type: 'default' }, + setting: {type: 'default'}, loading: false, demo: { - companyGroups : [ - { - 'id': 1, - 'groupName': "天河投资", - 'items': [ - {'id': 101, 'name': "本期数", 'fieldType': "万元"}, - {'id': 102, 'name': "上年同期", 'fieldType': "万元"}, - {'id': 103, 'name': "增幅", 'fieldType': "%"}, - {'id': 104, 'name': "说明"} - ] - } + companyGroups: [ + { + 'id': 1, + 'groupName': "天河投资", + 'items': [ + {'id': 101, 'name': "本期数", 'fieldType': "万元"}, + {'id': 102, 'name': "上年同期", 'fieldType': "万元"}, + {'id': 103, 'name': "增幅", 'fieldType': "%"}, + {'id': 104, 'name': "说明"} ] + } + ], + rawRows: [ + { + id: 1, + name: '资产总额', + values: { + 101: "10000.00", + 102: "2000.00", + 103: "1500.00", + 104: "说明1", + 201: "8000.00", + 202: "1000.00", + 203: "800.00", + 204: "说明2" + } + }, + { + id: 2, + name: '本年营业收入', + values: { + 101: "5000.00", + 102: "1200.00", + 103: "800.00", + 104: "说明3", + 201: "4000.00", + 202: "900.00", + 203: "600.00", + 204: "说明4" + } + }, + { + id: 3, + name: '本年利润总额', + values: { + 101: "3000.00", + 102: "800.00", + 103: "500.00", + 104: "说明5", + 201: "2000.00", + 202: "600.00", + 203: "400.00", + 204: "说明6" + } + } + ] } }); @@ -75,7 +119,7 @@ class FinancialPage extends Component { 'sheet.collection.setting', [], ['id', 'name', 'type'], - { limit: 1 } + {limit: 1} ); if (settings.length > 0) { @@ -92,33 +136,35 @@ class FinancialPage extends Component { async loadDefaultData() { this.state.pageTitle = "各公司主要财务数据"; - this.state.setting = { type: 'default' }; + this.state.setting = {type: 'default'}; try { // 通过RPC调用后端接口 const companyGroups = await this.rpc('/get/account/title'); - if (companyGroups && companyGroups.length > 0) { + const rawRows = await this.rpc('/get/account/project'); + + if (companyGroups && rawRows && companyGroups.length > 0 && rawRows.length > 0) { // 固定分组(合计和预算) const fixedGroups = [ { id: this.FIXED_GROUP_IDS.TOTAL, groupName: "合计", items: [ - { id: 1001, name: "本期数", fieldType: "万元" }, - { id: 1002, name: "上年同期", fieldType: "万元" }, - { id: 1003, name: "增幅", fieldType: "%" }, - { id: 1004, name: "说明" } + {id: 10001, name: "本期数", fieldType: "万元"}, + {id: 10002, name: "上年同期", fieldType: "万元"}, + {id: 10003, name: "增幅", fieldType: "%"}, + {id: 10004, name: "说明"} ] }, { id: this.FIXED_GROUP_IDS.BUDGET, groupName: "本年度预算", items: [ - { id: 2001, name: "预测财局下达目标", fieldType: "万元" }, - { id: 2002, name: "完成率", fieldType: "%" }, - { id: 2003, name: "集团目标", fieldType: "%" }, - { id: 2004, name: "完成率", fieldType: "%" } + {id: 20001, name: "预测财局下达目标", fieldType: "万元"}, + {id: 20002, name: "完成率", fieldType: "%"}, + {id: 20003, name: "集团目标", fieldType: "%"}, + {id: 20004, name: "完成率", fieldType: "%"} ] } ]; @@ -126,24 +172,6 @@ class FinancialPage extends Component { // 合并分组,确保固定分组在最后 this.state.tableData.displayHeaders = [...companyGroups, ...fixedGroups]; - // 原始行数据(不包含合计的计算) - const rawRows = [ - { - id: 1, - name: '资产总额', - values: { - 101: "10000.00", - 102: "2000.00", - 103: "1500.00", - 104: "说明1", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明2" - } - }, - ]; - // 计算并添加合计数据 const rowsWithTotals = this.calculateTotals(rawRows, companyGroups); this.state.tableData.rows = rowsWithTotals; @@ -168,168 +196,27 @@ class FinancialPage extends Component { id: this.FIXED_GROUP_IDS.TOTAL, groupName: "合计", items: [ - { id: 1001, name: "本期数", fieldType: "万元" }, - { id: 1002, name: "上年同期", fieldType: "万元" }, - { id: 1003, name: "增幅", fieldType: "%" }, - { id: 1004, name: "说明" } + {id: 10001, name: "本期数", fieldType: "万元"}, + {id: 10002, name: "上年同期", fieldType: "万元"}, + {id: 10003, name: "增幅", fieldType: "%"}, + {id: 10004, name: "说明"} ] }, { id: this.FIXED_GROUP_IDS.BUDGET, groupName: "本年度预算", items: [ - { id: 2001, name: "预测财局下达目标", fieldType: "万元" }, - { id: 2002, name: "完成率", fieldType: "%" }, - { id: 2003, name: "集团目标", fieldType: "%" }, - { id: 2004, name: "完成率", fieldType: "%" } + {id: 20001, name: "预测财局下达目标", fieldType: "万元"}, + {id: 20002, name: "完成率", fieldType: "%"}, + {id: 20003, name: "集团目标", fieldType: "%"}, + {id: 20004, name: "完成率", fieldType: "%"} ] } ]; this.state.tableData.displayHeaders = [...companyGroups, ...fixedGroups]; - const rawRows = [ - { - id: 1, - name: '资产总额', - values: { - 101: "10000.00", - 102: "2000.00", - 103: "1500.00", - 104: "说明1", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明2" - } - }, - { - id: 2, - name: '本年营业收入', - values: { - 101: "5000.00", - 102: "1200.00", - 103: "800.00", - 104: "说明3", - 201: "4000.00", - 202: "900.00", - 203: "600.00", - 204: "说明4" - } - }, - { - id: 3, - name: '本年利润总额', - values: { - 101: "3000.00", - 102: "800.00", - 103: "500.00", - 104: "说明5", - 201: "2000.00", - 202: "600.00", - 203: "400.00", - 204: "说明6" - } - }, - { - id: 4, - name: '(自有物业)可出租面积(万平方米)', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明7", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明8" - } - }, - { - id: 5, - name: '(自有物业)已出租面积(万平方米)', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明9", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明10" - } - }, - { - id: 6, - name: '自有物业出租率', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明11", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明12" - } - }, - { - id: 7, - name: '(代管物业)可出租面积(万平方米)', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明13", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明14" - } - }, - { - id: 8, - name: '(代管物业)已出租面积(万平方米)', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明15", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明16" - } - }, - { - id: 9, - name: '代管物业出租率', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明17", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明18" - } - }, - { - id: 10, - name: '整体出租率', - values: { - 101: "8000.00", - 102: "1000.00", - 103: "800.00", - 104: "说明19", - 201: "8000.00", - 202: "1000.00", - 203: "800.00", - 204: "说明20" - } - } - ]; + const rawRows = this.state.demo.rawRows const rowsWithTotals = this.calculateTotals(rawRows, companyGroups); this.state.tableData.rows = rowsWithTotals; @@ -346,7 +233,7 @@ class FinancialPage extends Component { const newRow = { id: row.id, name: row.name, - values: { ...row.values } + values: {...row.values} }; // 提取每个公司的本期数ID @@ -390,14 +277,14 @@ class FinancialPage extends Component { if (totalLastYear !== 0) { increaseRate = ((totalCurrentPeriod - totalLastYear) / totalLastYear * 100).toFixed(2); } - newRow.values[1003] = increaseRate; - newRow.values[1004] = "合计说明"; // 合计说明 + newRow.values[10003] = increaseRate; + newRow.values[10004] = "合计说明"; // 合计说明 // 预算相关数据可以留空或设置默认值 - newRow.values[2001] = ""; // 预测财局下达目标 - newRow.values[2002] = ""; // 完成率 - newRow.values[2003] = ""; // 集团目标 - newRow.values[2004] = ""; // 完成率 + newRow.values[20001] = ""; // 预测财局下达目标 + newRow.values[20002] = ""; // 完成率 + newRow.values[20003] = ""; // 集团目标 + newRow.values[20004] = ""; // 完成率 return newRow; }); @@ -411,21 +298,21 @@ class FinancialPage extends Component { 'sheet.collection.setting.header', [['setting_id', '=', settingId]], ['id', 'sequence', 'group_name', 'vertical_header_name'], - { order: 'sequence' } + {order: 'sequence'} ); const headerItems = await this.orm.searchRead( 'sheet.collection.setting.header.item', [['header_id.setting_id', '=', settingId]], ['id', 'header_id', 'sequence', 'name', 'field_type'], - { order: 'sequence' } + {order: 'sequence'} ); const dataRows = await this.orm.searchRead( 'sheet.collection.setting.data', [['setting_id', '=', settingId]], ['id', 'sequence', 'name'], - { order: 'sequence' } + {order: 'sequence'} ); const dataValues = await this.orm.searchRead( @@ -518,20 +405,20 @@ class FinancialPage extends Component { id: this.FIXED_GROUP_IDS.TOTAL, groupName: "合计", items: [ - { id: 1001, name: "本期数", fieldType: "万元" }, - { id: 1002, name: "上年同期", fieldType: "万元" }, - { id: 1003, name: "增幅", fieldType: "%" }, - { id: 1004, name: "说明" } + {id: 10001, name: "本期数", fieldType: "万元"}, + {id: 10002, name: "上年同期", fieldType: "万元"}, + {id: 10003, name: "增幅", fieldType: "%"}, + {id: 10004, name: "说明"} ] }, { id: this.FIXED_GROUP_IDS.BUDGET, groupName: "本年度预算", items: [ - { id: 2001, name: "预测财局下达目标", fieldType: "万元" }, - { id: 2002, name: "完成率", fieldType: "%" }, - { id: 2003, name: "集团目标", fieldType: "%" }, - { id: 2004, name: "完成率", fieldType: "%" } + {id: 20001, name: "预测财局下达目标", fieldType: "万元"}, + {id: 20002, name: "完成率", fieldType: "%"}, + {id: 20003, name: "集团目标", fieldType: "%"}, + {id: 20004, name: "完成率", fieldType: "%"} ] } ]); diff --git a/yuthon_account_report/static/src/js/information.js b/yuthon_account_report/static/src/js/information.js new file mode 100644 index 000000000..aa8f3a4c3 --- /dev/null +++ b/yuthon_account_report/static/src/js/information.js @@ -0,0 +1,317 @@ +/** @odoo-module **/ + +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; + +const {Component, useState, onWillStart, useRef, onMounted} = owl; + +export class FinancialSinglePage extends Component { + setup() { + super.setup(); + + this.orm = useService("orm"); + this.action = useService("action"); + this.rpc = useService("rpc"); + this.notification = useService("notification"); + + // 初始化状态 + this.state = useState({ + filters: { + date: this.getCurrentDate(), + company: "", + department: "", + }, + tableData: { + headers: [], + rows: [], + }, + displayInfo: { + reportDate: this.getCurrentDate(), + companyName: "所有公司", + departmentName: "所有部门" + }, + pageTitle: "信息汇总表", + loading: false, + // 演示数据 + demoData: { + headers: [ + {id: 1, title: "去年底", subtitle: ""}, + {id: 2, title: "本年当月", subtitle: ""}, + {id: 3, title: "去年同月", subtitle: ""}, + {id: 4, title: "同比增长", subtitle: "%"}, + {id: 5, title: "说明", subtitle: ""}, + {id: 6, title: "天河公司", subtitle: ""}, + {id: 7, title: "天河物管", subtitle: ""}, + {id: 8, title: "天河粮储", subtitle: ""}, + ], + rows: [ + { + id: 1, + name: '一、总资产', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + }, + { + id: 2, + name: '二、总负债', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + }, + { + id: 3, + name: '其中:有息负债', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 1 + }, + { + id: 4, + name: '利息支出', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 1 + }, + { + id: 5, + name: '三、净资产', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + }, + { + id: 6, + name: '四、经营收入(累计当年)', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + }, + { + id: 7, + name: '其中:物业租赁收入', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 1 + }, + { + id: 8, + name: '储备粮轮换收入', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 2 + }, + { + id: 9, + name: '利息收入', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 2 + }, + { + id: 10, + name: '其他业务收入', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 2 + }, + { + id: 11, + name: '五、利润总额(累计当年)', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + }, + { + id: 12, + name: '六、净利润(累计当年)', + values: {1: "", 2: "", 3: "", 4: "", 5: "", 6: "", 7: "", 8: ""}, + indent: 0 + } + ] + } + }); + + // 引用 + this.tableRef = useRef("table"); + + onWillStart(async () => { + await this.loadData(); + }); + + onMounted(() => { + }); + } + + getCurrentDate() { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const day = String(today.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; + } + + async loadData() { + try { + this.state.loading = true; + + // 先尝试从后端获取数据 + await this.loadFromBackend(); + + } catch (error) { + console.error("从后端加载数据失败:", error); + // 如果后端加载失败,使用演示数据 + await this.loadDemoData(); + } finally { + this.state.loading = false; + } + } + + async loadFromBackend() { + try { + // 这里调用后端RPC接口 + const data = await this.rpc('/financial/single/get/data', { + filters: this.state.filters + }); + + if (data && data.headers && data.rows) { + this.state.tableData.headers = data.headers; + this.state.tableData.rows = data.rows; + this.notification.add("数据加载成功", { type: "success" }); + } else { + // 如果后端返回的数据格式不正确,使用演示数据 + throw new Error("数据格式不正确"); + } + } catch (error) { + console.warn("后端接口不可用,使用演示数据:", error); + await this.loadDemoData(); + } + } + + async loadDemoData() { + // 使用演示数据 + this.state.tableData.headers = this.state.demoData.headers; + this.state.tableData.rows = this.state.demoData.rows; + + // 填充一些示例数据 + this.fillExampleData(); + + this.notification.add("使用演示数据", { type: "info" }); + } + + fillExampleData() { + // 填充一些示例数据以便预览 + const rows = this.state.tableData.rows; + + // 一、总资产 + rows[0].values = {1: "12,500.00", 2: "15,000.00", 3: "11,800.00", 4: "27.12", 5: "较去年增长", 6: "8,000.00", 7: "4,000.00", 8: "3,000.00"}; + + // 二、总负债 + rows[1].values = {1: "7,500.00", 2: "8,200.00", 3: "6,800.00", 4: "20.59", 5: "负债率控制在合理范围", 6: "4,500.00", 7: "2,500.00", 8: "1,200.00"}; + + // 其中:有息负债 + rows[2].values = {1: "3,200.00", 2: "3,500.00", 3: "2,800.00", 4: "25.00", 5: "银行贷款为主", 6: "2,000.00", 7: "1,000.00", 8: "500.00"}; + + // 利息支出 + rows[3].values = {1: "85.00", 2: "92.50", 3: "78.20", 4: "18.29", 5: "利率有所下降", 6: "50.00", 7: "30.00", 8: "12.50"}; + + // 三、净资产 + rows[4].values = {1: "5,000.00", 2: "6,800.00", 3: "5,000.00", 4: "36.00", 5: "净资产稳步增长", 6: "3,500.00", 7: "1,500.00", 8: "1,800.00"}; + + // 四、经营收入(累计当年) + rows[5].values = {1: "8,200.00", 2: "9,500.00", 3: "7,500.00", 4: "26.67", 5: "收入稳步增长", 6: "5,200.00", 7: "2,800.00", 8: "1,500.00"}; + + // 其中:物业租赁收入 + rows[6].values = {1: "3,500.00", 2: "4,200.00", 3: "3,200.00", 4: "31.25", 5: "出租率提升", 6: "2,500.00", 7: "1,200.00", 8: "500.00"}; + + // 储备粮轮换收入 + rows[7].values = {1: "2,800.00", 2: "3,000.00", 3: "2,500.00", 4: "20.00", 5: "轮换计划完成", 6: "", 7: "", 8: "3,000.00"}; + + // 利息收入 + rows[8].values = {1: "350.00", 2: "420.00", 3: "300.00", 4: "40.00", 5: "存款利息", 6: "200.00", 7: "120.00", 8: "100.00"}; + + // 其他业务收入 + rows[9].values = {1: "1,550.00", 2: "1,880.00", 3: "1,500.00", 4: "25.33", 5: "多元化经营", 6: "500.00", 7: "1,000.00", 8: "380.00"}; + + // 五、利润总额(累计当年) + rows[10].values = {1: "1,200.00", 2: "1,650.00", 3: "1,050.00", 4: "57.14", 5: "利润增长显著", 6: "900.00", 7: "450.00", 8: "300.00"}; + + // 六、净利润(累计当年) + rows[11].values = {1: "850.00", 2: "1,180.00", 3: "720.00", 4: "63.89", 5: "净利润率提升", 6: "650.00", 7: "320.00", 8: "210.00"}; + + // 七、经管物业面积 + rows[12].values = {1: "120,000", 2: "150,000", 3: "115,000", 4: "30.43", 5: "平方米", 6: "80,000", 7: "50,000", 8: "20,000"}; + + } + + // 查询按钮点击事件 + async onSearch() { + this.state.displayInfo.reportDate = this.state.filters.date || this.getCurrentDate(); + this.state.displayInfo.companyName = this.state.filters.company || "所有公司"; + this.state.displayInfo.departmentName = this.state.filters.department || "所有部门"; + + await this.loadData(); + } + + // 重置筛选条件 + onReset() { + this.state.filters = { + date: this.getCurrentDate(), + company: "", + department: "", + }; + this.onSearch(); + } + + /** + * 导出数据为Excel + */ + onExport() { + this.notification.add("导出功能正在开发中...", { type: "info" }); + } + + /** + * 打印报表 + */ + onPrint() { + window.print(); + } + + /** + * 刷新数据 + */ + async onRefresh() { + await this.loadData(); + } + + /** + * 获取表头颜色 + */ + getHeaderColor(index) { + const colors = [ + "#667eea", // 去年底 - 蓝色 + "#f6ad55", // 本年当月 - 橙色 + "#68d391", // 去年同月 - 绿色 + "#fc8181", // 同比增长 - 红色 + "#a0aec0", // 说明 - 灰色 + "#4c51bf", // 天河公司 - 深蓝 + "#38a169", // 天河物管 - 绿色 + "#d69e2e", // 天河粮储 - 金色 + ]; + return colors[index % colors.length]; + } + + /** + * 获取行样式类 + */ + getRowClass(row) { + if (row.indent === 0) return "main-row"; + if (row.indent === 1) return "sub-row-1"; + if (row.indent === 2) return "sub-row-2"; + return ""; + } + + /** + * 获取项目名称的缩进样式 + */ + getProjectIndentStyle(row) { + const basePadding = 15; // 基础缩进 + const indentSize = 20; // 每级缩进大小 + return `padding-left: ${basePadding + (row.indent * indentSize)}px;`; + } +} + +FinancialSinglePage.template = "statement.FinancialSingleComponent"; +FinancialSinglePage.components = {}; + +// 正确的注册方式 +registry.category("actions").add("financial_single_data_action", FinancialSinglePage); diff --git a/yuthon_account_report/static/src/xml/information.xml b/yuthon_account_report/static/src/xml/information.xml new file mode 100644 index 000000000..352bcfc0c --- /dev/null +++ b/yuthon_account_report/static/src/xml/information.xml @@ -0,0 +1,229 @@ + + + +
+ +
+
+
+
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+

+ + +

+
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
项目
+
时间(公司)
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+
+ +
+
+ +

暂无数据

+

请选择筛选条件后查询

+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+ 正在加载... +
+

数据加载中,请稍候...

+

正在获取最新的财务数据

+
+
+
+
+
diff --git a/yuthon_account_report/views/custom.xml b/yuthon_account_report/views/custom.xml index b2ce7dcb7..5eeb9804d 100644 --- a/yuthon_account_report/views/custom.xml +++ b/yuthon_account_report/views/custom.xml @@ -5,6 +5,12 @@ financial_data_action + + 信息汇总报表 + financial_single_data_action + + + diff --git a/yuthon_account_report/views/financial_sheet_collection_views.xml b/yuthon_account_report/views/financial_sheet_collection_views.xml index 202bab80e..2c49b4569 100644 --- a/yuthon_account_report/views/financial_sheet_collection_views.xml +++ b/yuthon_account_report/views/financial_sheet_collection_views.xml @@ -7,7 +7,6 @@ - > diff --git a/yuthon_account_report/views/information_summary_table_views.xml b/yuthon_account_report/views/information_summary_table_views.xml index fd039d505..44c9dc2cd 100644 --- a/yuthon_account_report/views/information_summary_table_views.xml +++ b/yuthon_account_report/views/information_summary_table_views.xml @@ -7,7 +7,6 @@ - > diff --git a/yuthon_work_brand/views/hr_menus.xml b/yuthon_work_brand/views/hr_menus.xml index dfa62abd3..6f1a6dd0c 100644 --- a/yuthon_work_brand/views/hr_menus.xml +++ b/yuthon_work_brand/views/hr_menus.xml @@ -810,7 +810,7 @@