| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- # Copyright (c) Opendatalab. All rights reserved.
- """
- 数据模型定义
- """
- from typing import List, Optional
- class WeatherData:
- """气象数据模型"""
- def __init__(self):
- self.monitorAt: str = ""
- self.weather: str = ""
- self.temp: str = ""
- self.humidity: str = ""
- self.windSpeed: str = ""
- self.windDirection: str = ""
- self._auto_filled_weather: bool = False
-
- def to_dict(self):
- return {
- "monitorAt": self.monitorAt,
- "weather": self.weather,
- "temp": self.temp,
- "humidity": self.humidity,
- "windSpeed": self.windSpeed,
- "windDirection": self.windDirection
- }
- class NoiseData:
- """噪声数据模型"""
- def __init__(self):
- self.code: str = ""
- self.address: str = ""
- self.source: str = ""
- self.dayMonitorAt: str = ""
- self.dayMonitorValue: str = ""
- self.dayMonitorBackgroundValue: str = ""
- self.nightMonitorAt: str = ""
- self.nightMonitorValue: str = ""
- self.nightMonitorBackgroundValue: str = ""
- self.remark: str = ""
-
- def to_dict(self):
- return {
- "code": self.code,
- "address": self.address,
- "source": self.source,
- "dayMonitorAt": self.dayMonitorAt,
- "dayMonitorValue": self.dayMonitorValue,
- "dayMonitorBackgroundValue": self.dayMonitorBackgroundValue,
- "nightMonitorAt": self.nightMonitorAt,
- "nightMonitorValue": self.nightMonitorValue,
- "nightMonitorBackgroundValue": self.nightMonitorBackgroundValue,
- "remark": self.remark
- }
- class OperationalCondition:
- """工况信息数据模型(旧格式)"""
- def __init__(self):
- self.monitorAt: str = "" # 检测时间
- self.project: str = "" # 项目名称
- self.name: str = "" # 名称,如1#主变
- self.voltage: str = "" # 电压范围
- self.current: str = "" # 电流范围
- self.activePower: str = "" # 有功功率
- self.reactivePower: str = "" # 无功功率
-
- def to_dict(self):
- return {
- "monitorAt": self.monitorAt,
- "project": self.project,
- "name": self.name,
- "voltage": self.voltage,
- "current": self.current,
- "activePower": self.activePower,
- "reactivePower": self.reactivePower
- }
- class OperationalConditionV2:
- """工况信息数据模型(新格式:表1检测工况)"""
- def __init__(self):
- self.monitorAt: str = "" # 检测时间
- self.project: str = "" # 项目名称
- self.name: str = "" # 名称,如500kV 江黄Ⅰ线
- self.maxVoltage: str = "" # 电压最大值
- self.minVoltage: str = "" # 电压最小值
- self.maxCurrent: str = "" # 电流最大值
- self.minCurrent: str = "" # 电流最小值
- self.maxActivePower: str = "" # 有功功率最大值
- self.minActivePower: str = "" # 有功功率最小值
- self.maxReactivePower: str = "" # 无功功率最大值
- self.minReactivePower: str = "" # 无功功率最小值
-
- def to_dict(self):
- return {
- "monitorAt": self.monitorAt,
- "project": self.project,
- "name": self.name,
- "maxVoltage": self.maxVoltage,
- "minVoltage": self.minVoltage,
- "maxCurrent": self.maxCurrent,
- "minCurrent": self.minCurrent,
- "maxActivePower": self.maxActivePower,
- "minActivePower": self.minActivePower,
- "maxReactivePower": self.maxReactivePower,
- "minReactivePower": self.minReactivePower
- }
- class NoiseDetectionRecord:
- """噪声检测记录数据模型"""
- def __init__(self):
- self.project: str = ""
- self.standardReferences: str = ""
- self.soundLevelMeterMode: str = ""
- self.soundCalibratorMode: str = ""
- self.calibrationValueBefore: str = ""
- self.calibrationValueAfter: str = ""
- self.weather: List[WeatherData] = []
- self.noise: List[NoiseData] = []
- self.operationalConditions: List[OperationalCondition] = []
-
- def to_dict(self):
- return {
- "project": self.project,
- "standardReferences": self.standardReferences,
- "soundLevelMeterMode": self.soundLevelMeterMode,
- "soundCalibratorMode": self.soundCalibratorMode,
- "calibrationValueBefore": self.calibrationValueBefore,
- "calibrationValueAfter": self.calibrationValueAfter,
- "weather": [w.to_dict() for w in self.weather],
- "noise": [n.to_dict() for n in self.noise],
- "operationalConditions": [oc.to_dict() for oc in self.operationalConditions]
- }
- class ElectromagneticWeatherData:
- """电磁检测气象数据模型"""
- def __init__(self):
- self.weather: str = ""
- self.temp: str = ""
- self.humidity: str = ""
- self.windSpeed: str = ""
- self.windDirection: str = ""
-
- def to_dict(self):
- return {
- "weather": self.weather,
- "temp": self.temp,
- "humidity": self.humidity,
- "windSpeed": self.windSpeed,
- "windDirection": self.windDirection
- }
- class ElectromagneticData:
- """电磁数据模型"""
- def __init__(self):
- self.code: str = ""
- self.address: str = ""
- self.height: str = ""
- self.monitorAt: str = ""
- self.powerFrequencyEFieldStrength1: str = ""
- self.powerFrequencyEFieldStrength2: str = ""
- self.powerFrequencyEFieldStrength3: str = ""
- self.powerFrequencyEFieldStrength4: str = ""
- self.powerFrequencyEFieldStrength5: str = ""
- self.avgPowerFrequencyEFieldStrength: str = ""
- self.powerFrequencyMagneticDensity1: str = ""
- self.powerFrequencyMagneticDensity2: str = ""
- self.powerFrequencyMagneticDensity3: str = ""
- self.powerFrequencyMagneticDensity4: str = ""
- self.powerFrequencyMagneticDensity5: str = ""
- self.avgPowerFrequencyMagneticDensity: str = ""
-
- def to_dict(self):
- return {
- "code": self.code,
- "address": self.address,
- "height": self.height,
- "monitorAt": self.monitorAt,
- "powerFrequencyEFieldStrength1": self.powerFrequencyEFieldStrength1,
- "powerFrequencyEFieldStrength2": self.powerFrequencyEFieldStrength2,
- "powerFrequencyEFieldStrength3": self.powerFrequencyEFieldStrength3,
- "powerFrequencyEFieldStrength4": self.powerFrequencyEFieldStrength4,
- "powerFrequencyEFieldStrength5": self.powerFrequencyEFieldStrength5,
- "avgPowerFrequencyEFieldStrength": self.avgPowerFrequencyEFieldStrength,
- "powerFrequencyMagneticDensity1": self.powerFrequencyMagneticDensity1,
- "powerFrequencyMagneticDensity2": self.powerFrequencyMagneticDensity2,
- "powerFrequencyMagneticDensity3": self.powerFrequencyMagneticDensity3,
- "powerFrequencyMagneticDensity4": self.powerFrequencyMagneticDensity4,
- "powerFrequencyMagneticDensity5": self.powerFrequencyMagneticDensity5,
- "avgPowerFrequencyMagneticDensity": self.avgPowerFrequencyMagneticDensity
- }
- class ElectromagneticDetectionRecord:
- """电磁检测记录数据模型"""
- def __init__(self):
- self.project: str = ""
- self.standardReferences: str = ""
- self.deviceName: str = ""
- self.deviceMode: str = ""
- self.deviceCode: str = ""
- self.monitorHeight: str = ""
- self.weather: ElectromagneticWeatherData = ElectromagneticWeatherData()
- self.electricMagnetic: List[ElectromagneticData] = []
-
- def to_dict(self):
- return {
- "project": self.project,
- "standardReferences": self.standardReferences,
- "deviceName": self.deviceName,
- "deviceMode": self.deviceMode,
- "deviceCode": self.deviceCode,
- "monitorHeight": self.monitorHeight,
- "weather": self.weather.to_dict(),
- "electricMagnetic": [em.to_dict() for em in self.electricMagnetic]
- }
- class InvestmentItem:
- """投资项目数据模型"""
- def __init__(self):
- self.no: str = "" # 序号
- self.name: str = "" # 工程或费用名称
- self.level: str = "" # 明细等级
- self.constructionScaleOverheadLine: str = "" # 建设规模-架空线(仅可研批复)
- self.constructionScaleBay: str = "" # 建设规模-间隔(仅可研批复)
- self.constructionScaleSubstation: str = "" # 建设规模-变电(仅可研批复)
- self.constructionScaleOpticalCable: str = "" # 建设规模-光缆(仅可研批复)
- self.staticInvestment: str = "" # 静态投资(元)
- self.dynamicInvestment: str = "" # 动态投资(元)
- # 新增费用字段(仅可研批复)
- self.constructionProjectCost: str = "" # 建筑工程费(元)
- self.equipmentPurchaseCost: str = "" # 设备购置费(元)
- self.installationProjectCost: str = "" # 安装工程费(元)
- self.otherExpenses: str = "" # 其他费用-合计(元)
-
- def to_dict(self, include_construction_scale: bool = False, include_cost_breakdown: bool = False):
- """
- 转换为字典
-
- Args:
- include_construction_scale: 是否包含建设规模字段(可研批复需要)
- include_cost_breakdown: 是否包含费用明细字段(可研批复需要)
- """
- result = {
- "No": self.no,
- "name": self.name,
- "Level": self.level,
- "staticInvestment": self.staticInvestment,
- "dynamicInvestment": self.dynamicInvestment
- }
-
- # 如果需要建设规模字段,添加到输出(用于可研批复)
- if include_construction_scale:
- result["constructionScaleOverheadLine"] = self.constructionScaleOverheadLine
- result["constructionScaleBay"] = self.constructionScaleBay
- result["constructionScaleSubstation"] = self.constructionScaleSubstation
- result["constructionScaleOpticalCable"] = self.constructionScaleOpticalCable
-
- # 如果需要费用明细字段,添加到输出(用于可研批复)
- if include_cost_breakdown:
- result["constructionProjectCost"] = self.constructionProjectCost
- result["equipmentPurchaseCost"] = self.equipmentPurchaseCost
- result["installationProjectCost"] = self.installationProjectCost
- result["otherExpenses"] = self.otherExpenses
-
- return result
- class FeasibilityApprovalInvestment:
- """可研批复投资估算数据模型
-
- 返回结构与 designReview 保持一致,包含建设规模字段
- 三层嵌套结构:
- - Level 0: 顶层大类(如"山西晋城周村220千伏输变电工程")
- - Level 1: 二级分类(如"变电工程"、"线路工程"),有自己的 items
- - Level 2: 具体项目(如"周村220千伏变电站新建工程")
-
- 项目信息(可选,用于 safetyFsApproval 类型):
- - projectName: 工程(项目)名称
- - projectUnit: 项目单位
- - designUnit: 设计单位
- """
- def __init__(self):
- self.items: List[InvestmentItem] = []
- # 项目基本信息(safetyFsApproval 专用)
- self.projectName: Optional[str] = None
- self.projectUnit: Optional[str] = None
- self.designUnit: Optional[str] = None
-
- def to_dict(self):
- """转换为嵌套结构,与 designReview 保持一致
-
- Level="1" 的项目作为顶层大类(Level: 0)
- Level="2" 的项目作为二级分类(Level: 1),有自己的 items
- Level="3" 的项目作为具体项目(Level: 2),放入二级分类的 items
- Level="0" 的项目(合计)跳过
-
- 特殊处理:如果表格没有 Level=1 的顶层大类(如湖北省格式),
- 自动创建一个虚拟顶层大类来包含所有 Level=2 的项目
- """
- if not self.items:
- return []
-
- # 检查是否有 Level=1 的顶层大类
- has_level_1 = any(item.level == "1" for item in self.items)
-
- result = []
- current_top_category = None # Level 0 顶层大类
- current_sub_category = None # Level 1 二级分类
-
- # 如果没有 Level=1 的顶层大类,创建一个虚拟的
- if not has_level_1:
- current_top_category = {
- "name": "项目总表",
- "Level": 0,
- "constructionScaleSubstation": "",
- "constructionScaleBay": "",
- "constructionScaleOverheadLine": "",
- "constructionScaleOpticalCable": "",
- "staticInvestment": "",
- "dynamicInvestment": "",
- "constructionProjectCost": "",
- "equipmentPurchaseCost": "",
- "installationProjectCost": "",
- "otherExpenses": "",
- "items": []
- }
-
- for item in self.items:
- if item.level == "1":
- # 顶层大类(如"山西晋城周村220千伏输变电工程")
- # 保存之前的二级分类和顶层大类
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- current_sub_category = None
- if current_top_category is not None:
- result.append(current_top_category)
-
- current_top_category = {
- "name": item.name,
- "Level": 0,
- "constructionScaleSubstation": item.constructionScaleSubstation or "",
- "constructionScaleBay": item.constructionScaleBay or "",
- "constructionScaleOverheadLine": item.constructionScaleOverheadLine or "",
- "constructionScaleOpticalCable": item.constructionScaleOpticalCable or "",
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "constructionProjectCost": self._parse_number(item.constructionProjectCost),
- "equipmentPurchaseCost": self._parse_number(item.equipmentPurchaseCost),
- "installationProjectCost": self._parse_number(item.installationProjectCost),
- "otherExpenses": self._parse_number(item.otherExpenses),
- "items": []
- }
- elif item.level == "2" and current_top_category is not None:
- # 二级分类(如"变电工程"、"线路工程")
- # 保存之前的二级分类
- if current_sub_category is not None:
- current_top_category["items"].append(current_sub_category)
-
- current_sub_category = {
- "No": self._parse_no(item.no),
- "name": item.name,
- "Level": 1,
- "constructionScaleSubstation": item.constructionScaleSubstation or "",
- "constructionScaleBay": item.constructionScaleBay or "",
- "constructionScaleOverheadLine": item.constructionScaleOverheadLine or "",
- "constructionScaleOpticalCable": item.constructionScaleOpticalCable or "",
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "constructionProjectCost": self._parse_number(item.constructionProjectCost),
- "equipmentPurchaseCost": self._parse_number(item.equipmentPurchaseCost),
- "installationProjectCost": self._parse_number(item.installationProjectCost),
- "otherExpenses": self._parse_number(item.otherExpenses),
- "items": []
- }
- elif item.level == "3" and current_sub_category is not None:
- # 具体项目(如"周村220千伏变电站新建工程")
- current_sub_category["items"].append({
- "No": self._parse_no(item.no),
- "name": item.name,
- "Level": 2,
- "constructionScaleSubstation": item.constructionScaleSubstation or "",
- "constructionScaleBay": item.constructionScaleBay or "",
- "constructionScaleOverheadLine": item.constructionScaleOverheadLine or "",
- "constructionScaleOpticalCable": item.constructionScaleOpticalCable or "",
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "constructionProjectCost": self._parse_number(item.constructionProjectCost),
- "equipmentPurchaseCost": self._parse_number(item.equipmentPurchaseCost),
- "installationProjectCost": self._parse_number(item.installationProjectCost),
- "otherExpenses": self._parse_number(item.otherExpenses),
- })
- elif item.level == "0":
- # 合计行 - 跳过
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- current_sub_category = None
- if current_top_category is not None:
- result.append(current_top_category)
- current_top_category = None
-
- # 添加最后的分类
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- if current_top_category is not None:
- result.append(current_top_category)
-
- # 如果有项目信息,返回包含项目信息的字典;否则直接返回数据列表
- if self.projectName or self.projectUnit or self.designUnit:
- return {
- "projectInfo": {
- "projectName": self.projectName or "",
- "projectUnit": self.projectUnit or "",
- "designUnit": self.designUnit or ""
- },
- "data": result
- }
- return result
-
- @staticmethod
- def _parse_number(value: str) -> str:
- """将数字字符串格式化,保留原始精度"""
- if not value or not value.strip():
- return "0"
- return value.strip()
-
- @staticmethod
- def _parse_no(value: str) -> int:
- if not value or not value.strip():
- return 0
- try:
- return int(value.strip())
- except ValueError:
- return 0
- class FeasibilityReviewInvestment:
- """可研评审投资估算数据模型
-
- 返回结构与 designReview 保持一致,不包含建设规模字段
- 三层嵌套结构:
- - Level 0: 顶层大类
- - Level 1: 二级分类,有自己的 items
- - Level 2: 具体项目
- """
- def __init__(self):
- self.items: List[InvestmentItem] = []
-
- def to_dict(self):
- """转换为嵌套结构,与 designReview 保持一致
-
- Level="1" 的项目作为顶层大类(Level: 0)
- Level="2" 的项目作为二级分类(Level: 1),有自己的 items
- Level="3" 的项目作为具体项目(Level: 2),放入二级分类的 items
- Level="0" 的项目(合计)跳过
- """
- if not self.items:
- return []
-
- result = []
- current_top_category = None
- current_sub_category = None
-
- for item in self.items:
- if item.level == "1":
- # 顶层大类
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- current_sub_category = None
- if current_top_category is not None:
- result.append(current_top_category)
-
- current_top_category = {
- "name": item.name,
- "Level": 0,
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "items": []
- }
- elif item.level == "2" and current_top_category is not None:
- # 二级分类
- if current_sub_category is not None:
- current_top_category["items"].append(current_sub_category)
-
- current_sub_category = {
- "No": self._parse_no(item.no),
- "name": item.name,
- "Level": 1,
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "items": []
- }
- elif item.level == "3" and current_sub_category is not None:
- # 具体项目
- current_sub_category["items"].append({
- "No": self._parse_no(item.no),
- "name": item.name,
- "Level": 2,
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- })
- elif item.level == "0":
- # 合计行 - 跳过
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- current_sub_category = None
- if current_top_category is not None:
- result.append(current_top_category)
- current_top_category = None
-
- # 添加最后的分类
- if current_sub_category is not None and current_top_category is not None:
- current_top_category["items"].append(current_sub_category)
- if current_top_category is not None:
- result.append(current_top_category)
-
- return result
-
- @staticmethod
- def _parse_number(value: str) -> str:
- """将数字字符串格式化,保留原始精度"""
- if not value or not value.strip():
- return "0"
- return value.strip()
-
- @staticmethod
- def _parse_no(value: str) -> int:
- if not value or not value.strip():
- return 0
- try:
- return int(value.strip())
- except ValueError:
- return 0
- class PreliminaryApprovalInvestment:
- """初设批复概算投资数据模型
-
- 返回结构与 designReview 保持一致:
- [{
- "name": str, # 大类名称(如"变电工程"、"线路工程")
- "Level": 0, # 大类层级
- "staticInvestment": float, # 静态投资总计
- "dynamicInvestment": float, # 动态投资总计
- "items": [ # 子项列表
- {
- "No": int, # 序号
- "name": str, # 工程名称
- "Level": 1, # 子项层级
- "staticInvestment": float, # 静态投资
- "dynamicInvestment": float, # 动态投资
- },
- ...
- ]
- }, ...]
- """
- def __init__(self):
- self.items: List[InvestmentItem] = []
-
- def to_dict(self):
- """转换为嵌套结构,与 designReview 保持一致
-
- Level="1" 的项目作为大类(变电工程、线路工程等)
- Level="2" 的项目作为子项
- Level="0" 的项目(合计)跳过,不包含在输出中
- """
- if not self.items:
- return []
-
- result = []
- current_category = None
-
- for item in self.items:
- if item.level == "1":
- # 大类项目 - 创建新的类别
- if current_category is not None:
- result.append(current_category)
-
- current_category = {
- "name": item.name,
- "Level": 0,
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- "items": []
- }
- elif item.level == "2" and current_category is not None:
- # 子项目 - 添加到当前类别的 items 中
- current_category["items"].append({
- "No": self._parse_no(item.no),
- "name": item.name,
- "Level": 1,
- "staticInvestment": self._parse_number(item.staticInvestment),
- "dynamicInvestment": self._parse_number(item.dynamicInvestment),
- })
- elif item.level == "0":
- # 合计行 - 跳过,不包含在输出中
- # 先保存当前类别
- if current_category is not None:
- result.append(current_category)
- current_category = None
-
- # 添加最后一个类别
- if current_category is not None:
- result.append(current_category)
-
- return result
-
- @staticmethod
- def _parse_number(value: str) -> str:
- """将数字字符串格式化,保留原始精度"""
- if not value or not value.strip():
- return "0"
- return value.strip()
-
- @staticmethod
- def _parse_no(value: str) -> int:
- """将序号转换为整数"""
- if not value or not value.strip():
- return 0
- try:
- return int(value.strip())
- except ValueError:
- return 0
- class FinalAccountItem:
- """决算报告单项工程投资完成情况数据模型"""
- def __init__(self):
- self.no: int = 0 # 序号(项目序号)
- self.name: str = "" # 项目名称(审计内容)
- self.feeName: str = "" # 费用项目(建筑安装工程、设备购置、其他费用)
- self.estimatedCost: str = "" # 概算金额
- self.approvedFinalAccountExcludingVat: str = "" # 决算金额审定不含税
- self.vatAmount: str = "" # 增值税额
- self.costVariance: str = "" # 超节支金额
- self.varianceRate: str = "" # 超节支率
-
- def to_dict(self, include_project_info: bool = True):
- """转换为字典
-
- Args:
- include_project_info: 是否包含项目序号和名称(分组后不需要)
- """
- result = {
- "feeName": self.feeName,
- "estimatedCost": self.estimatedCost,
- "approvedFinalAccountExcludingVat": self.approvedFinalAccountExcludingVat,
- "vatAmount": self.vatAmount,
- "costVariance": self.costVariance,
- "varianceRate": self.varianceRate
- }
- if include_project_info:
- result["No"] = self.no
- result["name"] = self.name
- return result
- class FinalAccountRecord:
- """决算报告记录数据模型
-
- 返回结构:按项目分组的嵌套数组
- [{
- "No": int, # 序号(项目序号,如1、2、3、4)
- "name": str, # 项目名称(如"周村220kV输变电工程变电站新建工程")
- "items": [{ # 费用明细列表
- "feeName": str, # 费用项目(如"建筑安装工程"、"设备购置"、"其他费用")
- "estimatedCost": str, # 概算金额
- "approvedFinalAccountExcludingVat": str, # 决算金额审定不含税
- "vatAmount": str, # 增值税额
- "costVariance": str, # 超节支金额
- "varianceRate": str, # 超节支率
- }, ...]
- }, ...]
- """
- def __init__(self):
- self.items: List[FinalAccountItem] = []
-
- def to_dict(self):
- """转换为按项目分组的嵌套结构"""
- from collections import OrderedDict
-
- # 按项目序号分组
- grouped: OrderedDict[int, dict] = OrderedDict()
-
- for item in self.items:
- if item.no not in grouped:
- grouped[item.no] = {
- "No": item.no,
- "name": item.name,
- "items": []
- }
- # 添加费用明细(不包含项目序号和名称)
- grouped[item.no]["items"].append(item.to_dict(include_project_info=False))
-
- return list(grouped.values())
|