staran 0.6.0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- staran/__init__.py +10 -0
- staran/tools/__init__.py +5 -5
- staran-1.0.0.dist-info/METADATA +301 -0
- staran-1.0.0.dist-info/RECORD +8 -0
- staran/banks/__init__.py +0 -30
- staran/banks/xinjiang_icbc/__init__.py +0 -90
- staran/engines/__init__.py +0 -65
- staran/engines/base.py +0 -255
- staran/engines/hive.py +0 -163
- staran/engines/spark.py +0 -252
- staran/engines/turing.py +0 -439
- staran/examples/__init__.py +0 -8
- staran/examples/aum_longtail.py +0 -250
- staran/examples/aum_longtail_old.py +0 -487
- staran/features/__init__.py +0 -59
- staran/features/engines.py +0 -284
- staran/features/generator.py +0 -603
- staran/features/manager.py +0 -155
- staran/features/schema.py +0 -193
- staran/models/__init__.py +0 -72
- staran/models/bank_configs.py +0 -269
- staran/models/config.py +0 -271
- staran/models/daifa_models.py +0 -361
- staran/models/registry.py +0 -281
- staran/models/target.py +0 -321
- staran/schemas/__init__.py +0 -27
- staran/schemas/aum/__init__.py +0 -210
- staran/schemas/document_generator.py +0 -350
- staran/tools/document_generator.py +0 -350
- staran-0.6.0.dist-info/METADATA +0 -564
- staran-0.6.0.dist-info/RECORD +0 -33
- {staran-0.6.0.dist-info → staran-1.0.0.dist-info}/WHEEL +0 -0
- {staran-0.6.0.dist-info → staran-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {staran-0.6.0.dist-info → staran-1.0.0.dist-info}/top_level.txt +0 -0
staran/schemas/aum/__init__.py
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
新疆工行代发长尾客户表结构定义模块
|
3
|
-
|
4
|
-
包含新疆工行代发长尾客户相关的所有表结构:
|
5
|
-
- 代发长尾客户行为特征表 (XinjiangICBCDaifaLongtailBehaviorSchema)
|
6
|
-
- 代发长尾客户资产平均值表 (XinjiangICBCDaifaLongtailAssetAvgSchema)
|
7
|
-
- 代发长尾客户资产配置表 (XinjiangICBCDaifaLongtailAssetConfigSchema)
|
8
|
-
- 代发长尾客户月度统计表 (XinjiangICBCDaifaLongtailMonthlyStatSchema)
|
9
|
-
|
10
|
-
数据库: xinjiang_icbc_daifa_longtail
|
11
|
-
业务范围: 代发长尾客户(资产10k-100k)
|
12
|
-
|
13
|
-
这些表结构可以用于:
|
14
|
-
1. 代发长尾客户特征工程
|
15
|
-
2. 提升模型和防流失模型构建
|
16
|
-
3. 业务文档生成
|
17
|
-
4. 数据质量检查
|
18
|
-
"""
|
19
|
-
|
20
|
-
from typing import Dict
|
21
|
-
from ...features.schema import TableSchema
|
22
|
-
from ...tools.document_generator import SchemaDocumentGenerator
|
23
|
-
|
24
|
-
|
25
|
-
class XinjiangICBCDaifaLongtailBehaviorSchema:
|
26
|
-
"""新疆工行代发长尾客户行为特征表 - 严格按照已提供给行方的字段"""
|
27
|
-
|
28
|
-
# 统计指标定义 - 与原始定义完全一致
|
29
|
-
_STATS = [
|
30
|
-
("max", "最大值"),
|
31
|
-
("min", "最小值"),
|
32
|
-
("sum", "总和"),
|
33
|
-
("avg", "均值"),
|
34
|
-
("var", "方差"),
|
35
|
-
("std", "标准差"),
|
36
|
-
("rng", "极差"),
|
37
|
-
("med", "中位数"),
|
38
|
-
]
|
39
|
-
|
40
|
-
@staticmethod
|
41
|
-
def create() -> TableSchema:
|
42
|
-
"""创建新疆工行代发长尾客户行为特征表结构"""
|
43
|
-
schema = TableSchema('xinjiang_icbc_daifa_hlwj_dfcw_f1_f4_wy')
|
44
|
-
schema.add_primary_key('party_id', 'string')
|
45
|
-
schema.add_date_field('data_dt', 'string')
|
46
|
-
|
47
|
-
# 基础字段 - 严格按照原始定义
|
48
|
-
schema.add_field("buy_ct", "int", comment="购买次数", aggregatable=True)
|
49
|
-
schema.add_field("recency", "int", comment="最近一次购买距今天数", aggregatable=True)
|
50
|
-
schema.add_field("tenure", "int", comment="客户关系持续时间", aggregatable=True)
|
51
|
-
schema.add_field("window1", "string", comment="时间窗口标记")
|
52
|
-
schema.add_field("freq", "float", comment="总购买频率", aggregatable=True)
|
53
|
-
schema.add_field("freq1", "float", comment="最近时间段购买频率", aggregatable=True)
|
54
|
-
schema.add_field("productidcount", "int", comment="产品种类数", aggregatable=True)
|
55
|
-
schema.add_field("orderidcount", "int", comment="订单数", aggregatable=True)
|
56
|
-
schema.add_field("label", "float", comment="标签值(如是否购买)", aggregatable=True)
|
57
|
-
|
58
|
-
# productamount and m1 ~ m4 的含义描述
|
59
|
-
m_fields = {
|
60
|
-
"productamount": "购买金额",
|
61
|
-
"m1": "去重订单数",
|
62
|
-
"m2": "去重商品数",
|
63
|
-
"m3": "去重渠道数",
|
64
|
-
"m4": "去重产品品类数",
|
65
|
-
}
|
66
|
-
|
67
|
-
# 使用循环注册 productamount and m1~m4 各统计字段
|
68
|
-
for prefix, meaning in m_fields.items():
|
69
|
-
for stat_key, stat_desc in XinjiangICBCDaifaLongtailBehaviorSchema._STATS:
|
70
|
-
field_name = f"{prefix}_{stat_key}"
|
71
|
-
description = f"{meaning}的{stat_desc}"
|
72
|
-
schema.add_field(field_name, "float", comment=description, aggregatable=True)
|
73
|
-
|
74
|
-
# 其他字段
|
75
|
-
schema.add_field("life_day", "float", comment="客户生命周期天数", aggregatable=True)
|
76
|
-
schema.add_field("gender", "float", comment="性别(编码)", aggregatable=True)
|
77
|
-
schema.add_field("open_day", "float", comment="开户天数", aggregatable=True)
|
78
|
-
|
79
|
-
schema.set_monthly_unique(False) # 每人每日记录
|
80
|
-
return schema
|
81
|
-
|
82
|
-
|
83
|
-
class XinjiangICBCDaifaLongtailAssetAvgSchema:
|
84
|
-
"""新疆工行代发长尾客户资产平均值表"""
|
85
|
-
|
86
|
-
@staticmethod
|
87
|
-
def create() -> TableSchema:
|
88
|
-
"""创建新疆工行代发长尾客户资产平均值表结构"""
|
89
|
-
schema = TableSchema('xinjiang_icbc_daifa_hlwj_zi_chan_avg_wy')
|
90
|
-
schema.add_primary_key('party_id', 'string')
|
91
|
-
schema.add_date_field('data_dt', 'string')
|
92
|
-
|
93
|
-
# 基础余额字段
|
94
|
-
schema.add_field("asset_total_bal", "decimal", comment="总资产余额", aggregatable=True)
|
95
|
-
schema.add_field("liab_total_bal", "decimal", comment="总负债余额", aggregatable=True)
|
96
|
-
schema.add_field("net_asset_bal", "decimal", comment="净资产余额", aggregatable=True)
|
97
|
-
|
98
|
-
# 存款相关字段
|
99
|
-
schema.add_field("dep_bal", "decimal", comment="存款余额", aggregatable=True)
|
100
|
-
schema.add_field("current_dep_bal", "decimal", comment="活期存款余额", aggregatable=True)
|
101
|
-
schema.add_field("time_dep_bal", "decimal", comment="定期存款余额", aggregatable=True)
|
102
|
-
|
103
|
-
# 理财投资字段
|
104
|
-
schema.add_field("wealth_bal", "decimal", comment="理财余额", aggregatable=True)
|
105
|
-
schema.add_field("fund_bal", "decimal", comment="基金余额", aggregatable=True)
|
106
|
-
schema.add_field("insurance_bal", "decimal", comment="保险余额", aggregatable=True)
|
107
|
-
|
108
|
-
schema.set_monthly_unique(True) # 每人每月一条记录
|
109
|
-
return schema
|
110
|
-
|
111
|
-
|
112
|
-
class XinjiangICBCDaifaLongtailAssetConfigSchema:
|
113
|
-
"""新疆工行代发长尾客户资产配置表"""
|
114
|
-
|
115
|
-
@staticmethod
|
116
|
-
def create() -> TableSchema:
|
117
|
-
"""创建新疆工行代发长尾客户资产配置表结构"""
|
118
|
-
schema = TableSchema('xinjiang_icbc_daifa_hlwj_zi_chan_config_wy')
|
119
|
-
schema.add_primary_key('party_id', 'string')
|
120
|
-
schema.add_date_field('data_dt', 'string')
|
121
|
-
|
122
|
-
# 资产配置比例字段
|
123
|
-
schema.add_field("cash_ratio", "float", comment="现金类资产占比", aggregatable=True)
|
124
|
-
schema.add_field("fixed_income_ratio", "float", comment="固收类资产占比", aggregatable=True)
|
125
|
-
schema.add_field("equity_ratio", "float", comment="权益类资产占比", aggregatable=True)
|
126
|
-
schema.add_field("alternative_ratio", "float", comment="另类资产占比", aggregatable=True)
|
127
|
-
|
128
|
-
# 风险偏好相关
|
129
|
-
schema.add_field("risk_level", "int", comment="风险偏好等级(1-5)", aggregatable=True)
|
130
|
-
schema.add_field("investment_experience", "int", comment="投资经验年限", aggregatable=True)
|
131
|
-
|
132
|
-
# 配置变化指标
|
133
|
-
schema.add_field("config_change_freq", "int", comment="配置调整频率", aggregatable=True)
|
134
|
-
schema.add_field("rebalance_count", "int", comment="再平衡次数", aggregatable=True)
|
135
|
-
|
136
|
-
schema.set_monthly_unique(True)
|
137
|
-
return schema
|
138
|
-
|
139
|
-
|
140
|
-
class XinjiangICBCDaifaLongtailMonthlyStatSchema:
|
141
|
-
"""新疆工行代发长尾客户月度统计表"""
|
142
|
-
|
143
|
-
@staticmethod
|
144
|
-
def create() -> TableSchema:
|
145
|
-
"""创建新疆工行代发长尾客户月度统计表结构"""
|
146
|
-
schema = TableSchema('xinjiang_icbc_daifa_hlwj_monthly_stat_wy')
|
147
|
-
schema.add_primary_key('party_id', 'string')
|
148
|
-
schema.add_date_field('data_dt', 'string')
|
149
|
-
|
150
|
-
# 月度交易统计
|
151
|
-
schema.add_field("monthly_txn_count", "int", comment="月度交易笔数", aggregatable=True)
|
152
|
-
schema.add_field("monthly_txn_amount", "decimal", comment="月度交易金额", aggregatable=True)
|
153
|
-
schema.add_field("monthly_deposit_amount", "decimal", comment="月度存入金额", aggregatable=True)
|
154
|
-
schema.add_field("monthly_withdraw_amount", "decimal", comment="月度取出金额", aggregatable=True)
|
155
|
-
|
156
|
-
# 代发工资相关统计
|
157
|
-
schema.add_field("salary_amount", "decimal", comment="月度代发工资金额", aggregatable=True)
|
158
|
-
schema.add_field("salary_date", "string", comment="代发工资日期")
|
159
|
-
schema.add_field("salary_stability", "float", comment="工资稳定性指数", aggregatable=True)
|
160
|
-
|
161
|
-
# 长尾客户特征
|
162
|
-
schema.add_field("longtail_score", "float", comment="长尾客户评分", aggregatable=True)
|
163
|
-
schema.add_field("upgrade_potential", "float", comment="提升潜力评分", aggregatable=True)
|
164
|
-
schema.add_field("churn_risk", "float", comment="流失风险评分", aggregatable=True)
|
165
|
-
|
166
|
-
# 活跃度指标
|
167
|
-
schema.add_field("login_days", "int", comment="月度登录天数", aggregatable=True)
|
168
|
-
schema.add_field("channel_usage", "string", comment="渠道使用情况")
|
169
|
-
|
170
|
-
schema.set_monthly_unique(True)
|
171
|
-
return schema
|
172
|
-
|
173
|
-
|
174
|
-
def get_xinjiang_icbc_daifa_longtail_schemas() -> Dict[str, TableSchema]:
|
175
|
-
"""获取新疆工行代发长尾客户所有表结构"""
|
176
|
-
return {
|
177
|
-
'daifa_longtail_behavior': XinjiangICBCDaifaLongtailBehaviorSchema.create(),
|
178
|
-
'daifa_longtail_asset_avg': XinjiangICBCDaifaLongtailAssetAvgSchema.create(),
|
179
|
-
'daifa_longtail_asset_config': XinjiangICBCDaifaLongtailAssetConfigSchema.create(),
|
180
|
-
'daifa_longtail_monthly_stat': XinjiangICBCDaifaLongtailMonthlyStatSchema.create(),
|
181
|
-
}
|
182
|
-
|
183
|
-
|
184
|
-
def export_xinjiang_icbc_daifa_longtail_docs(output_dir: str = "./docs") -> Dict[str, str]:
|
185
|
-
"""导出新疆工行代发长尾客户表结构文档"""
|
186
|
-
generator = SchemaDocumentGenerator()
|
187
|
-
schemas = get_xinjiang_icbc_daifa_longtail_schemas()
|
188
|
-
exported_files = {}
|
189
|
-
|
190
|
-
for table_type, schema in schemas.items():
|
191
|
-
file_path = generator.export_schema_doc(
|
192
|
-
schema,
|
193
|
-
business_domain="新疆工行代发长尾客户",
|
194
|
-
table_type=table_type,
|
195
|
-
output_dir=output_dir
|
196
|
-
)
|
197
|
-
exported_files[table_type] = file_path
|
198
|
-
|
199
|
-
return exported_files
|
200
|
-
|
201
|
-
|
202
|
-
# 导出主要组件
|
203
|
-
__all__ = [
|
204
|
-
'XinjiangICBCDaifaLongtailBehaviorSchema',
|
205
|
-
'XinjiangICBCDaifaLongtailAssetAvgSchema',
|
206
|
-
'XinjiangICBCDaifaLongtailAssetConfigSchema',
|
207
|
-
'XinjiangICBCDaifaLongtailMonthlyStatSchema',
|
208
|
-
'get_xinjiang_icbc_daifa_longtail_schemas',
|
209
|
-
'export_xinjiang_icbc_daifa_longtail_docs'
|
210
|
-
]
|
@@ -1,350 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Schema文档生成器
|
3
|
-
|
4
|
-
支持根据表结构定义生成多种格式的技术文档:
|
5
|
-
- Markdown格式:适合开发团队和版本控制
|
6
|
-
- PDF格式:适合正式交付和业务方审阅
|
7
|
-
- HTML格式:适合在线查看和分享
|
8
|
-
|
9
|
-
主要功能:
|
10
|
-
1. 表结构自动解析
|
11
|
-
2. 字段信息格式化
|
12
|
-
3. 业务含义说明
|
13
|
-
4. 技术规范文档
|
14
|
-
5. 多格式导出支持
|
15
|
-
"""
|
16
|
-
|
17
|
-
import os
|
18
|
-
from typing import Dict, List, Optional
|
19
|
-
from datetime import datetime
|
20
|
-
|
21
|
-
|
22
|
-
class SchemaDocumentGenerator:
|
23
|
-
"""表结构文档生成器"""
|
24
|
-
|
25
|
-
def __init__(self):
|
26
|
-
self.template_configs = {
|
27
|
-
'markdown': {
|
28
|
-
'extension': '.md',
|
29
|
-
'header_template': self._get_markdown_header_template(),
|
30
|
-
'field_template': self._get_markdown_field_template(),
|
31
|
-
'footer_template': self._get_markdown_footer_template()
|
32
|
-
},
|
33
|
-
'pdf': {
|
34
|
-
'extension': '.pdf',
|
35
|
-
'requires_conversion': True,
|
36
|
-
'base_format': 'markdown' # 先生成MD再转PDF
|
37
|
-
},
|
38
|
-
'html': {
|
39
|
-
'extension': '.html',
|
40
|
-
'header_template': self._get_html_header_template(),
|
41
|
-
'field_template': self._get_html_field_template(),
|
42
|
-
'footer_template': self._get_html_footer_template()
|
43
|
-
}
|
44
|
-
}
|
45
|
-
|
46
|
-
def export_schema_doc(self, schema, business_domain: str, table_type: str,
|
47
|
-
output_dir: str = "./docs", format_type: str = "markdown") -> str:
|
48
|
-
"""
|
49
|
-
导出表结构文档
|
50
|
-
|
51
|
-
Args:
|
52
|
-
schema: TableSchema对象
|
53
|
-
business_domain: 业务域名称 (如: AUM, CRM, RISK)
|
54
|
-
table_type: 表类型 (如: behavior, asset_avg)
|
55
|
-
output_dir: 输出目录
|
56
|
-
format_type: 文档格式 ('markdown', 'pdf', 'html')
|
57
|
-
|
58
|
-
Returns:
|
59
|
-
生成的文档文件路径
|
60
|
-
"""
|
61
|
-
# 确保输出目录存在
|
62
|
-
os.makedirs(output_dir, exist_ok=True)
|
63
|
-
|
64
|
-
# 生成文件名
|
65
|
-
timestamp = datetime.now().strftime("%Y%m%d")
|
66
|
-
filename = f"{business_domain}_{table_type}_schema_{timestamp}"
|
67
|
-
|
68
|
-
if format_type.lower() == 'pdf':
|
69
|
-
# PDF格式先生成Markdown再转换
|
70
|
-
md_content = self._generate_markdown_content(schema, business_domain, table_type)
|
71
|
-
md_path = os.path.join(output_dir, f"{filename}.md")
|
72
|
-
|
73
|
-
with open(md_path, 'w', encoding='utf-8') as f:
|
74
|
-
f.write(md_content)
|
75
|
-
|
76
|
-
# 转换为PDF (这里可以集成pandoc或其他转换工具)
|
77
|
-
pdf_path = os.path.join(output_dir, f"{filename}.pdf")
|
78
|
-
self._convert_md_to_pdf(md_path, pdf_path)
|
79
|
-
return pdf_path
|
80
|
-
|
81
|
-
elif format_type.lower() == 'html':
|
82
|
-
# HTML格式
|
83
|
-
html_content = self._generate_html_content(schema, business_domain, table_type)
|
84
|
-
html_path = os.path.join(output_dir, f"{filename}.html")
|
85
|
-
|
86
|
-
with open(html_path, 'w', encoding='utf-8') as f:
|
87
|
-
f.write(html_content)
|
88
|
-
return html_path
|
89
|
-
|
90
|
-
else:
|
91
|
-
# 默认Markdown格式
|
92
|
-
md_content = self._generate_markdown_content(schema, business_domain, table_type)
|
93
|
-
md_path = os.path.join(output_dir, f"{filename}.md")
|
94
|
-
|
95
|
-
with open(md_path, 'w', encoding='utf-8') as f:
|
96
|
-
f.write(md_content)
|
97
|
-
return md_path
|
98
|
-
|
99
|
-
def _generate_markdown_content(self, schema, business_domain: str, table_type: str) -> str:
|
100
|
-
"""生成Markdown格式内容"""
|
101
|
-
content = []
|
102
|
-
|
103
|
-
# 文档头部
|
104
|
-
content.append(f"# {business_domain} - {table_type.upper()}表结构文档")
|
105
|
-
content.append("")
|
106
|
-
content.append(f"## 基本信息")
|
107
|
-
content.append("")
|
108
|
-
content.append(f"- **表名**: `{schema.table_name}`")
|
109
|
-
content.append(f"- **业务域**: {business_domain}")
|
110
|
-
content.append(f"- **表类型**: {table_type}")
|
111
|
-
content.append(f"- **生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
112
|
-
content.append(f"- **月度唯一性**: {'是' if getattr(schema, 'is_monthly_unique', False) else '否'}")
|
113
|
-
content.append("")
|
114
|
-
|
115
|
-
# 表结构说明
|
116
|
-
content.append("## 表结构说明")
|
117
|
-
content.append("")
|
118
|
-
if hasattr(schema, 'description'):
|
119
|
-
content.append(f"{schema.description}")
|
120
|
-
content.append("")
|
121
|
-
|
122
|
-
# 主键信息
|
123
|
-
if hasattr(schema, 'primary_key') and schema.primary_key:
|
124
|
-
content.append("### 主键字段")
|
125
|
-
content.append("")
|
126
|
-
content.append(f"- `{schema.primary_key}` (主键)")
|
127
|
-
content.append("")
|
128
|
-
|
129
|
-
# 日期字段
|
130
|
-
if hasattr(schema, 'date_field') and schema.date_field:
|
131
|
-
content.append("### 日期字段")
|
132
|
-
content.append("")
|
133
|
-
content.append(f"- `{schema.date_field}` (日期字段)")
|
134
|
-
content.append("")
|
135
|
-
|
136
|
-
# 字段详情表格
|
137
|
-
content.append("## 字段详情")
|
138
|
-
content.append("")
|
139
|
-
content.append("| 字段名 | 数据类型 | 业务含义 | 可聚合 | 备注 |")
|
140
|
-
content.append("|--------|----------|----------|--------|------|")
|
141
|
-
|
142
|
-
if hasattr(schema, 'fields'):
|
143
|
-
for field_name, field in schema.fields.items():
|
144
|
-
# 简化数据类型显示
|
145
|
-
field_type_str = str(field.field_type) if hasattr(field, 'field_type') else 'string'
|
146
|
-
field_type = field_type_str.replace('FieldType.', '').lower()
|
147
|
-
comment = field.comment if hasattr(field, 'comment') else ''
|
148
|
-
aggregatable = '是' if getattr(field, 'aggregatable', False) else '否'
|
149
|
-
remarks = '' # 可以从其他地方获取备注
|
150
|
-
|
151
|
-
content.append(f"| `{field_name}` | {field_type} | {comment} | {aggregatable} | {remarks} |")
|
152
|
-
|
153
|
-
content.append("")
|
154
|
-
|
155
|
-
# 业务规则说明
|
156
|
-
content.append("## 业务规则")
|
157
|
-
content.append("")
|
158
|
-
content.append("### 数据更新规则")
|
159
|
-
if getattr(schema, 'is_monthly_unique', False):
|
160
|
-
content.append("- 每人每月一条记录")
|
161
|
-
content.append("- 月末批量更新")
|
162
|
-
else:
|
163
|
-
content.append("- 每人每日一条记录")
|
164
|
-
content.append("- 日终批量更新")
|
165
|
-
content.append("")
|
166
|
-
|
167
|
-
content.append("### 数据质量要求")
|
168
|
-
content.append("- 主键字段不允许为空")
|
169
|
-
content.append("- 日期字段格式统一为YYYYMMDD")
|
170
|
-
content.append("- 金额字段精度保持2位小数")
|
171
|
-
content.append("- 比例字段取值范围[0,1]")
|
172
|
-
content.append("")
|
173
|
-
|
174
|
-
# 使用说明
|
175
|
-
content.append("## 使用说明")
|
176
|
-
content.append("")
|
177
|
-
content.append("### 特征工程配置")
|
178
|
-
if table_type == 'behavior':
|
179
|
-
content.append("- 生成原始拷贝特征")
|
180
|
-
content.append("- 生成聚合特征")
|
181
|
-
content.append("- 不生成环比、同比特征")
|
182
|
-
else:
|
183
|
-
content.append("- 生成聚合特征")
|
184
|
-
content.append("- 生成5个月环比特征")
|
185
|
-
content.append("- 生成1年同比特征")
|
186
|
-
content.append("")
|
187
|
-
|
188
|
-
content.append("### 示例SQL查询")
|
189
|
-
content.append("```sql")
|
190
|
-
content.append(f"-- 查询最新数据")
|
191
|
-
content.append(f"SELECT * FROM {schema.table_name}")
|
192
|
-
content.append(f"WHERE data_dt = (SELECT MAX(data_dt) FROM {schema.table_name})")
|
193
|
-
content.append(f"LIMIT 10;")
|
194
|
-
content.append("```")
|
195
|
-
content.append("")
|
196
|
-
|
197
|
-
# 文档尾部
|
198
|
-
content.append("---")
|
199
|
-
content.append("*本文档由Staran Schema自动生成*")
|
200
|
-
|
201
|
-
return "\n".join(content)
|
202
|
-
|
203
|
-
def _generate_html_content(self, schema, business_domain: str, table_type: str) -> str:
|
204
|
-
"""生成HTML格式内容"""
|
205
|
-
# 基础HTML模板,可以根据需要扩展
|
206
|
-
html_content = f"""
|
207
|
-
<!DOCTYPE html>
|
208
|
-
<html lang="zh-CN">
|
209
|
-
<head>
|
210
|
-
<meta charset="UTF-8">
|
211
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
212
|
-
<title>{business_domain} - {table_type.upper()}表结构文档</title>
|
213
|
-
<style>
|
214
|
-
body {{ font-family: 'Microsoft YaHei', Arial, sans-serif; margin: 40px; }}
|
215
|
-
h1, h2, h3 {{ color: #333; }}
|
216
|
-
table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
|
217
|
-
th, td {{ border: 1px solid #ddd; padding: 12px; text-align: left; }}
|
218
|
-
th {{ background-color: #f2f2f2; font-weight: bold; }}
|
219
|
-
code {{ background-color: #f4f4f4; padding: 2px 4px; border-radius: 3px; }}
|
220
|
-
.info-table {{ background-color: #f9f9f9; }}
|
221
|
-
</style>
|
222
|
-
</head>
|
223
|
-
<body>
|
224
|
-
<h1>{business_domain} - {table_type.upper()}表结构文档</h1>
|
225
|
-
|
226
|
-
<h2>基本信息</h2>
|
227
|
-
<table class="info-table">
|
228
|
-
<tr><th>表名</th><td><code>{schema.table_name}</code></td></tr>
|
229
|
-
<tr><th>业务域</th><td>{business_domain}</td></tr>
|
230
|
-
<tr><th>表类型</th><td>{table_type}</td></tr>
|
231
|
-
<tr><th>生成时间</th><td>{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</td></tr>
|
232
|
-
<tr><th>月度唯一性</th><td>{'是' if getattr(schema, 'is_monthly_unique', False) else '否'}</td></tr>
|
233
|
-
</table>
|
234
|
-
|
235
|
-
<h2>字段详情</h2>
|
236
|
-
<table>
|
237
|
-
<thead>
|
238
|
-
<tr>
|
239
|
-
<th>字段名</th>
|
240
|
-
<th>数据类型</th>
|
241
|
-
<th>业务含义</th>
|
242
|
-
<th>可聚合</th>
|
243
|
-
<th>备注</th>
|
244
|
-
</tr>
|
245
|
-
</thead>
|
246
|
-
<tbody>
|
247
|
-
"""
|
248
|
-
|
249
|
-
# 添加字段行
|
250
|
-
if hasattr(schema, 'fields'):
|
251
|
-
for field_name, field in schema.fields.items():
|
252
|
-
# 简化数据类型显示
|
253
|
-
field_type_str = str(field.field_type) if hasattr(field, 'field_type') else 'string'
|
254
|
-
field_type = field_type_str.replace('FieldType.', '').lower()
|
255
|
-
comment = field.comment if hasattr(field, 'comment') else ''
|
256
|
-
aggregatable = '是' if getattr(field, 'aggregatable', False) else '否'
|
257
|
-
remarks = '' # 可以从其他地方获取备注
|
258
|
-
|
259
|
-
html_content += f"""
|
260
|
-
<tr>
|
261
|
-
<td><code>{field_name}</code></td>
|
262
|
-
<td>{field_type}</td>
|
263
|
-
<td>{comment}</td>
|
264
|
-
<td>{aggregatable}</td>
|
265
|
-
<td>{remarks}</td>
|
266
|
-
</tr>"""
|
267
|
-
|
268
|
-
html_content += """
|
269
|
-
</tbody>
|
270
|
-
</table>
|
271
|
-
|
272
|
-
<hr>
|
273
|
-
<p><em>本文档由Staran Schema自动生成</em></p>
|
274
|
-
</body>
|
275
|
-
</html>"""
|
276
|
-
|
277
|
-
return html_content
|
278
|
-
|
279
|
-
def _convert_md_to_pdf(self, md_path: str, pdf_path: str):
|
280
|
-
"""将Markdown转换为PDF (需要安装pandoc或其他转换工具)"""
|
281
|
-
try:
|
282
|
-
import subprocess
|
283
|
-
# 尝试使用pandoc转换
|
284
|
-
subprocess.run([
|
285
|
-
'pandoc', md_path, '-o', pdf_path,
|
286
|
-
'--pdf-engine=xelatex',
|
287
|
-
'--variable=CJKmainfont:Microsoft YaHei'
|
288
|
-
], check=True)
|
289
|
-
except (subprocess.CalledProcessError, FileNotFoundError):
|
290
|
-
# 如果pandoc不可用,创建一个说明文件
|
291
|
-
with open(pdf_path.replace('.pdf', '_conversion_note.txt'), 'w', encoding='utf-8') as f:
|
292
|
-
f.write(f"PDF转换说明:\\n")
|
293
|
-
f.write(f"原始Markdown文件:{md_path}\\n")
|
294
|
-
f.write(f"如需PDF格式,请安装pandoc工具:\\n")
|
295
|
-
f.write(f"pip install pandoc\\n")
|
296
|
-
f.write(f"或访问:https://pandoc.org/installing.html\\n")
|
297
|
-
|
298
|
-
def _get_markdown_header_template(self) -> str:
|
299
|
-
return "# {title}\\n\\n## 基本信息\\n\\n"
|
300
|
-
|
301
|
-
def _get_markdown_field_template(self) -> str:
|
302
|
-
return "| {name} | {type} | {comment} | {aggregatable} |\\n"
|
303
|
-
|
304
|
-
def _get_markdown_footer_template(self) -> str:
|
305
|
-
return "\\n---\\n*文档生成时间: {timestamp}*\\n"
|
306
|
-
|
307
|
-
def _get_html_header_template(self) -> str:
|
308
|
-
return "<h1>{title}</h1>\\n<h2>基本信息</h2>\\n"
|
309
|
-
|
310
|
-
def _get_html_field_template(self) -> str:
|
311
|
-
return "<tr><td>{name}</td><td>{type}</td><td>{comment}</td><td>{aggregatable}</td></tr>\\n"
|
312
|
-
|
313
|
-
def _get_html_footer_template(self) -> str:
|
314
|
-
return "<hr><p><em>文档生成时间: {timestamp}</em></p>\\n"
|
315
|
-
|
316
|
-
|
317
|
-
def export_business_docs(business_domain: str, schemas_dict: Dict, output_dir: str = "./docs",
|
318
|
-
format_type: str = "markdown") -> Dict[str, str]:
|
319
|
-
"""
|
320
|
-
批量导出业务域表结构文档
|
321
|
-
|
322
|
-
Args:
|
323
|
-
business_domain: 业务域名称
|
324
|
-
schemas_dict: 表结构字典 {table_type: schema}
|
325
|
-
output_dir: 输出目录
|
326
|
-
format_type: 文档格式
|
327
|
-
|
328
|
-
Returns:
|
329
|
-
生成的文档文件路径字典
|
330
|
-
"""
|
331
|
-
generator = SchemaDocumentGenerator()
|
332
|
-
results = {}
|
333
|
-
|
334
|
-
for table_type, schema in schemas_dict.items():
|
335
|
-
file_path = generator.export_schema_doc(
|
336
|
-
schema=schema,
|
337
|
-
business_domain=business_domain,
|
338
|
-
table_type=table_type,
|
339
|
-
output_dir=output_dir,
|
340
|
-
format_type=format_type
|
341
|
-
)
|
342
|
-
results[table_type] = file_path
|
343
|
-
|
344
|
-
return results
|
345
|
-
|
346
|
-
|
347
|
-
__all__ = [
|
348
|
-
'SchemaDocumentGenerator',
|
349
|
-
'export_business_docs'
|
350
|
-
]
|