Commit 167cacff by Jony.L

Merge remote-tracking branch 'origin/fixbug' into develop

parents 3f6d4c2d 222d9ef6
...@@ -20,6 +20,11 @@ export const ApiEndpointRelApi = { ...@@ -20,6 +20,11 @@ export const ApiEndpointRelApi = {
return await request.get({ url: `/apihub/api-endpoint-rel/get?id=` + id }) return await request.get({ url: `/apihub/api-endpoint-rel/get?id=` + id })
}, },
// 根据接口ID查询关联的API应用
getApisByEndpointId: async (apiEndpointId: number) => {
return await request.get({ url: `/apihub/api-endpoint-rel/list-by-endpoint?apiEndpointId=` + apiEndpointId })
},
// 新增API 应用与接口关系 // 新增API 应用与接口关系
createApiEndpointRel: async (data: ApiEndpointRel) => { createApiEndpointRel: async (data: ApiEndpointRel) => {
return await request.post({ url: `/apihub/api-endpoint-rel/create`, data }) return await request.post({ url: `/apihub/api-endpoint-rel/create`, data })
......
...@@ -101,12 +101,12 @@ ...@@ -101,12 +101,12 @@
</el-card> </el-card>
</el-col> </el-col>
<!-- 第三个图表:折线图--> <!-- 算力订单统计图表 -->
<el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24"> <el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
<div style="display: flex; justify-content: flex-end; margin-bottom: 10px;"> <div style="display: flex; justify-content: flex-end; margin-bottom: 10px;">
<el-radio-group <el-radio-group
v-model="orderDateType" v-model="computeOrderDateType"
@change="handleOrderDateDateTypeChange" @change="handleComputeOrderDateTypeChange"
size="small" size="small"
> >
<el-radio label="d">日数据(近7天)</el-radio> <el-radio label="d">日数据(近7天)</el-radio>
...@@ -116,7 +116,27 @@ ...@@ -116,7 +116,27 @@
</div> </div>
<el-card shadow="hover" class="mb-8px"> <el-card shadow="hover" class="mb-8px">
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<Echart :options="orderChartOptions" :height="420"/> <Echart :options="computeOrderChartOptions" :height="420"/>
</el-skeleton>
</el-card>
</el-col>
<!-- API订单统计图表 -->
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
<div style="display: flex; justify-content: flex-end; margin-bottom: 10px;">
<el-radio-group
v-model="apiOrderDateType"
@change="handleApiOrderDateTypeChange"
size="small"
>
<el-radio label="d">日数据(近7天)</el-radio>
<el-radio label="m">月数据(近30天)</el-radio>
<el-radio label="y">年数据(近12个月)</el-radio>
</el-radio-group>
</div>
<el-card shadow="hover" class="mb-8px">
<el-skeleton :loading="loading" animated>
<Echart :options="apiOrderChartOptions" :height="420"/>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
...@@ -154,7 +174,8 @@ const username = userStore.getUser.nickname ...@@ -154,7 +174,8 @@ const username = userStore.getUser.nickname
// 切换状态(d=日,m=月) // 切换状态(d=日,m=月)
const userDateType = ref('d'); const userDateType = ref('d');
const apiCallsDateType = ref('d'); const apiCallsDateType = ref('d');
const orderDateType = ref('d'); const computeOrderDateType = ref('d');
const apiOrderDateType = ref('d');
const handleUserDateTypeChange = () => { const handleUserDateTypeChange = () => {
getUsersChartData(userDateType.value); getUsersChartData(userDateType.value);
...@@ -165,8 +186,12 @@ const handleApiCallsDateTypeChange = () => { ...@@ -165,8 +186,12 @@ const handleApiCallsDateTypeChange = () => {
getApiCallsChartData(apiCallsDateType.value); getApiCallsChartData(apiCallsDateType.value);
} }
const handleOrderDateDateTypeChange = () => { const handleComputeOrderDateTypeChange = () => {
getOrderChartData(orderDateType.value); getComputeOrderChartData(computeOrderDateType.value);
}
const handleApiOrderDateTypeChange = () => {
getApiOrderChartData(apiOrderDateType.value);
} }
// 统计数据 // 统计数据
...@@ -250,10 +275,10 @@ const getApiCallsChartData = async (apiCallsDateType) => { ...@@ -250,10 +275,10 @@ const getApiCallsChartData = async (apiCallsDateType) => {
apiCallChartOptions.value.series![0].data = data.map(item => item.callsCount) apiCallChartOptions.value.series![0].data = data.map(item => item.callsCount)
} }
//订单折线图配置 // 算力订单折线图配置
const orderChartOptions = ref<EChartsOption>({ const computeOrderChartOptions = ref<EChartsOption>({
title: { title: {
text: '订单相关统计', text: '算力订单统计',
left: 'center' left: 'center'
}, },
tooltip: { tooltip: {
...@@ -284,24 +309,7 @@ const orderChartOptions = ref<EChartsOption>({ ...@@ -284,24 +309,7 @@ const orderChartOptions = ref<EChartsOption>({
itemStyle: { itemStyle: {
color: '#67C23A' // 自定义颜色 color: '#67C23A' // 自定义颜色
} }
}, {
name: 'API订单',
data: [], // 后续会动态填充
type: 'line', // 明确指定为折线图
smooth: false, // 平滑曲线
itemStyle: {
color: '#409EFF' // 自定义颜色
}
}, {
name: '总订单',
data: [], // 后续会动态填充
type: 'line', // 明确指定为折线图
smooth: false, // 平滑曲线
itemStyle: {
color: '#F59E0B' // 自定义颜色
}
}, },
// ---------------------- 新增3个金额系列(都绑右侧轴)----------------------
{ {
name: '算力订单金额', name: '算力订单金额',
data: [], // 算力金额数据 data: [], // 算力金额数据
...@@ -309,6 +317,44 @@ const orderChartOptions = ref<EChartsOption>({ ...@@ -309,6 +317,44 @@ const orderChartOptions = ref<EChartsOption>({
smooth: false, smooth: false,
itemStyle: {color: '#94D274'}, // 浅绿(和算力订单数颜色呼应) itemStyle: {color: '#94D274'}, // 浅绿(和算力订单数颜色呼应)
yAxisIndex: 1 // 关键:绑右侧金额轴 yAxisIndex: 1 // 关键:绑右侧金额轴
}
]
})
// API订单折线图配置
const apiOrderChartOptions = ref<EChartsOption>({
title: {
text: 'API订单统计',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: [] // 后续会动态填充
},
yAxis: [
{
type: 'value',
name: '订单数量'
},
{
// 右Y轴:金额(新增轴,index=1)
type: 'value',
name: '金额(元)', // 轴名称
position: 'right' // 放在右侧
}
],
series: [
{
name: 'API订单',
data: [], // 后续会动态填充
type: 'line', // 明确指定为折线图
smooth: false, // 平滑曲线
itemStyle: {
color: '#409EFF' // 自定义颜色
}
}, },
{ {
name: 'API订单金额', name: 'API订单金额',
...@@ -317,29 +363,26 @@ const orderChartOptions = ref<EChartsOption>({ ...@@ -317,29 +363,26 @@ const orderChartOptions = ref<EChartsOption>({
smooth: false, smooth: false,
itemStyle: {color: '#7CB6FF'}, // 浅蓝(和API订单数颜色呼应) itemStyle: {color: '#7CB6FF'}, // 浅蓝(和API订单数颜色呼应)
yAxisIndex: 1 // 绑右侧金额轴 yAxisIndex: 1 // 绑右侧金额轴
},
{
name: '总金额',
data: [], // 总金额数据
type: 'line',
smooth: false,
itemStyle: {color: '#FFC53D'}, // 浅黄(和总订单数颜色呼应)
yAxisIndex: 1 // 绑右侧金额轴
} }
] ]
}) })
//订单折线图数据 // 算力订单折线图数据
const getOrderChartData = async (orderDateType) => { const getComputeOrderChartData = async (orderDateType) => {
let ordersData = await IndexCountApi.getOrdersData(orderDateType);
computeOrderChartOptions.value.xAxis!.data = ordersData.map(item => t(item.countDate))
computeOrderChartOptions.value.series![0].data = ordersData.map(item => item.computeOrdersCount)
computeOrderChartOptions.value.series![1].data = ordersData.map(item => item.computeOrdersAmount)
}
// API订单折线图数据
const getApiOrderChartData = async (orderDateType) => {
let ordersData = await IndexCountApi.getOrdersData(orderDateType); let ordersData = await IndexCountApi.getOrdersData(orderDateType);
orderChartOptions.value.xAxis!.data = ordersData.map(item => t(item.countDate)) apiOrderChartOptions.value.xAxis!.data = ordersData.map(item => t(item.countDate))
orderChartOptions.value.series![0].data = ordersData.map(item => item.computeOrdersCount) apiOrderChartOptions.value.series![0].data = ordersData.map(item => item.apiOrdersCount)
orderChartOptions.value.series![1].data = ordersData.map(item => item.apiOrdersCount) apiOrderChartOptions.value.series![1].data = ordersData.map(item => item.apiOrdersAmount)
orderChartOptions.value.series![2].data = ordersData.map(item => item.totalOrdersCount)
orderChartOptions.value.series![3].data = ordersData.map(item => item.computeOrdersAmount)
orderChartOptions.value.series![4].data = ordersData.map(item => item.apiOrdersAmount)
orderChartOptions.value.series![5].data = ordersData.map(item => item.totalOrdersAmount)
} }
// 初始化数据 // 初始化数据
...@@ -348,7 +391,8 @@ const initData = async () => { ...@@ -348,7 +391,8 @@ const initData = async () => {
getCount(), getCount(),
getUsersChartData(userDateType.value), getUsersChartData(userDateType.value),
getApiCallsChartData(apiCallsDateType.value), getApiCallsChartData(apiCallsDateType.value),
getOrderChartData(orderDateType.value) getComputeOrderChartData(computeOrderDateType.value),
getApiOrderChartData(apiOrderDateType.value)
]) ])
loading.value = false loading.value = false
} }
......
...@@ -24,7 +24,12 @@ ...@@ -24,7 +24,12 @@
oninput="this.value = this.value.replace(/\D/g,'')" oninput="this.value = this.value.replace(/\D/g,'')"
/> />
</el-form-item> </el-form-item>
<el-form-item label="是否上架" prop="isShelf">
<el-radio-group v-model="formData.isShelf">
<el-radio :label="true">已上架</el-radio>
<el-radio :label="false">未上架</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="关联行业应用"> <el-form-item label="关联行业应用">
<!-- 添加接口按钮独占一行 --> <!-- 添加接口按钮独占一行 -->
...@@ -94,6 +99,7 @@ ...@@ -94,6 +99,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ApiEndpointApi, ApiEndpoint, IndustryApplication} from '@/api/apihub/apiendpoint' import { ApiEndpointApi, ApiEndpoint, IndustryApplication} from '@/api/apihub/apiendpoint'
import { ApiEndpointRelApi } from '@/api/apihub/apiendpointrel'
/** API 接口 表单 */ /** API 接口 表单 */
defineOptions({ name: 'ApiEndpointForm' }) defineOptions({ name: 'ApiEndpointForm' })
...@@ -111,14 +117,13 @@ const formData = ref({ ...@@ -111,14 +117,13 @@ const formData = ref({
path: undefined, path: undefined,
method: undefined, method: undefined,
consumptionPoints: undefined, consumptionPoints: undefined,
industryApplications: [ industryApplications: [],
{ title: 'AI诗词', image: 'https://', id: null } isShelf: undefined
]
// params: undefined, // params: undefined,
// response: undefined, // response: undefined,
// authType: undefined, // authType: undefined,
// rateLimit: undefined, // rateLimit: undefined,
// remark: undefined // remark: undefined
}) })
const formRules = reactive({ const formRules = reactive({
name: [{ required: true, message: '接口名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '接口名称不能为空', trigger: 'blur' }],
...@@ -142,10 +147,6 @@ const open = async (type: string, id?: number) => { ...@@ -142,10 +147,6 @@ const open = async (type: string, id?: number) => {
formLoading.value = true formLoading.value = true
try { try {
const res = await ApiEndpointApi.getApiEndpoint(id) const res = await ApiEndpointApi.getApiEndpoint(id)
// 确保 industryApplications 至少有一行
if (!res.industryApplications || res.industryApplications.length === 0) {
res.industryApplications = [{ title: '', image: '', id: null }]
}
formData.value = res formData.value = res
} finally { } finally {
formLoading.value = false formLoading.value = false
...@@ -159,6 +160,30 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成 ...@@ -159,6 +160,30 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成
const submitForm = async () => { const submitForm = async () => {
// 校验表单 // 校验表单
await formRef.value.validate() await formRef.value.validate()
// 如果处于上架状态,检查是否被API关联(适用于创建和修改)
if (formData.value.isShelf) {
// 对于修改操作,需要检查是否有API关联
if (formData.value.id) {
try {
const relatedApis = await ApiEndpointRelApi.getApisByEndpointId(formData.value.id)
if (!relatedApis || relatedApis.length === 0) {
// 若不满足条件,给出错误提示并终止提交
message.error('上架状态下,接口必须被至少一个API关联')
return
}
} catch (e) {
console.error('检查API关联失败', e)
message.error('检查API关联失败,请稍后再试')
return
}
} else {
// 对于新建操作,不允许直接上架,因为新建的接口还没有被API关联
message.error('新建接口不能直接上架,请先创建接口并关联到API后再上架')
return
}
}
// 提交请求 // 提交请求
formLoading.value = true formLoading.value = true
try { try {
...@@ -186,9 +211,8 @@ const resetForm = () => { ...@@ -186,9 +211,8 @@ const resetForm = () => {
path: undefined, path: undefined,
method: undefined, method: undefined,
consumptionPoints: undefined, consumptionPoints: undefined,
industryApplications: [ industryApplications: [],
{ title: 'AI诗词', image: 'https://', id: null } isShelf: undefined
]
// params: undefined, // params: undefined,
// response: undefined, // response: undefined,
// authType: undefined, // authType: undefined,
......
...@@ -153,6 +153,13 @@ ...@@ -153,6 +153,13 @@
:formatter="dateFormatter" :formatter="dateFormatter"
width="180px" width="180px"
/> />
<el-table-column label="是否上架" align="center" prop="isShelf">
<template #default="scope">
<span :class="{ 'shelved': scope.row.isShelf, 'unshelved':!scope.row.isShelf }">
{{ scope.row.isShelf? '已上架' : '未上架' }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" min-width="120px"> <el-table-column label="操作" align="center" min-width="120px">
<template #default="scope"> <template #default="scope">
<el-button <el-button
...@@ -297,4 +304,4 @@ const handleExport = async () => { ...@@ -297,4 +304,4 @@ const handleExport = async () => {
onMounted(() => { onMounted(() => {
getList() getList()
}) })
</script> </script>
\ No newline at end of file
...@@ -15,24 +15,24 @@ ...@@ -15,24 +15,24 @@
的文件 的文件
</p> </p>
</el-form-item> </el-form-item>
<el-form-item label="内容" prop="information"> <!-- <el-form-item label="内容" prop="information">
<el-input v-model="formData.information" placeholder="请输入内容" /> <el-input v-model="formData.information" placeholder="请输入内容" />
</el-form-item> </el-form-item>-->
<el-form-item label="标题" prop="title"> <!-- <el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题" /> <el-input v-model="formData.title" placeholder="请输入标题" />
</el-form-item> </el-form-item>-->
<el-form-item label="链接地址" prop="url"> <el-form-item label="链接地址" prop="url">
<el-input v-model="formData.url" placeholder="请输入链接地址" /> <el-input v-model="formData.url" placeholder="请输入链接地址" />
</el-form-item> </el-form-item>
<el-form-item label="描述内容" prop="description"> <!-- <el-form-item label="描述内容" prop="description">
<!-- <Editor v-model="formData.description" height="150px" />--> <Editor v-model="formData.description" height="150px" />
<el-input <el-input
v-model="formData.description" v-model="formData.description"
:rows="2" :rows="2"
type="textarea" type="textarea"
placeholder="请输入描述内容" placeholder="请输入描述内容"
/> />
</el-form-item> </el-form-item>-->
<el-form-item label="排序值" prop="orderNum"> <el-form-item label="排序值" prop="orderNum">
<el-input v-model="formData.orderNum" placeholder="请输入排序值" /> <el-input v-model="formData.orderNum" placeholder="请输入排序值" />
</el-form-item> </el-form-item>
...@@ -89,8 +89,8 @@ const formData = ref({ ...@@ -89,8 +89,8 @@ const formData = ref({
remark: undefined remark: undefined
}) })
const formRules = reactive({ const formRules = reactive({
information: [{ required: true, message: '内容不能为空', trigger: 'blur' }], //information: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }], //title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
showStatus: [{ required: true, message: '状态不能为空', trigger: 'blur' }], showStatus: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
orderNum: [{ required: true, message: '排序值不能为空', trigger: 'blur' }] orderNum: [{ required: true, message: '排序值不能为空', trigger: 'blur' }]
}) })
......
...@@ -103,10 +103,10 @@ ...@@ -103,10 +103,10 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="内容" align="center" prop="information" /> <!-- <el-table-column label="内容" align="center" prop="information" />-->
<el-table-column label="标题" align="center" prop="title" /> <!-- <el-table-column label="标题" align="center" prop="title" />-->
<el-table-column label="链接地址" align="center" prop="url" /> <el-table-column label="链接地址" align="center" prop="url" />
<el-table-column label="描述内容" align="center" prop="description" /> <!-- <el-table-column label="描述内容" align="center" prop="description" />-->
<el-table-column label="状态" align="center" prop="showStatus"> <el-table-column label="状态" align="center" prop="showStatus">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.HOME_INFO_STATUS" :value="Number(scope.row.showStatus)" /> <dict-tag :type="DICT_TYPE.HOME_INFO_STATUS" :value="Number(scope.row.showStatus)" />
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
<el-form-item label="链接地址" prop="url"> <el-form-item label="链接地址" prop="url">
<el-input v-model="formData.url" placeholder="请输入链接地址" /> <el-input v-model="formData.url" placeholder="请输入链接地址" />
</el-form-item> </el-form-item>
<el-form-item label="描述内容" prop="description"> <!-- <el-form-item label="描述内容" prop="description">
<Editor v-model="formData.description" height="150px" /> <Editor v-model="formData.description" height="150px" />
</el-form-item> </el-form-item>-->
<!-- <el-form-item label="计算资源应用类别" prop="category">--> <!-- <el-form-item label="计算资源应用类别" prop="category">-->
<!-- <el-select--> <!-- <el-select-->
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
<el-table-column label="内容" align="center" prop="information" /> <el-table-column label="内容" align="center" prop="information" />
<el-table-column label="标题" align="center" prop="title" /> <el-table-column label="标题" align="center" prop="title" />
<el-table-column label="链接地址" align="center" prop="url" /> <el-table-column label="链接地址" align="center" prop="url" />
<el-table-column label="描述内容" align="center" prop="description" /> <!-- <el-table-column label="描述内容" align="center" prop="description" />-->
<!-- <el-table-column label="计算资源应用类别" align="center" prop="category">--> <!-- <el-table-column label="计算资源应用类别" align="center" prop="category">-->
<!-- <template #default="scope">--> <!-- <template #default="scope">-->
<!-- <dict-tag :type="DICT_TYPE.HOME_INFO_COMPUTILITY_TYPE" :value="scope.row.category" />--> <!-- <dict-tag :type="DICT_TYPE.HOME_INFO_COMPUTILITY_TYPE" :value="scope.row.category" />-->
......
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
<el-form-item label="标题" prop="title"> <el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题" /> <el-input v-model="formData.title" placeholder="请输入标题" />
</el-form-item> </el-form-item>
<el-form-item label="链接地址" prop="url"> <!-- <el-form-item label="链接地址" prop="url">
<el-input v-model="formData.url" placeholder="请输入链接地址" /> <el-input v-model="formData.url" placeholder="请输入链接地址" />
</el-form-item> </el-form-item>-->
<el-form-item label="描述内容" prop="description"> <el-form-item label="描述内容" prop="description">
<Editor v-model="formData.description" height="150px" /> <Editor v-model="formData.description" height="150px" />
</el-form-item> </el-form-item>
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
</p> </p>
</el-form-item> </el-form-item>
<el-form-item label="组件类型" prop="assemblyType"> <!-- <el-form-item label="组件类型" prop="assemblyType">
<el-select <el-select
v-model="formData.assemblyType" v-model="formData.assemblyType"
placeholder="请选择组件类型" placeholder="请选择组件类型"
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
:value="dict.value" :value="dict.value"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>-->
<el-form-item label="排序值" prop="orderNum"> <el-form-item label="排序值" prop="orderNum">
<el-input v-model="formData.orderNum" placeholder="请输入排序值" /> <el-input v-model="formData.orderNum" placeholder="请输入排序值" />
......
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
<!-- <el-table-column label="首页展示图片" align="center" prop="homeImage" />--> <!-- <el-table-column label="首页展示图片" align="center" prop="homeImage" />-->
<el-table-column label="内容" align="center" prop="information" /> <el-table-column label="内容" align="center" prop="information" />
<el-table-column label="标题" align="center" prop="title" /> <el-table-column label="标题" align="center" prop="title" />
<el-table-column label="链接地址" align="center" prop="url" /> <!-- <el-table-column label="链接地址" align="center" prop="url" />-->
<!-- <el-table-column label="组件类型" align="center" prop="assemblyType">--> <!-- <el-table-column label="组件类型" align="center" prop="assemblyType">-->
<!-- <template #default="scope">--> <!-- <template #default="scope">-->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment