Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/api/ai/billing/budgetConfig/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import request from '@/config/axios'

// AI 预算配置 VO
export interface BudgetConfigVO {
id: number
userId: number
periodType: string
currency: string
budgetAmount: number
budgetAmountYuan: number
alertThresholds: string
status: number
createTime: Date
}

// AI 预算配置 API
export const BudgetConfigApi = {
// 查询分页
getBudgetConfigPage: async (params: any) => {
return await request.get({ url: `/ai/budget-config/page`, params })
},

// 查询详情
getBudgetConfig: async (id: number) => {
return await request.get({ url: `/ai/budget-config/get?id=` + id })
},

// 新增
createBudgetConfig: async (data: BudgetConfigVO) => {
return await request.post({ url: `/ai/budget-config/create`, data })
},

// 修改
updateBudgetConfig: async (data: BudgetConfigVO) => {
return await request.put({ url: `/ai/budget-config/update`, data })
},

// 删除
deleteBudgetConfig: async (id: number) => {
return await request.delete({ url: `/ai/budget-config/delete?id=` + id })
}
}
25 changes: 25 additions & 0 deletions src/api/ai/billing/budgetLog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import request from '@/config/axios'

// AI 预算事件日志 VO
export interface BudgetLogVO {
id: number
userId: number
eventType: string
periodStartTime: Date
currency: string
budgetAmount: number
usedAmount: number
deltaAmount: number
requestBizType: string
requestBizId: number
message: string
createTime: Date
}

// AI 预算事件日志 API
export const BudgetLogApi = {
// 查询分页
getBudgetLogPage: async (params: any) => {
return await request.get({ url: `/ai/budget-log/page`, params })
}
}
23 changes: 23 additions & 0 deletions src/api/ai/billing/budgetUsage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import request from '@/config/axios'

// AI 预算使用情况 VO
export interface BudgetUsageVO {
userId: number
periodStartTime: Date
currency: string
usedAmount: number
usedAmountYuan: number
budgetAmount: number
budgetAmountYuan: number
remainAmount: number
remainAmountYuan: number
usagePercent: number
}

// AI 预算使用情况 API
export const BudgetUsageApi = {
// 查询当前周期预算使用情况
getBudgetUsage: async (userId: number) => {
return await request.get({ url: `/ai/budget-usage/get?userId=` + userId })
}
}
61 changes: 61 additions & 0 deletions src/api/ai/billing/modelCallLog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import request from '@/config/axios'

// AI 模型调用日志 VO
export interface ModelCallLogVO {
id: number
userId: number
platform: string
modelId: number
model: string
bizType: string
bizId: number
conversationId: number
requestTime: Date
responseTime: Date
durationMs: number
status: string
errorMessage: string
promptTokens: number
completionTokens: number
totalTokens: number
cachedTokens: number
reasoningTokens: number
tokenSource: string
currency: string
priceInPer1m: number
priceOutPer1m: number
costAmount: number
blocked: boolean
createTime: Date
}

// AI 调用日志统计 VO
export interface ModelCallLogStatVO {
totalCount: number
successCount: number
failCount: number
totalPromptTokens: number
totalCompletionTokens: number
totalTokens: number
totalCostAmount: number
totalCostAmountYuan: number
avgDurationMs: number
}

// AI 模型调用日志 API
export const ModelCallLogApi = {
// 查询分页
getModelCallLogPage: async (params: any) => {
return await request.get({ url: `/ai/model-call-log/page`, params })
},

// 查询统计
getModelCallLogStat: async (params: any) => {
return await request.get({ url: `/ai/model-call-log/stat`, params })
},

// 导出
exportModelCallLog: async (params: any) => {
return await request.download({ url: `/ai/model-call-log/export-excel`, params })
}
}
42 changes: 42 additions & 0 deletions src/api/ai/billing/modelPricing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import request from '@/config/axios'

// AI 模型计费配置 VO
export interface ModelPricingVO {
id: number
modelId: number
currency: string
priceInPer1mYuan: number
priceCachedPer1mYuan: number
priceOutPer1mYuan: number
priceReasoningPer1mYuan: number
status: number
createTime: Date
}

// AI 模型计费配置 API
export const ModelPricingApi = {
// 查询分页
getModelPricingPage: async (params: any) => {
return await request.get({ url: `/ai/model-pricing/page`, params })
},

// 查询详情
getModelPricing: async (id: number) => {
return await request.get({ url: `/ai/model-pricing/get?id=` + id })
},

// 新增
createModelPricing: async (data: ModelPricingVO) => {
return await request.post({ url: `/ai/model-pricing/create`, data })
},

// 修改
updateModelPricing: async (data: ModelPricingVO) => {
return await request.put({ url: `/ai/model-pricing/update`, data })
},

// 删除
deleteModelPricing: async (id: number) => {
return await request.delete({ url: `/ai/model-pricing/delete?id=` + id })
}
}
109 changes: 109 additions & 0 deletions src/views/ai/billing/budgetConfig/BudgetConfigForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" v-loading="formLoading">
<el-form-item label="用户编号" prop="userId">
<el-input-number v-model="formData.userId" :min="0" class="!w-1/1" placeholder="0 表示租户级预算" />
</el-form-item>
<el-form-item label="周期类型" prop="periodType">
<el-select v-model="formData.periodType" placeholder="请选择" clearable>
<el-option label="月度" value="MONTHLY" />
<el-option label="每日" value="DAILY" />
</el-select>
</el-form-item>
<el-form-item label="预算金额(元)" prop="budgetAmountYuan">
<el-input-number v-model="formData.budgetAmountYuan" :min="0" :precision="2" class="!w-1/1" placeholder="请输入预算金额" />
</el-form-item>
<el-form-item label="告警阈值" prop="alertThresholds">
<el-input v-model="formData.alertThresholds" placeholder="例如 [80,90,100]" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</template>
</Dialog>
</template>

<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { BudgetConfigApi, BudgetConfigVO } from '@/api/ai/billing/budgetConfig'
import { CommonStatusEnum } from '@/utils/constants'

defineOptions({ name: 'BudgetConfigForm' })

const { t } = useI18n()
const message = useMessage()

const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref({
id: undefined,
userId: 0,
periodType: 'MONTHLY',
budgetAmountYuan: undefined,
alertThresholds: '[80,90,100]',
status: CommonStatusEnum.ENABLE
})
const formRules = reactive({
userId: [{ required: true, message: '用户编号不能为空', trigger: 'blur' }],
periodType: [{ required: true, message: '周期类型不能为空', trigger: 'blur' }],
budgetAmountYuan: [{ required: true, message: '预算金额不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
const formRef = ref()

const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (id) {
formLoading.value = true
try {
formData.value = await BudgetConfigApi.getBudgetConfig(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open })

const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = formData.value as unknown as BudgetConfigVO
if (formType.value === 'create') {
await BudgetConfigApi.createBudgetConfig(data)
message.success(t('common.createSuccess'))
} else {
await BudgetConfigApi.updateBudgetConfig(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}

const resetForm = () => {
formData.value = {
id: undefined,
userId: 0,
periodType: 'MONTHLY',
budgetAmountYuan: undefined,
alertThresholds: '[80,90,100]',
status: CommonStatusEnum.ENABLE
}
formRef.value?.resetFields()
}
</script>
Loading