Commit d68ac293 by Jony.L

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

parents 6b53c619 a2e8bcf4
import request from '@/utils/request.js'
// 查询api使用记录
export function getApiCallLog (query) {
return request({
url: '/apihub/api-call-log/page',
method: 'get',
params: query
})
}
// 查询api使用记录详细
export function getApiCallLogDetail (id) {
return request({
url: '/apihub/api-call-log/' + id,
method: 'get'
})
}
...@@ -9,6 +9,16 @@ export function listResources(query) { ...@@ -9,6 +9,16 @@ export function listResources(query) {
}) })
} }
// 查询-api资源管理列表
export function listApiResources(query) {
return request({
url: '/apihub/user-api-usage/page',
method: 'get',
params: query
})
}
// 查询订单管理-用户资源管理详细 // 查询订单管理-用户资源管理详细
export function getResources(query) { export function getResources(query) {
return request({ return request({
......
...@@ -18,3 +18,12 @@ export function auditInfo(query) { ...@@ -18,3 +18,12 @@ export function auditInfo(query) {
data: query data: query
}) })
} }
// 根据用户查询AppId和AppSecret
export function appInfo() {
return request({
url: '/apihub/app-credential/get',
method: 'get',
})
}
...@@ -232,6 +232,18 @@ export const constantRoutes = [ ...@@ -232,6 +232,18 @@ export const constantRoutes = [
component: ManageLayout, component: ManageLayout,
children: [ children: [
{ {
path: 'apiCallLog',
component: () => import('@/views/console/apiCallLog.vue'),
name: 'ApiCallLog',
meta: {title: 'API使用记录', icon: 'order'}
}
]
},
{
path: '/console',
component: ManageLayout,
children: [
{
path: 'apiResources', path: 'apiResources',
component: () => import('@/views/console/apiResources.vue'), component: () => import('@/views/console/apiResources.vue'),
name: 'ApiResources', name: 'ApiResources',
......
<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="接口名称" prop="apiEndpointName">
<el-input
v-model="queryParams.apiEndpointName"
placeholder="请输入接口名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"
>搜索
</el-button
>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="apiCallLogList"
:max-height="620"
>
<!--<el-table-column type="selection" width="45" align="center"/>-->
<!--<el-table-column label="序号" align="center" prop="id"/>-->
<el-table-column label="接口名称" align="center" prop="apiEndpointName"/>
<el-table-column label="请求方式" align="center" prop="method"/>
<el-table-column label="请求接口" align="center" prop="path"/>
<el-table-column label="请求参数" align="center" prop="requestParams" width="200">
<template #default="scope">
<el-tooltip class="item" effect="dark" :content="scope.row.requestParams" placement="top">
<div class="ellipsis-text">{{ scope.row.requestParams }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="返回结果" align="center" prop="responseParams" width="200">
<template #default="scope">
<el-tooltip class="item" effect="dark" :content="scope.row.responseParams" placement="top">
<div class="ellipsis-text">{{ scope.row.responseParams }}</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="请求时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<!-- <el-table-column-->
<!-- label="操作"-->
<!-- align="center"-->
<!-- fixed="right"-->
<!-- class-name="small-padding fixed-width">-->
<!-- <template #default="scope">-->
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- @click="handleDetails(scope.row)"-->
<!-- >-->
<!-- 详情-->
<!-- </el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改管理-需求单管理对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<div>
<div class="info-block">
<div class="info-item flex-align-center flex-space-between">
<div class="label">商品名称</div>
<div class="value">{{ form.spuName }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">订单编号</div>
<div class="value">{{ form.no }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">费用</div>
<div class="value">{{ form.payPrice ? (form.payPrice / 100) : '-' }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">商品类别</div>
<div class="value">{{ form.categoryName }}</div>
</div>
</div>
<div class="info-block">
<div class="info-item flex-align-center flex-space-between" v-for="(i,index) in form.properties"
:key="i.index">
<div class="label">{{ i.propertyName }}</div>
<div class="value">{{ i.valueName }}</div>
</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">订单状态</div>
<div class="value">{{ form.statusName }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">下单时间</div>
<div class="value">{{ parseTime(form.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ApiCallLog">
import {
getApiCallLog ,getApiCallLogDetail
} from '@/api/apicalllog.js'
import {parseTime} from "../../utils/ruoyi.js";
const {proxy} = getCurrentInstance()
const apiCallLogList = ref([])
const open = ref(false)
const sOpen = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const total = ref(0)
const title = ref('')
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 10,
path: null,
searchQuery: null,
status: null
},
})
const {queryParams, form} = toRefs(data)
/** 查询使用记录 */
function loadList() {
loading.value = true
getApiCallLog(queryParams.value).then((response) => {
apiCallLogList.value = response.data.list
total.value = response.data.total
loading.value = false
})
}
// 取消按钮
function cancel() {
open.value = false
reset()
}
// 表单重置
function reset() {
form.value = {
searchQuery: null,
status: null
}
proxy.resetForm('queryRef')
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
loadList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm('queryRef')
handleQuery()
}
function handleDetails(row) {
const _id = row.id || ids.value
// getResources({id: _id}).then(response => {
// form.value = response.data
open.value = true
title.value = '查看使用记录详情'
// })
}
loadList()
</script>
<style lang="scss" scoped>
.el-form {
padding: 20px 20px 0 20px;
border-radius: 4px;
background-color: #FFFFFF;
margin-bottom: 20px;
}
.pagination-container {
background-color: transparent;
}
.info-block {
background-color: #ffffff;
padding: 4px 0;
//margin-bottom: 14px;
}
.info-item {
padding: 12px 20px;
.label {
font-weight: 400;
font-size: 16px;
color: #626566;
}
.value {
font-weight: bold;
font-size: 16px;
color: #303233;
}
}
.ellipsis-text {
max-width: 180px; // 控制宽度
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
<el-form-item label="高级查询" prop="searchQuery"> <el-form-item label="高级查询" prop="searchQuery">
<el-input <el-input
v-model="queryParams.searchQuery" v-model="queryParams.searchQuery"
placeholder="请输入api名称/订单编号" placeholder="请输入应用名称/订单编号"
clearable clearable
style="width: 200px" style="width: 200px"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
...@@ -103,13 +103,17 @@ ...@@ -103,13 +103,17 @@
<!--<el-table-column type="selection" width="45" align="center"/>--> <!--<el-table-column type="selection" width="45" align="center"/>-->
<!--<el-table-column label="序号" align="center" prop="id"/>--> <!--<el-table-column label="序号" align="center" prop="id"/>-->
<el-table-column label="订单编号" align="center" prop="orderNo"/> <el-table-column label="订单编号" align="center" prop="orderNo"/>
<el-table-column label="api名称" align="center" prop="apiName"/> <el-table-column label="应用名称" align="center" prop="apiName"/>
<el-table-column label="资源包" align="center" prop="packageName"/> <el-table-column label="资源包" align="center" prop="packageName"/>
<el-table-column label="使用次数" align="center" prop="packageTimes"/> <el-table-column label="使用次数" align="center" prop="packageTimes"/>
<el-table-column label=有效期 align="center" prop="packageValidDays"/> <el-table-column label=有效期 align="center" prop="packageValidDays">
<template #default="scope">
{{ (scope.row.packageValidDays) }}
</template>
</el-table-column>
<el-table-column label="实付金额" align="center" prop="costPrice"> <el-table-column label="实付金额" align="center" prop="costPrice">
<template #default="scope"> <template #default="scope">
{{ scope.row.costPrice / 100 }} {{ (scope.row.costPrice / 100).toFixed(2) }}
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column label="商品类别" align="center" prop="category">--> <!-- <el-table-column label="商品类别" align="center" prop="category">-->
...@@ -164,7 +168,7 @@ ...@@ -164,7 +168,7 @@
<pagination <pagination
v-show="total > 0" v-show="total > 0"
:total="total" :total="total"
v-model:page="queryParams.pageNum" v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
......
<template> <template>
<div class="app-container"> <div class="app-container">
<el-table v-loading="loading" :data="resourcesList" :max-height="620"> <el-table v-loading="loading" :data="resourcesList" :max-height="620">
<el-table-column label="订单编号" align="center" prop="tradeOrderNo"/> <el-table-column label="应用名称" align="center" prop="apiName" width="150px" />
<el-table-column label="商品类别" align="center" prop="categoryName"/> <el-table-column label="套餐名称" align="center" prop="packageName" width="150px" />
<el-table-column <el-table-column label="套餐总量" align="center" prop="packageTimes" />
v-for="(item, index) in resourcesList[0]?.properties.length!==0?resourcesList[0]?.properties.slice(0,4):resourcesList[0]?.properties" <el-table-column label="有效时长" align="center" prop="packageValidDays">
:key="index"
:label="item.propertyName"
>
<template #default="{ row }">
{{ row.properties[index].valueName }}
</template>
</el-table-column>
<el-table-column label="申请时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="有效期限" align="center" prop="expTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.expTime, '{y}-{m}-{d}') }}</span> {{ scope.row.packageValidDays }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="已使用次数" align="center" prop="usedTimes" width="150px" />
<el-table-column
label="过期时间"
align="center"
prop="expireTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column
label="购买时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" @click="handleUpdate(scope.row,scope.$index)">详情</el-button> <el-button link type="primary" @click="handleUpdate(scope.row,scope.$index)">详情</el-button>
...@@ -38,56 +39,13 @@ ...@@ -38,56 +39,13 @@
@pagination="getList" @pagination="getList"
/> />
<!-- 添加或修改订单管理-用户资源管理对话框 -->
<el-dialog :title="title" v-model="open" width="800px" append-to-body>
<div>
<div class="info-block">
<div class="info-item flex-align-center flex-space-between">
<div class="label">订单编号</div>
<div class="value">{{ form.tradeOrderNo }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">商品类别</div>
<div class="value">{{ form.categoryName }}</div>
</div>
</div>
<div class="info-block">
<div class="info-item flex-align-center flex-space-between" v-for="(i,index) in form.properties"
:key="i.index">
<div class="label">{{ i.propertyName }}</div>
<div class="value">{{ i.valueName }}</div>
</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">申请时间</div>
<div class="value">{{ parseTime(form.createTime, '{y}-{m}-{d}') }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">有效期限</div>
<div class="value">{{ parseTime(form.expTime, '{y}-{m}-{d}') }}</div>
</div>
<div class="info-item flex-align-center flex-space-between">
<div class="label">鉴权信息</div>
<div class="value">{{ form.auth}}</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel">关闭</el-button>
</div>
</template>
</el-dialog>
</div> </div>
</template> </template>
<script setup name="NaturalResources"> <script setup name="NaturalResources">
import {listResources, getResources} from '@/api/computility/resources' import {listResources, getResources, listApiResources} from '@/api/computility/resources'
import {parseTime} from "../../utils/ruoyi.js"; import dayjs from 'dayjs'
const resourcesList = ref([]) const resourcesList = ref([])
const open = ref(false) const open = ref(false)
...@@ -109,7 +67,7 @@ const {queryParams, form} = toRefs(data) ...@@ -109,7 +67,7 @@ const {queryParams, form} = toRefs(data)
/** 查询订单管理-用户资源管理列表 */ /** 查询订单管理-用户资源管理列表 */
function getList() { function getList() {
loading.value = true loading.value = true
listResources(queryParams.value).then(response => { listApiResources(queryParams.value).then(response => {
resourcesList.value = response.data.list resourcesList.value = response.data.list
total.value = response.data.total total.value = response.data.total
loading.value = false loading.value = false
...@@ -131,6 +89,11 @@ function handleUpdate(row) { ...@@ -131,6 +89,11 @@ function handleUpdate(row) {
}) })
} }
const dateFormatter = (row, column, cellValue) => {
if (!cellValue) return ''
return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
}
getList() getList()
</script> </script>
......
...@@ -102,6 +102,43 @@ ...@@ -102,6 +102,43 @@
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<span>AppId和AppSecret</span>
</div>
</template>
<el-form-item label="AppSecret:">
<el-tooltip
effect="dark"
:content="appData.appId || '-'"
placement="top"
v-if="appData.appId"
>
<span class="secret-text">
{{ formatString(appData.appId) }}
</span>
</el-tooltip>
<span v-else>-</span>
</el-form-item>
<el-form-item label="AppSecret:">
<el-tooltip
effect="dark"
:content="appData.appSecret || '-'"
placement="top"
v-if="appData.appSecret"
>
<span class="secret-text">
{{ formatString(appData.appSecret) }}
</span>
</el-tooltip>
<span v-else>-</span>
</el-form-item>
</el-card>
</el-col>
<el-col :span="12">
<el-card shadow="never">
<template #header>
<div class="card-header">
<span>常见Q&A</span> <span>常见Q&A</span>
</div> </div>
</template> </template>
...@@ -121,17 +158,20 @@ ...@@ -121,17 +158,20 @@
</template> </template>
<script setup name="Overview"> <script setup name="Overview">
import {auditInfo} from '@/api/console.js' import {auditInfo, appInfo} from '@/api/console.js'
import {ref} from 'vue' import {ref} from 'vue'
import {ElMessageBox} from 'element-plus' import {ElMessageBox} from 'element-plus'
import {parseTime} from "../../utils/ruoyi.js"; import {parseTime} from "../../utils/ruoyi.js";
import {useDict} from "@/utils/dict.js"; import {useDict} from "@/utils/dict.js";
import {listData} from "@/api/system/dict/data.js"; import {listData} from "@/api/system/dict/data.js";
import {get} from "@vueuse/core";
// const {proxy} = getCurrentInstance(); // const {proxy} = getCurrentInstance();
// const {check_status} = proxy.useDict("check_status"); // const {check_status} = proxy.useDict("check_status");
const infoData = ref({}) const infoData = ref({})
const appData = ref({})
function getAuditInfo() { function getAuditInfo() {
auditInfo().then(res => { auditInfo().then(res => {
...@@ -139,6 +179,13 @@ function getAuditInfo() { ...@@ -139,6 +179,13 @@ function getAuditInfo() {
}) })
} }
function getAppInfo() {
appInfo().then(res => {
appData.value = res.data
})
}
/** 查看驳回理由按钮操作 */ /** 查看驳回理由按钮操作 */
function handleViewReason() { function handleViewReason() {
ElMessageBox.alert(infoData.value.remark, '驳回理由', { ElMessageBox.alert(infoData.value.remark, '驳回理由', {
...@@ -149,6 +196,16 @@ function handleViewReason() { ...@@ -149,6 +196,16 @@ function handleViewReason() {
} }
getAuditInfo() getAuditInfo()
getAppInfo()
// script setup 里加一个方法
function formatString(str) {
if (!str) return '-'
if (str.length <= 10) return secret
// 只显示前 4 位 + ... + 后 4 位
return `${str.slice(0, 4)}****${str.slice(-4)}`
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.remind { .remind {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<div class="search-box"> <div class="search-box">
<el-input <el-input
v-model="searchQuery" v-model="searchQuery"
placeholder="可输入API名称/分类名称" placeholder="可输入应用名称/分类名称"
@keyup.enter="handleSearch" @keyup.enter="handleSearch"
clearable clearable
> >
......
...@@ -104,10 +104,51 @@ ...@@ -104,10 +104,51 @@
<el-tab-pane label="应用说明" name="detail"></el-tab-pane> <el-tab-pane label="应用说明" name="detail"></el-tab-pane>
<el-tab-pane label="接口文档" name="doc"></el-tab-pane> <el-tab-pane label="接口文档" name="doc"></el-tab-pane>
</el-tabs> </el-tabs>
<div class="tab-content-area"> <div class="tab-content-area">
<div class="main-content" v-html="currentHtml"></div> <!-- 应用说明 tab -->
<div v-if="mainTab === 'detail'" class="main-content" v-html="currentHtml"></div>
<!-- 接口文档 tab -->
<div v-else-if="mainTab === 'doc'" class="main-content">
<!-- 接口 + 行业应用卡片 -->
<div class="api-endpoints">
<h2 class="section-title">接口列表</h2>
<div
v-for="endpoint in productData.apiEndPoints"
:key="endpoint.id"
class="endpoint-card"
>
<div class="endpoint-header">
<span class="endpoint-name">{{ endpoint.name }}</span>
<el-tag size="small" type="info">{{ endpoint.method }}</el-tag>
<span class="endpoint-path">{{ endpoint.path }}</span>
</div>
<!-- 行业应用 -->
<div v-if="endpoint.industryApplications?.length" class="applications">
<span class="label">行业应用:</span>
<el-tag
v-for="app in endpoint.industryApplications"
:key="app.id"
size="small"
type="success"
effect="light"
class="application-item"
@click="goToIndustryApplication(app.id)"
>
{{ app.title }}
</el-tag>
</div>
</div>
</div>
<!-- 接口文档 HTML -->
<div class="doc-content" v-html="productData.doc"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -115,7 +156,7 @@ ...@@ -115,7 +156,7 @@
<template #default> <template #default>
<div class="info-block"> <div class="info-block">
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between">
<div class="label">api名称</div> <div class="label">应用名称</div>
<div class="value">{{ productData.name }}</div> <div class="value">{{ productData.name }}</div>
</div> </div>
<div class="info-item flex-align-center flex-space-between"> <div class="info-item flex-align-center flex-space-between">
...@@ -556,6 +597,11 @@ const clearProtocol = () => { ...@@ -556,6 +597,11 @@ const clearProtocol = () => {
} }
function handleSolution(id) {
router.push(`/industryApplications/detail?id=${id}`)
}
// 暴露 goOrderConfirm 到模板 // 暴露 goOrderConfirm 到模板
defineExpose({ goOrderConfirm }); defineExpose({ goOrderConfirm });
</script> </script>
...@@ -977,5 +1023,66 @@ defineExpose({ goOrderConfirm }); ...@@ -977,5 +1023,66 @@ defineExpose({ goOrderConfirm });
} }
.api-endpoints {
margin-bottom: 20px;
.section-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 12px;
color: #333;
}
.endpoint-card {
border: 1px solid #e4e7ed;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
background: #fafafa;
.endpoint-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
.endpoint-name {
font-weight: bold;
font-size: 15px;
color: #333;
}
.endpoint-path {
color: #666;
font-size: 14px;
}
}
.applications {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 8px;
}
.application-item {
cursor: pointer; /* 鼠标变成手型 */
transition: all 0.3s; /* 平滑过渡 */
}
/* 鼠标悬停变色 */
.application-item:hover {
background-color: #67c23a !important; /* 可以自定义颜色 */
color: white !important;
border-color: #67c23a !important;
}
}
}
.doc-content {
margin-top: 20px;
}
</style> </style>
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