|
|
@@ -0,0 +1,419 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <el-card shadow="never" class="mb8">
|
|
|
+ <div slot="header">
|
|
|
+ <span>外部接口管理配置</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="70px">
|
|
|
+ <el-form-item label="接口类型">
|
|
|
+ <el-input v-model="queryParams.apiType" placeholder="请输入" clearable @keyup.enter.native="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="接口名称">
|
|
|
+ <el-input v-model="queryParams.apiName" placeholder="请输入" clearable @keyup.enter.native="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="接口编码">
|
|
|
+ <el-input v-model="queryParams.apiCode" placeholder="请输入" clearable @keyup.enter.native="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="状态">
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择" clearable style="width: 120px">
|
|
|
+ <el-option label="启用" :value="1" />
|
|
|
+ <el-option label="停用" :value="0" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
|
|
|
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <el-row :gutter="10" class="mb8">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增接口</el-button>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-table v-loading="loading" :data="list" border>
|
|
|
+ <el-table-column type="index" label="序号" width="60" />
|
|
|
+ <el-table-column prop="apiName" label="接口名称" min-width="160" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="apiCode" label="接口编码" min-width="160" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="apiType" label="接口类型" width="120" />
|
|
|
+ <el-table-column prop="apiUrl" label="请求地址" min-width="260" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="httpMethod" label="请求方式" width="110" />
|
|
|
+ <el-table-column label="限频规则" width="140">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span v-if="scope.row.rateMaxCount && scope.row.rateWindowSeconds">
|
|
|
+ {{ scope.row.rateMaxCount }}次/{{ formatWindow(scope.row.rateWindowSeconds) }}
|
|
|
+ </span>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="priority" label="优先级" width="90" />
|
|
|
+ <el-table-column label="状态" width="110">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-switch
|
|
|
+ v-model="scope.row.status"
|
|
|
+ :active-value="1"
|
|
|
+ :inactive-value="0"
|
|
|
+ @change="val => handleStatusChange(scope.row, val)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="260" fixed="right">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button type="text" size="mini" @click="handleTest(scope.row)">测试</el-button>
|
|
|
+ <el-button type="text" size="mini" @click="handleEdit(scope.row)">编辑</el-button>
|
|
|
+ <el-button type="text" size="mini" @click="handleLogs(scope.row)">日志</el-button>
|
|
|
+ <el-button type="text" size="mini" style="color:#F56C6C" @click="handleDelete(scope.row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total > 0"
|
|
|
+ :total="total"
|
|
|
+ :page.sync="queryParams.pageNum"
|
|
|
+ :limit.sync="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 新增/编辑 -->
|
|
|
+ <el-dialog :title="form.id ? '编辑接口' : '新增接口'" :visible.sync="openForm" width="720px" append-to-body>
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
|
|
|
+ <el-row :gutter="12">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="接口类型" prop="apiType">
|
|
|
+ <el-input v-model="form.apiType" placeholder="例如 WEATHER" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="接口名称" prop="apiName">
|
|
|
+ <el-input v-model="form.apiName" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="接口编码" prop="apiCode">
|
|
|
+ <el-input v-model="form.apiCode" :disabled="!!form.id" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="请求方式" prop="httpMethod">
|
|
|
+ <el-select v-model="form.httpMethod" placeholder="请选择" style="width:100%">
|
|
|
+ <el-option label="GET" value="GET" />
|
|
|
+ <el-option label="POST" value="POST" />
|
|
|
+ <el-option label="PUT" value="PUT" />
|
|
|
+ <el-option label="DELETE" value="DELETE" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="请求地址" prop="apiUrl">
|
|
|
+ <el-input v-model="form.apiUrl" placeholder="https://..." />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="限频窗口(秒)">
|
|
|
+ <el-input-number v-model="form.rateWindowSeconds" :min="1" :step="1" style="width:100%" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="窗口最大次数">
|
|
|
+ <el-input-number v-model="form.rateMaxCount" :min="1" :step="1" style="width:100%" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="优先级">
|
|
|
+ <el-input-number v-model="form.priority" :min="0" :step="1" style="width:100%" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="状态">
|
|
|
+ <el-select v-model="form.status" style="width:100%">
|
|
|
+ <el-option label="启用" :value="1" />
|
|
|
+ <el-option label="停用" :value="0" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="超时(ms)">
|
|
|
+ <el-input-number v-model="form.timeoutMs" :min="1000" :step="500" style="width:100%" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="默认请求头(JSON)">
|
|
|
+ <el-input v-model="form.defaultHeadersJson" type="textarea" :rows="3" placeholder='{"Content-Type":"application/json"}' />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="默认请求体(JSON)">
|
|
|
+ <el-input v-model="form.defaultBodyJson" type="textarea" :rows="4" placeholder='{"k":"v"}' />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="openForm = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitForm">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 测试 -->
|
|
|
+ <el-dialog title="测试接口" :visible.sync="openTest" width="760px" append-to-body>
|
|
|
+ <el-form :model="testForm" label-width="130px">
|
|
|
+ <el-form-item label="覆盖请求头(JSON)">
|
|
|
+ <el-input v-model="testForm.headersJson" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="覆盖请求体(JSON)">
|
|
|
+ <el-input v-model="testForm.bodyJson" type="textarea" :rows="4" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="覆盖超时(ms)">
|
|
|
+ <el-input-number v-model="testForm.timeoutMs" :min="1000" :step="500" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <el-divider content-position="left">响应</el-divider>
|
|
|
+ <el-descriptions :column="2" border size="small">
|
|
|
+ <el-descriptions-item label="状态码">{{ testResult.responseStatus || '-' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="耗时(ms)">{{ testResult.durationMs || '-' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="是否成功">{{ testResult.success === true ? '是' : (testResult.success === false ? '否' : '-') }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="错误信息">{{ testResult.errorMessage || '-' }}</el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ <el-input v-model="testResult.responseBody" type="textarea" :rows="10" readonly style="margin-top: 10px" />
|
|
|
+
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="openTest = false">关闭</el-button>
|
|
|
+ <el-button type="primary" :loading="testLoading" @click="doTest">开始测试</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 日志 -->
|
|
|
+ <el-dialog title="调用日志" :visible.sync="openLogs" width="980px" append-to-body>
|
|
|
+ <el-table v-loading="logsLoading" :data="logs" border height="520px">
|
|
|
+ <el-table-column type="index" label="序号" width="60" />
|
|
|
+ <el-table-column prop="createTime" label="时间" width="170" />
|
|
|
+ <el-table-column prop="httpMethod" label="方法" width="90" />
|
|
|
+ <el-table-column prop="requestUrl" label="URL" min-width="260" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="responseStatus" label="状态码" width="90" />
|
|
|
+ <el-table-column prop="durationMs" label="耗时(ms)" width="100" />
|
|
|
+ <el-table-column prop="success" label="成功" width="80">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.success === 1" type="success">成功</el-tag>
|
|
|
+ <el-tag v-else type="danger">失败</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="errorMessage" label="错误信息" min-width="160" show-overflow-tooltip />
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="logsTotal > 0"
|
|
|
+ :total="logsTotal"
|
|
|
+ :page.sync="logsQuery.pageNum"
|
|
|
+ :limit.sync="logsQuery.pageSize"
|
|
|
+ @pagination="getLogs"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="openLogs = false">关闭</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import {
|
|
|
+ pageExternalApi,
|
|
|
+ getExternalApi,
|
|
|
+ saveOrUpdateExternalApi,
|
|
|
+ changeExternalApiStatus,
|
|
|
+ deleteExternalApi,
|
|
|
+ testExternalApi,
|
|
|
+ pageExternalApiLogs
|
|
|
+} from '@/api/company/externalApi'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'CompanyWorkflowExternalApi',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ loading: false,
|
|
|
+ list: [],
|
|
|
+ total: 0,
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ apiType: undefined,
|
|
|
+ apiName: undefined,
|
|
|
+ apiCode: undefined,
|
|
|
+ status: undefined
|
|
|
+ },
|
|
|
+
|
|
|
+ openForm: false,
|
|
|
+ form: this.emptyForm(),
|
|
|
+ rules: {
|
|
|
+ apiType: [{ required: true, message: '接口类型不能为空', trigger: 'blur' }],
|
|
|
+ apiName: [{ required: true, message: '接口名称不能为空', trigger: 'blur' }],
|
|
|
+ apiCode: [{ required: true, message: '接口编码不能为空', trigger: 'blur' }],
|
|
|
+ apiUrl: [{ required: true, message: '请求地址不能为空', trigger: 'blur' }],
|
|
|
+ httpMethod: [{ required: true, message: '请求方式不能为空', trigger: 'change' }]
|
|
|
+ },
|
|
|
+
|
|
|
+ openTest: false,
|
|
|
+ testLoading: false,
|
|
|
+ currentRow: null,
|
|
|
+ testForm: {
|
|
|
+ headersJson: '',
|
|
|
+ bodyJson: '',
|
|
|
+ timeoutMs: 10000
|
|
|
+ },
|
|
|
+ testResult: {
|
|
|
+ responseStatus: null,
|
|
|
+ responseBody: '',
|
|
|
+ durationMs: null,
|
|
|
+ success: null,
|
|
|
+ errorMessage: ''
|
|
|
+ },
|
|
|
+
|
|
|
+ openLogs: false,
|
|
|
+ logsLoading: false,
|
|
|
+ logs: [],
|
|
|
+ logsTotal: 0,
|
|
|
+ logsQuery: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ configId: null
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ emptyForm() {
|
|
|
+ return {
|
|
|
+ id: null,
|
|
|
+ apiType: '',
|
|
|
+ apiName: '',
|
|
|
+ apiCode: '',
|
|
|
+ apiUrl: '',
|
|
|
+ httpMethod: 'GET',
|
|
|
+ rateWindowSeconds: null,
|
|
|
+ rateMaxCount: null,
|
|
|
+ priority: 0,
|
|
|
+ status: 1,
|
|
|
+ timeoutMs: 10000,
|
|
|
+ defaultHeadersJson: '',
|
|
|
+ defaultBodyJson: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ formatWindow(seconds) {
|
|
|
+ if (!seconds) return '-'
|
|
|
+ if (seconds % 86400 === 0) return (seconds / 86400) + '天'
|
|
|
+ if (seconds % 3600 === 0) return (seconds / 3600) + '小时'
|
|
|
+ if (seconds % 60 === 0) return (seconds / 60) + '分钟'
|
|
|
+ return seconds + '秒'
|
|
|
+ },
|
|
|
+ getList() {
|
|
|
+ this.loading = true
|
|
|
+ pageExternalApi(this.queryParams).then(res => {
|
|
|
+ const page = res.data || {}
|
|
|
+ this.list = page.records || []
|
|
|
+ this.total = page.total || 0
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleQuery() {
|
|
|
+ this.queryParams.pageNum = 1
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+ resetQuery() {
|
|
|
+ this.queryParams = {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ apiType: undefined,
|
|
|
+ apiName: undefined,
|
|
|
+ apiCode: undefined,
|
|
|
+ status: undefined
|
|
|
+ }
|
|
|
+ this.getList()
|
|
|
+ },
|
|
|
+ handleAdd() {
|
|
|
+ this.form = this.emptyForm()
|
|
|
+ this.openForm = true
|
|
|
+ this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
|
|
|
+ },
|
|
|
+ handleEdit(row) {
|
|
|
+ getExternalApi(row.id).then(res => {
|
|
|
+ this.form = Object.assign(this.emptyForm(), res.data || {})
|
|
|
+ this.openForm = true
|
|
|
+ this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
|
|
|
+ })
|
|
|
+ },
|
|
|
+ submitForm() {
|
|
|
+ this.$refs.formRef.validate(valid => {
|
|
|
+ if (!valid) return
|
|
|
+ saveOrUpdateExternalApi(this.form).then(() => {
|
|
|
+ this.$message.success('保存成功')
|
|
|
+ this.openForm = false
|
|
|
+ this.getList()
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleStatusChange(row, val) {
|
|
|
+ changeExternalApiStatus(row.id, val).then(() => {
|
|
|
+ this.$message.success('状态已更新')
|
|
|
+ }).catch(() => {
|
|
|
+ row.status = val === 1 ? 0 : 1
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleDelete(row) {
|
|
|
+ this.$confirm(`确认删除接口【${row.apiName}】?`, '提示', { type: 'warning' })
|
|
|
+ .then(() => deleteExternalApi(row.id))
|
|
|
+ .then(() => {
|
|
|
+ this.$message.success('删除成功')
|
|
|
+ this.getList()
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
+ },
|
|
|
+ handleTest(row) {
|
|
|
+ this.currentRow = row
|
|
|
+ this.testForm = { headersJson: '', bodyJson: '', timeoutMs: row.timeoutMs || 10000 }
|
|
|
+ this.testResult = { responseStatus: null, responseBody: '', durationMs: null, success: null, errorMessage: '' }
|
|
|
+ this.openTest = true
|
|
|
+ },
|
|
|
+ doTest() {
|
|
|
+ if (!this.currentRow) return
|
|
|
+ this.testLoading = true
|
|
|
+ testExternalApi(this.currentRow.id, this.testForm).then(res => {
|
|
|
+ this.testResult = res.data || this.testResult
|
|
|
+ }).finally(() => {
|
|
|
+ this.testLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleLogs(row) {
|
|
|
+ this.logsQuery = { pageNum: 1, pageSize: 10, configId: row.id }
|
|
|
+ this.openLogs = true
|
|
|
+ this.getLogs()
|
|
|
+ },
|
|
|
+ getLogs() {
|
|
|
+ this.logsLoading = true
|
|
|
+ pageExternalApiLogs(this.logsQuery).then(res => {
|
|
|
+ const page = res.data || {}
|
|
|
+ this.logs = page.records || []
|
|
|
+ this.logsTotal = page.total || 0
|
|
|
+ }).finally(() => {
|
|
|
+ this.logsLoading = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.mb8 { margin-bottom: 8px; }
|
|
|
+</style>
|
|
|
+
|