Backend (Django 4.2 + DRF): - Admin auth with SimpleJWT - Volcengine API client with HMAC-SHA256 signing - IAM user management (create/sync/import/disable/enable) - Billing query with pagination - Feishu webhook notifications (async) - APScheduler for periodic spending checks - AES-256 encrypted credential storage - API key auth for external system integration Frontend (Vue 3 + Element Plus): - Login page - Dashboard with stats overview - IAM user list with per-user threshold config - Billing view with spending progress bars - Alert history with type filtering - Settings page for global config and Volcengine account management Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
118 lines
7.6 KiB
Python
118 lines
7.6 KiB
Python
# Generated by Django 4.2.21 on 2026-03-19 04:58
|
||
|
||
from django.db import migrations, models
|
||
import django.db.models.deletion
|
||
|
||
|
||
class Migration(migrations.Migration):
|
||
|
||
initial = True
|
||
|
||
dependencies = [
|
||
]
|
||
|
||
operations = [
|
||
migrations.CreateModel(
|
||
name='GlobalConfig',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('default_alert_threshold', models.DecimalField(decimal_places=2, default=1000, max_digits=12, verbose_name='默认告警阈值(元)')),
|
||
('default_disable_threshold', models.DecimalField(decimal_places=2, default=5000, max_digits=12, verbose_name='默认停用阈值(元)')),
|
||
('monitor_interval_seconds', models.IntegerField(default=3600, verbose_name='监控间隔(秒)')),
|
||
('feishu_webhook_url', models.URLField(blank=True, max_length=500, verbose_name='飞书 Webhook URL')),
|
||
('feishu_alert_mobiles', models.CharField(blank=True, max_length=500, verbose_name='飞书通知手机号(逗号分隔)')),
|
||
('updated_at', models.DateTimeField(auto_now=True)),
|
||
],
|
||
options={
|
||
'verbose_name': '全局配置',
|
||
'verbose_name_plural': '全局配置',
|
||
'db_table': 'airgate_global_config',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='VolcAccount',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('name', models.CharField(default='默认主账号', max_length=100, verbose_name='账号名称')),
|
||
('access_key_enc', models.TextField(blank=True, verbose_name='AccessKey(加密)')),
|
||
('secret_key_enc', models.TextField(blank=True, verbose_name='SecretKey(加密)')),
|
||
('access_key_hint', models.CharField(blank=True, max_length=20, verbose_name='AK 提示(前4后4)')),
|
||
('is_active', models.BooleanField(default=True, verbose_name='启用')),
|
||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||
('updated_at', models.DateTimeField(auto_now=True)),
|
||
],
|
||
options={
|
||
'verbose_name': '火山主账号',
|
||
'verbose_name_plural': '火山主账号',
|
||
'db_table': 'airgate_volc_account',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='IAMUser',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('username', models.CharField(db_index=True, max_length=200, verbose_name='IAM 用户名')),
|
||
('display_name', models.CharField(blank=True, max_length=200, verbose_name='显示名')),
|
||
('user_id', models.CharField(blank=True, max_length=100, verbose_name='火山 UserID')),
|
||
('email', models.EmailField(blank=True, max_length=254, verbose_name='邮箱')),
|
||
('phone', models.CharField(blank=True, max_length=20, verbose_name='手机号')),
|
||
('project_name', models.CharField(blank=True, help_text='用于按项目维度追踪消费', max_length=200, verbose_name='关联项目名')),
|
||
('status', models.CharField(choices=[('active', '正常'), ('disabled', '已停用'), ('unknown', '未知')], default='unknown', max_length=20, verbose_name='状态')),
|
||
('access_key_ids', models.JSONField(blank=True, default=list, verbose_name='AccessKey ID 列表')),
|
||
('monitor_enabled', models.BooleanField(default=True, verbose_name='启用消费监控')),
|
||
('auto_disable_enabled', models.BooleanField(default=True, verbose_name='启用自动停用')),
|
||
('alert_threshold', models.DecimalField(blank=True, decimal_places=2, help_text='为空则使用全局默认值', max_digits=12, null=True, verbose_name='告警阈值(元)')),
|
||
('disable_threshold', models.DecimalField(blank=True, decimal_places=2, help_text='为空则使用全局默认值', max_digits=12, null=True, verbose_name='停用阈值(元)')),
|
||
('current_month_spending', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='本月消费(元)')),
|
||
('spending_updated_at', models.DateTimeField(blank=True, null=True, verbose_name='消费更新时间')),
|
||
('remark', models.TextField(blank=True, verbose_name='备注')),
|
||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||
('updated_at', models.DateTimeField(auto_now=True)),
|
||
('volc_account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='iam_users', to='monitor.volcaccount')),
|
||
],
|
||
options={
|
||
'verbose_name': 'IAM 子账号',
|
||
'verbose_name_plural': 'IAM 子账号',
|
||
'db_table': 'airgate_iam_user',
|
||
'unique_together': {('volc_account', 'username')},
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='AlertRecord',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('alert_type', models.CharField(choices=[('warning', '告警'), ('disable', '自动停用'), ('error', '错误'), ('manual', '手动操作')], max_length=20, verbose_name='告警类型')),
|
||
('title', models.CharField(max_length=200, verbose_name='标题')),
|
||
('content', models.TextField(verbose_name='详情')),
|
||
('spending_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, verbose_name='触发时消费金额')),
|
||
('threshold_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, verbose_name='触发阈值')),
|
||
('notified', models.BooleanField(default=False, verbose_name='已通知')),
|
||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||
('iam_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='alerts', to='monitor.iamuser')),
|
||
],
|
||
options={
|
||
'verbose_name': '告警记录',
|
||
'verbose_name_plural': '告警记录',
|
||
'db_table': 'airgate_alert_record',
|
||
'ordering': ['-created_at'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='SpendingRecord',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('bill_period', models.CharField(db_index=True, max_length=7, verbose_name='账期 (YYYY-MM)')),
|
||
('amount', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='消费金额(元)')),
|
||
('detail', models.JSONField(blank=True, default=dict, verbose_name='消费明细')),
|
||
('updated_at', models.DateTimeField(auto_now=True)),
|
||
('iam_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='spending_records', to='monitor.iamuser')),
|
||
],
|
||
options={
|
||
'verbose_name': '消费记录',
|
||
'verbose_name_plural': '消费记录',
|
||
'db_table': 'airgate_spending_record',
|
||
'unique_together': {('iam_user', 'bill_period')},
|
||
},
|
||
),
|
||
]
|