提交api接口设计前端页面以及后端更改

pull/8257/head
xlh12306 2025-05-10 23:56:06 +08:00
parent 21392c44f8
commit 49ba40e98a
34 changed files with 2020 additions and 247 deletions

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.openapi.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -16,8 +17,6 @@ import org.jeecg.modules.openapi.entity.OpenApiHeader;
import org.jeecg.modules.openapi.entity.OpenApiParam;
import org.jeecg.modules.openapi.generator.PathGenerator;
import org.jeecg.modules.openapi.service.OpenApiAuthService;
import org.jeecg.modules.openapi.service.OpenApiHeaderService;
import org.jeecg.modules.openapi.service.OpenApiParamService;
import org.jeecg.modules.openapi.service.OpenApiService;
import org.jeecg.modules.openapi.swagger.*;
import org.jeecg.modules.system.entity.SysUser;
@ -26,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@ -44,10 +42,6 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
@Autowired
private RestTemplate restTemplate;
@Autowired
private OpenApiParamService openApiParamService;
@Autowired
private OpenApiHeaderService openApiHeaderService;
@Autowired
private ISysUserService sysUserService;
@Autowired
private OpenApiAuthService openApiAuthService;
@ -67,10 +61,6 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
QueryWrapper<OpenApi> queryWrapper = QueryGenerator.initQueryWrapper(openApi, req.getParameterMap());
Page<OpenApi> page = new Page<>(pageNo, pageSize);
IPage<OpenApi> pageList = service.page(page, queryWrapper);
for (OpenApi api : pageList.getRecords()) {
api.setParams(openApiParamService.findByApiId(api.getId()));
api.setHeaders(openApiHeaderService.findByApiId(api.getId()));
}
return Result.ok(pageList);
}
@ -82,16 +72,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
*/
@PostMapping(value = "/add")
public Result<?> add(@RequestBody OpenApi openApi) {
if (service.save(openApi)) {
if (!CollectionUtils.isEmpty(openApi.getHeaders())) {
openApiHeaderService.saveBatch(openApi.getHeaders());
}
if (!CollectionUtils.isEmpty(openApi.getParams())) {
openApiParamService.saveBatch(openApi.getParams());
}
}
service.save(openApi);
return Result.ok("添加成功!");
}
@ -103,18 +84,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
*/
@PutMapping(value = "/edit")
public Result<?> edit(@RequestBody OpenApi openApi) {
if (service.updateById(openApi)) {
openApiHeaderService.deleteByApiId(openApi.getId());
openApiParamService.deleteByApiId(openApi.getId());
if (!CollectionUtils.isEmpty(openApi.getHeaders())) {
openApiHeaderService.saveBatch(openApi.getHeaders());
}
if (!CollectionUtils.isEmpty(openApi.getParams())) {
openApiParamService.saveBatch(openApi.getParams());
}
}
service.updateById(openApi);
return Result.ok("修改成功!");
}
@ -170,8 +140,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
result.put("data", null);
return Result.error("失败", result);
}
List<OpenApiHeader> headers = openApiHeaderService.findByApiId(openApi.getId());
List<OpenApiHeader> headers = JSON.parseArray(openApi.getHeadersJson(),OpenApiHeader.class);
String url = openApi.getOriginUrl();
String method = openApi.getRequestMethod();
@ -179,7 +148,6 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
for (OpenApiHeader header : headers) {
httpHeaders.put(header.getHeaderKey(), Lists.newArrayList(request.getHeader(header.getHeaderKey())));
}
String appkey = request.getHeader("appkey");
OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey);
SysUser systemUser = sysUserService.getById(openApiAuth.getSystemUserId());
@ -230,13 +198,16 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
definition.setType("object");
Map<String, SwaggerDefinitionProperties> definitionProperties = new HashMap<>();
definition.setProperties(definitionProperties);
JSONObject jsonObject = JSONObject.parseObject(openApi.getBody());
for (Map.Entry<String, Object> properties : jsonObject.entrySet()) {
SwaggerDefinitionProperties swaggerDefinitionProperties = new SwaggerDefinitionProperties();
swaggerDefinitionProperties.setType("string");
swaggerDefinitionProperties.setDescription(properties.getValue()+"");
definitionProperties.put(properties.getKey(), swaggerDefinitionProperties);
if (openApi.getBody()!=null){
JSONObject jsonObject = JSONObject.parseObject(openApi.getBody());
if (jsonObject.size()>0){
for (Map.Entry<String, Object> properties : jsonObject.entrySet()) {
SwaggerDefinitionProperties swaggerDefinitionProperties = new SwaggerDefinitionProperties();
swaggerDefinitionProperties.setType("string");
swaggerDefinitionProperties.setDescription(properties.getValue()+"");
definitionProperties.put(properties.getKey(), swaggerDefinitionProperties);
}
}
}
// body的definition构建完成
definitions.put(openApi.getRequestUrl()+"Using"+openApi.getRequestMethod()+"body", definition);
@ -327,25 +298,28 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
private void parameters(SwaggerOperation operation, OpenApi openApi) {
List<SwaggerOperationParameter> parameters = new ArrayList<>();
for (OpenApiParam openApiParam : openApiParamService.findByApiId(openApi.getId())) {
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
parameter.setIn("path");
parameter.setName(openApiParam.getParamKey());
parameter.setRequired(openApiParam.getRequired() == 1);
parameter.setDescription(openApiParam.getNote());
parameters.add(parameter);
if (openApi.getParamsJson()!=null) {
List<OpenApiParam> openApiParams = JSON.parseArray(openApi.getParamsJson(), OpenApiParam.class);
for (OpenApiParam openApiParam : openApiParams) {
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
parameter.setIn("path");
parameter.setName(openApiParam.getParamKey());
parameter.setRequired(openApiParam.getRequired() == 1);
parameter.setDescription(openApiParam.getNote());
parameters.add(parameter);
}
}
for (OpenApiHeader openApiHeader : openApiHeaderService.findByApiId(openApi.getId())) {
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
parameter.setIn("header");
parameter.setName(openApiHeader.getHeaderKey());
parameter.setRequired(openApiHeader.getRequired() == 1);
parameter.setDescription(openApiHeader.getNote());
parameters.add(parameter);
if (openApi.getHeadersJson()!=null) {
List<OpenApiHeader> openApiHeaders = JSON.parseArray(openApi.getHeadersJson(), OpenApiHeader.class);
for (OpenApiHeader openApiHeader : openApiHeaders) {
SwaggerOperationParameter parameter = new SwaggerOperationParameter();
parameter.setIn("header");
parameter.setName(openApiHeader.getHeaderKey());
parameter.setRequired(openApiHeader.getRequired() == 1);
parameter.setDescription(openApiHeader.getNote());
parameters.add(parameter);
}
}
operation.setParameters(parameters);
}

View File

@ -6,8 +6,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.openapi.entity.OpenApiRecord;
import org.jeecg.modules.openapi.service.OpenApiRecordService;
import org.jeecg.modules.openapi.entity.OpenApiLog;
import org.jeecg.modules.openapi.service.OpenApiLogService;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@ -18,47 +18,47 @@ import java.util.Arrays;
*/
@RestController
@RequestMapping("/openapi/record")
public class OpenApiRecordController extends JeecgController<OpenApiRecord, OpenApiRecordService> {
public class OpenApiLogController extends JeecgController<OpenApiLog, OpenApiLogService> {
/**
*
*
* @param openApiRecord
* @param OpenApiLog
* @param pageNo
* @param pageSize
* @param req
* @return
*/
@GetMapping(value = "/list")
public Result<?> queryPageList(OpenApiRecord openApiRecord, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
public Result<?> queryPageList(OpenApiLog OpenApiLog, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
QueryWrapper<OpenApiRecord> queryWrapper = QueryGenerator.initQueryWrapper(openApiRecord, req.getParameterMap());
Page<OpenApiRecord> page = new Page<>(pageNo, pageSize);
IPage<OpenApiRecord> pageList = service.page(page, queryWrapper);
QueryWrapper<OpenApiLog> queryWrapper = QueryGenerator.initQueryWrapper(OpenApiLog, req.getParameterMap());
Page<OpenApiLog> page = new Page<>(pageNo, pageSize);
IPage<OpenApiLog> pageList = service.page(page, queryWrapper);
return Result.ok(pageList);
}
/**
*
*
* @param openApiRecord
* @param OpenApiLog
* @return
*/
@PostMapping(value = "/add")
public Result<?> add(@RequestBody OpenApiRecord openApiRecord) {
service.save(openApiRecord);
public Result<?> add(@RequestBody OpenApiLog OpenApiLog) {
service.save(OpenApiLog);
return Result.ok("添加成功!");
}
/**
*
*
* @param openApiRecord
* @param OpenApiLog
* @return
*/
@PutMapping(value = "/edit")
public Result<?> edit(@RequestBody OpenApiRecord openApiRecord) {
service.updateById(openApiRecord);
public Result<?> edit(@RequestBody OpenApiLog OpenApiLog) {
service.updateById(OpenApiLog);
return Result.ok("修改成功!");
}
@ -96,7 +96,7 @@ public class OpenApiRecordController extends JeecgController<OpenApiRecord, Open
*/
@GetMapping(value = "/queryById")
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
OpenApiRecord openApiRecord = service.getById(id);
return Result.ok(openApiRecord);
OpenApiLog OpenApiLog = service.getById(id);
return Result.ok(OpenApiLog);
}
}

View File

@ -1,13 +1,15 @@
package org.jeecg.modules.openapi.controller;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.modules.openapi.entity.OpenApiPermission;
import org.jeecg.modules.openapi.service.OpenApiPermissionService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/openapi/permission")
@ -15,6 +17,19 @@ public class OpenApiPermissionController extends JeecgController<OpenApiPermissi
@PostMapping("add")
public Result add(@RequestBody OpenApiPermission openApiPermission) {
return Result.ok(service.save(openApiPermission));
List<String> list = Arrays.asList(openApiPermission.getApiId().split(","));
if (CollectionUtil.isNotEmpty(list)) {
list.forEach(l->{
OpenApiPermission saveApiPermission = new OpenApiPermission();
saveApiPermission.setApiId(l);
saveApiPermission.setApiAuthId(openApiPermission.getApiAuthId());
service.save(saveApiPermission);
});
}
return Result.ok("保存成功");
}
@GetMapping("/list")
public Result list( String apiAuthId) {
return Result.ok(service.list(Wrappers.<OpenApiPermission>lambdaQuery().eq(OpenApiPermission::getApiAuthId,apiAuthId)));
}
}

View File

@ -47,18 +47,15 @@ public class OpenApi implements Serializable {
* IP
*/
private String blackList;
/**
*
* json
*/
@TableField(exist = false)
private List<OpenApiHeader> headers;
private String headersJson;
/**
*
* json
*/
@TableField(exist = false)
private List<OpenApiParam> params;
private String paramsJson;
/**
* json

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import java.io.Serializable;
import java.util.Date;
@ -44,6 +45,7 @@ public class OpenApiAuth implements Serializable {
/**
* ID
*/
@Dict(dictTable = "sys_user",dicCode = "id",dicText = "username")
private String systemUserId;
/**

View File

@ -18,16 +18,6 @@ import java.io.Serializable;
public class OpenApiHeader implements Serializable {
private static final long serialVersionUID = 5032708503120184683L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private String id;
/**
* ID
*/
private String apiId;
/**
* key

View File

@ -16,7 +16,7 @@ import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class OpenApiRecord implements Serializable {
public class OpenApiLog implements Serializable {
private static final long serialVersionUID = -5870384488947863579L;
/**

View File

@ -17,16 +17,6 @@ import java.io.Serializable;
@Accessors(chain = true)
public class OpenApiParam implements Serializable {
private static final long serialVersionUID = -6174831468578022357L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private String id;
/**
* ID
*/
private String apiId;
/**
* key

View File

@ -4,11 +4,11 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.openapi.entity.OpenApi;
import org.jeecg.modules.openapi.entity.OpenApiAuth;
import org.jeecg.modules.openapi.entity.OpenApiLog;
import org.jeecg.modules.openapi.entity.OpenApiPermission;
import org.jeecg.modules.openapi.entity.OpenApiRecord;
import org.jeecg.modules.openapi.service.OpenApiAuthService;
import org.jeecg.modules.openapi.service.OpenApiLogService;
import org.jeecg.modules.openapi.service.OpenApiPermissionService;
import org.jeecg.modules.openapi.service.OpenApiRecordService;
import org.jeecg.modules.openapi.service.OpenApiService;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
@ -27,7 +27,7 @@ import java.util.List;
@Slf4j
public class ApiAuthFilter implements Filter {
private OpenApiRecordService openApiRecordService;
private OpenApiLogService openApiLogService;
private OpenApiAuthService openApiAuthService;
private OpenApiPermissionService openApiPermissionService;
private OpenApiService openApiService;
@ -61,13 +61,13 @@ public class ApiAuthFilter implements Filter {
filterChain.doFilter(servletRequest, servletResponse);
long endTime = System.currentTimeMillis();
OpenApiRecord record = new OpenApiRecord();
record.setApiId(openApi.getId());
record.setCallAuthId(openApiAuth.getId());
record.setCallTime(callTime);
record.setUsedTime(endTime - startTime);
record.setResponseTime(new Date());
openApiRecordService.save(record);
OpenApiLog openApiLog = new OpenApiLog();
openApiLog.setApiId(openApi.getId());
openApiLog.setCallAuthId(openApiAuth.getId());
openApiLog.setCallTime(callTime);
openApiLog.setUsedTime(endTime - startTime);
openApiLog.setResponseTime(new Date());
openApiLogService.save(openApiLog);
}
@Override
@ -75,7 +75,7 @@ public class ApiAuthFilter implements Filter {
ServletContext servletContext = filterConfig.getServletContext();
WebApplicationContext applicationContext = (WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
this.openApiService = applicationContext.getBean(OpenApiService.class);
this.openApiRecordService = applicationContext.getBean(OpenApiRecordService.class);
this.openApiLogService = applicationContext.getBean(OpenApiLogService.class);
this.openApiAuthService = applicationContext.getBean(OpenApiAuthService.class);
this.openApiPermissionService = applicationContext.getBean(OpenApiPermissionService.class);
}

View File

@ -1,12 +0,0 @@
package org.jeecg.modules.openapi.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.jeecg.modules.openapi.entity.OpenApiHeader;
/**
* @date 2024/12/10 14:47
*/
@Mapper
public interface OpenApiHeaderMapper extends BaseMapper<OpenApiHeader> {
}

View File

@ -2,11 +2,11 @@ package org.jeecg.modules.openapi.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.jeecg.modules.openapi.entity.OpenApiRecord;
import org.jeecg.modules.openapi.entity.OpenApiLog;
/**
* @date 2024/12/10 9:50
*/
@Mapper
public interface OpenApiRecordMapper extends BaseMapper<OpenApiRecord> {
public interface OpenApiLogMapper extends BaseMapper<OpenApiLog> {
}

View File

@ -1,12 +0,0 @@
package org.jeecg.modules.openapi.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.jeecg.modules.openapi.entity.OpenApiParam;
/**
* @date 2024/12/10 14:48
*/
@Mapper
public interface OpenApiParamMapper extends BaseMapper<OpenApiParam> {
}

View File

@ -1,16 +0,0 @@
package org.jeecg.modules.openapi.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.openapi.entity.OpenApiHeader;
import java.util.List;
/**
* @date 2024/12/10 14:48
*/
public interface OpenApiHeaderService extends IService<OpenApiHeader> {
boolean deleteByApiId(String apiId);
List<OpenApiHeader> findByApiId(String apiId);
}

View File

@ -1,10 +1,10 @@
package org.jeecg.modules.openapi.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.openapi.entity.OpenApiRecord;
import org.jeecg.modules.openapi.entity.OpenApiLog;
/**
* @date 2024/12/10 9:51
*/
public interface OpenApiRecordService extends IService<OpenApiRecord> {
public interface OpenApiLogService extends IService<OpenApiLog> {
}

View File

@ -1,15 +0,0 @@
package org.jeecg.modules.openapi.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.openapi.entity.OpenApiParam;
import java.util.List;
/**
* @date 2024/12/10 14:49
*/
public interface OpenApiParamService extends IService<OpenApiParam> {
boolean deleteByApiId(String apiId);
List<OpenApiParam> findByApiId(String apiId);
}

View File

@ -1,26 +0,0 @@
package org.jeecg.modules.openapi.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.openapi.entity.OpenApiHeader;
import org.jeecg.modules.openapi.mapper.OpenApiHeaderMapper;
import org.jeecg.modules.openapi.service.OpenApiHeaderService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @date 2024/12/10 14:49
*/
@Service
public class OpenApiHeaderServiceImpl extends ServiceImpl<OpenApiHeaderMapper, OpenApiHeader> implements OpenApiHeaderService {
@Override
public boolean deleteByApiId(String apiId) {
return baseMapper.delete(Wrappers.lambdaUpdate(OpenApiHeader.class).eq(OpenApiHeader::getApiId, apiId)) > 0;
}
@Override
public List<OpenApiHeader> findByApiId(String apiId) {
return baseMapper.selectList(Wrappers.lambdaQuery(OpenApiHeader.class).eq(OpenApiHeader::getApiId, apiId));
}
}

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.openapi.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.openapi.entity.OpenApiLog;
import org.jeecg.modules.openapi.mapper.OpenApiLogMapper;
import org.jeecg.modules.openapi.service.OpenApiLogService;
import org.springframework.stereotype.Service;
/**
* @date 2024/12/10 9:53
*/
@Service
public class OpenApiLogServiceImpl extends ServiceImpl<OpenApiLogMapper, OpenApiLog> implements OpenApiLogService {
}

View File

@ -1,27 +0,0 @@
package org.jeecg.modules.openapi.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.openapi.entity.OpenApiParam;
import org.jeecg.modules.openapi.mapper.OpenApiParamMapper;
import org.jeecg.modules.openapi.service.OpenApiParamService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @date 2024/12/10 14:50
*/
@Service
public class OpenApiParamServiceImpl extends ServiceImpl<OpenApiParamMapper, OpenApiParam> implements OpenApiParamService {
@Override
public boolean deleteByApiId(String apiId) {
return baseMapper.delete(Wrappers.lambdaUpdate(OpenApiParam.class).eq(OpenApiParam::getApiId, apiId)) > 0;
}
@Override
public List<OpenApiParam> findByApiId(String apiId) {
return baseMapper.selectList(Wrappers.lambdaQuery(OpenApiParam.class).eq(OpenApiParam::getApiId, apiId));
}
}

View File

@ -1,14 +0,0 @@
package org.jeecg.modules.openapi.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.openapi.entity.OpenApiRecord;
import org.jeecg.modules.openapi.mapper.OpenApiRecordMapper;
import org.jeecg.modules.openapi.service.OpenApiRecordService;
import org.springframework.stereotype.Service;
/**
* @date 2024/12/10 9:53
*/
@Service
public class OpenApiRecordServiceImpl extends ServiceImpl<OpenApiRecordMapper, OpenApiRecord> implements OpenApiRecordService {
}

View File

@ -66,6 +66,7 @@
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sortablejs": "^1.15.6",
"swagger-ui-dist": "^5.21.0",
"tinymce": "6.6.2",
"vditor": "^3.10.8",
"vue": "^3.5.13",

View File

@ -0,0 +1,118 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/openapi/list',
save='/openapi/add',
edit='/openapi/edit',
deleteOne = '/openapi/delete',
deleteBatch = '/openapi/deleteBatch',
genPath = '/openapi/genPath',
importExcel = '/openapi/importExcel',
exportXls = '/openapi/exportXls',
openApiHeaderList = '/openapi/list',
openApiParamList = '/openapi/list',
openApiJson = '/openapi/json',
}
/**
* 子表单查询接口
* @param params
*/
export const genPath = Api.genPath
/**
* swagger文档json
* @param params
*/
export const openApiJson = Api.openApiJson
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 子表单查询接口
* @param params
*/
export const queryOpenApiHeader = Api.openApiHeaderList
/**
* 子表单查询接口
* @param params
*/
export const queryOpenApiParam = Api.openApiParamList
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
if (isUpdate) {
return defHttp.put({url: Api.edit, params});
} else {
return defHttp.post({url: Api.save, params});
}
}
/**
* 获取接口地址
* @param params
*/
export const getGenPath = (params) =>
defHttp.get({url: Api.genPath, params},{isTransformResponse:false});
/**
* 子表列表接口
* @param params
*/
export const openApiHeaderList = (params) =>
defHttp.get({url: Api.openApiHeaderList, params},{isTransformResponse:false});
/**
* 子表列表接口
* @param params
*/
export const openApiParamList = (params) =>
defHttp.get({url: Api.openApiParamList, params},{isTransformResponse:false});
/**
* swagger文档json
* @param params
*/
export const getOpenApiJson = (params) =>
defHttp.get({url: Api.openApiJson, params},{isTransformResponse:false});

View File

@ -0,0 +1,347 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
import { getWeekMonthQuarterYear } from '/@/utils';
//
export const columns: BasicColumn[] = [
{
title: '接口名称',
align:"center",
dataIndex: 'name'
},
{
title: '请求方法',
align:"center",
dataIndex: 'requestMethod'
},
{
title: '接口地址',
align:"center",
dataIndex: 'requestUrl'
},
{
title: 'IP 黑名单',
align:"center",
dataIndex: 'blackList'
},
{
title: '状态',
align:"center",
dataIndex: 'status'
},
{
title: '创建人',
align:"center",
dataIndex: 'createBy'
},
{
title: '创建时间',
align:"center",
dataIndex: 'createTime'
},
];
//
export const searchFormSchema: FormSchema[] = [
{
label: "接口名称",
field: "name",
component: 'JInput',
},
{
label: "创建人",
field: "createBy",
component: 'JInput',
},
];
//
export const formSchema: FormSchema[] = [
{
label: '接口名称',
field: 'name',
component: 'Input',
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入接口名称!'},
];
},
},
{
label: '请求方法',
field: 'requestMethod',
component: 'JSearchSelect',
componentProps:{
dictOptions: [
{
text: 'post',
value: 'post',
},
{
text: 'get',
value: 'get',
},
{
text: 'head',
value: 'head',
},
{
text: 'put',
value: 'put',
},
{
text: 'patch',
value: 'patch',
},
{
text: 'delete',
value: 'delete',
},{
text: 'options',
value: 'options',
},{
text: 'trace',
value: 'trace',
},
]
},
dynamicRules: ({model,schema}) => {
return [
{ required: true, message: '请输入请求方法!'},
];
},
},
{
label: '接口地址',
field: 'requestUrl',
component: 'Input',
dynamicDisabled:true
},
{
label: 'IP 黑名单',
field: 'blackList',
component: 'Input',
},
{
label: '请求体内容',
component:"Input",
field: 'body'
},
{
label: '原始地址',
field: 'originUrl',
component: 'Input',
},
{
label: '删除标识',
field: 'delFlag',
component: 'Input',
defaultValue:0,
show:false
},
{
label: '状态',
field: 'status',
component: 'Input',
defaultValue:"1",
show:false
},
// TODO ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
//
//
export const openApiHeaderColumns: BasicColumn[] = [
// {
// title: 'apiId',
// align:"center",
// dataIndex: 'apiId'
// },
{
title: '请求头Key',
align:"center",
dataIndex: 'headerKey'
},
{
title: '是否必填',
align:"center",
dataIndex: 'required_dictText'
},
{
title: '默认值',
align:"center",
dataIndex: 'defaultValue'
},
{
title: '备注',
align:"center",
dataIndex: 'note'
},
];
//
export const openApiParamColumns: BasicColumn[] = [
// {
// title: 'apiId',
// align:"center",
// dataIndex: 'apiId'
// },
{
title: '参数Key',
align:"center",
dataIndex: 'paramKey'
},
{
title: '是否必填',
align:"center",
dataIndex: 'required_dictText'
},
{
title: '默认值',
align:"center",
dataIndex: 'defaultValue'
},
{
title: '备注',
align:"center",
dataIndex: 'note'
},
];
//
export const openApiHeaderJVxeColumns: JVxeColumn[] = [
// {
// title: 'apiId',
// key: 'apiId',
// type: JVxeTypes.input,
// width:"200px",
// placeholder: '${title}',
// defaultValue:'',
// },
{
title: '请求头Key',
key: 'headerKey',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
{
title: '是否必填',
key: 'required',
type: JVxeTypes.checkbox,
options:[],
// dictCode:"yn",
width:"100px",
placeholder: '请输入${title}',
defaultValue:'',
customValue: ['1','0']
},
{
title: '默认值',
key: 'defaultValue',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
{
title: '备注',
key: 'note',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
]
export const openApiParamJVxeColumns: JVxeColumn[] = [
// {
// title: 'apiId',
// key: 'apiId',
// type: JVxeTypes.input,
// width:"200px",
// placeholder: '${title}',
// defaultValue:'',
// },
{
title: '参数Key',
key: 'paramKey',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
{
title: '是否必填',
key: 'required',
type: JVxeTypes.checkbox,
options:[],
// dictCode:"yn",
width:"100px",
placeholder: '请输入${title}',
defaultValue:'',
customValue: ['1','0']
},
{
title: '默认值',
key: 'defaultValue',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
{
title: '备注',
key: 'note',
type: JVxeTypes.input,
width:"200px",
placeholder: '请输入${title}',
defaultValue:'',
},
]
//
export const superQuerySchema = {
name: {title: '接口名称',order: 0,view: 'text', type: 'string',},
requestMethod: {title: '请求方法',order: 1,view: 'list', type: 'string',dictCode: '',},
requestUrl: {title: '接口地址',order: 2,view: 'text', type: 'string',},
blackList: {title: 'IP 黑名单',order: 3,view: 'text', type: 'string',},
status: {title: '状态',order: 5,view: 'number', type: 'number',},
createBy: {title: '创建人',order: 6,view: 'text', type: 'string',},
createTime: {title: '创建时间',order: 7,view: 'datetime', type: 'string',},
//
openApiHeader: {
title: '请求头表',
view: 'table',
fields: {
// apiId: {title: 'apiId',order: 0,view: 'text', type: 'string',},
headerKey: {title: '请求头Key',order: 1,view: 'text', type: 'string',},
required: {title: '是否必填',order: 2,view: 'number', type: 'number',dictCode: 'yn',},
defaultValue: {title: '默认值',order: 3,view: 'text', type: 'string',},
note: {title: '备注',order: 4,view: 'text', type: 'string',},
}
},
openApiParam: {
title: '请求参数部分',
view: 'table',
fields: {
// apiId: {title: 'apiId',order: 0,view: 'text', type: 'string',},
paramKey: {title: '参数Key',order: 1,view: 'text', type: 'string',},
required: {title: '是否必填',order: 2,view: 'number', type: 'number',dictCode: 'yn',},
defaultValue: {title: '默认值',order: 3,view: 'text', type: 'string',},
note: {title: '备注',order: 4,view: 'text', type: 'string',},
}
},
};
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// formSchema
return formSchema;
}

View File

@ -0,0 +1,120 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/openapi/auth/list',
save='/openapi/auth/add',
edit='/openapi/auth/edit',
apiList= '/openapi/list',
genAKSK = '/openapi/auth/genAKSK',
permissionList='/openapi/permission/list',
permissionAdd='/openapi/permission/add',
deleteOne = '/openapi/auth/delete',
deleteBatch = '/openapi/auth/deleteBatch',
importExcel = '/openapi/auth/importExcel',
exportXls = '/openapi/auth/exportXls',
}
/**
* 获取API
* @param params
*/
export const apiList = Api.apiList;
/**
* 权限添加
* @param params
*/
export const permissionAdd = Api.permissionAdd;
/**
* 生成AKSK
* @param params
*/
export const genAKSK = Api.genAKSK;
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}
/**
* 全部权限列表接口
* @param params
*/
export const getApiList = (params) => defHttp.get({ url: Api.apiList, params });
/**
* 获取已授权项目的接口
* @param params
*/
export const getPermissionList = (params) => defHttp.get({ url: Api.permissionList, params });
/**
* 授权保存方法
* @param params
* @param isUpdate
*/
export const permissionAddFunction = (params) => {
return defHttp.post({ url: Api.permissionAdd, params }, { isTransformResponse: false });
}
/**
* 授权保存方法
* @param params
* @param isUpdate
*/
export const getGenAKSK = (params) => {
return defHttp.get({ url: Api.genAKSK, params });
}

View File

@ -0,0 +1,49 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//
export const columns: BasicColumn[] = [
{
title: '授权名称',
align: "center",
dataIndex: 'name'
},
{
title: 'AK',
align: "center",
dataIndex: 'ak'
},
{
title: 'SK',
align: "center",
dataIndex: 'sk'
},
{
title: '创建人',
align: "center",
dataIndex: 'createBy'
},
{
title: '创建时间',
align: "center",
dataIndex: 'createTime'
},
{
title: '关联系统用户名',
align: "center",
dataIndex: 'systemUserId_dictText',
},
];
//
export const superQuerySchema = {
name: {title: '授权名称',order: 0,view: 'text', type: 'string',},
ak: {title: 'AK',order: 1,view: 'text', type: 'string',},
sk: {title: 'SK',order: 2,view: 'text', type: 'string',},
createBy: {title: '创建人',order: 3,view: 'text', type: 'string',},
createTime: {title: '创建时间',order: 4,view: 'datetime', type: 'string',},
systemUserId: {title: '关联系统用户名',order: 5,view: 'text', type: 'string',},
};

View File

@ -0,0 +1,277 @@
<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="6">
<a-form-item name="name">
<template #label><span title="授权名称">授权名称</span></template>
<a-input placeholder="请输入授权名称" v-model:value="queryParam.name" allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="systemUserId">
<template #label><span title="关联系统用户名">关联系统用户名</span></template>
<JSearchSelect dict="sys_user,username,id" v-model:value="queryParam.systemUserId" placeholder="请输入关联系统用户名" allow-clear ></JSearchSelect>
<!-- <a-input placeholder="请输入关联系统用户名" v-model:value="queryParam.systemUserId" allow-clear ></a-input>-->
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery"></a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<a @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
</a>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'openapi:open_api_auth:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> </a-button>
<a-button type="primary" v-auth="'openapi:open_api_auth:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> </a-button>
<j-upload-button type="primary" v-auth="'openapi:open_api_auth:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls"></j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button v-auth="'openapi:open_api_auth:deleteBatch'">
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<OpenApiAuthModal ref="registerModal" @success="handleSuccess"></OpenApiAuthModal>
<AuthModal ref="authModal" @success="handleSuccess"></AuthModal>
</div>
</template>
<script lang="ts" name="openapi-openApiAuth" setup>
import { ref, reactive } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './OpenApiAuth.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './OpenApiAuth.api';
import OpenApiAuthModal from './components/OpenApiAuthModal.vue'
import AuthModal from './components/AuthModal.vue'
import { useUserStore } from '/@/store/modules/user';
import JSearchSelect from "../../components/Form/src/jeecg/components/JSearchSelect.vue";
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const authModal = ref();
const userStore = useUserStore();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '授权管理',
api: list,
columns,
canResize:false,
useSearchForm: false,
actionColumn: {
width: 200,
fixed: 'right',
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "授权管理",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, updateTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs:24,
sm:10,
xl:6,
xxl:10
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
//
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
searchQuery();
}
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleAuth(record: Recordable) {
authModal.value.disableSubmit = false;
authModal.value.edit(record);
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '授权',
onClick: handleAuth.bind(null, record),
auth: 'openapi:open_api_auth:edit'
},
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'openapi:open_api_auth:edit'
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
},
auth: 'openapi:open_api_auth:delete'
}
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust{
min-width: 100px !important;
}
.query-group-split-cust{
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help){
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
}
</style>

View File

@ -0,0 +1,217 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection" @expand="handleExpand">
<!-- 内嵌table区域 begin -->
<!-- <template #expandedRowRender="{record}">-->
<!-- <a-tabs tabPosition="top">-->
<!-- <a-tab-pane tab="请求头表" key="openApiHeader" forceRender>-->
<!-- <openApiHeaderSubTable v-if="expandedRowKeys.includes(record.id)" :id="record.id" />-->
<!-- </a-tab-pane>-->
<!-- <a-tab-pane tab="请求参数部分" key="openApiParam" forceRender>-->
<!-- <openApiParamSubTable v-if="expandedRowKeys.includes(record.id)" :id="record.id" />-->
<!-- </a-tab-pane>-->
<!-- </a-tabs>-->
<!-- </template>-->
<!-- 内嵌table区域 end -->
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'openapi:open_api:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> </a-button>
<a-button type="primary" v-auth="'openapi:open_api:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> </a-button>
<j-upload-button type="primary" v-auth="'openapi:open_api:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls"></j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button v-auth="'openapi:open_api:deleteBatch'">
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<OpenApiModal @register="registerModal" @success="handleSuccess"></OpenApiModal>
</div>
</template>
<script lang="ts" name="openapi-openApi" setup>
import {ref, reactive, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage'
import {useModal} from '/@/components/Modal';
import OpenApiModal from './components/OpenApiModal.vue'
import OpenApiHeaderSubTable from './subTables/OpenApiHeaderSubTable.vue'
import OpenApiParamSubTable from './subTables/OpenApiParamSubTable.vue'
import {columns, searchFormSchema, superQuerySchema} from './OpenApi.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './OpenApi.api';
import {downloadFile} from '/@/utils/common/renderUtils';
import { useUserStore } from '/@/store/modules/user';
const queryParam = reactive<any>({});
// key
const expandedRowKeys = ref<any[]>([]);
//model
const [registerModal, {openModal}] = useModal();
const userStore = useUserStore();
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '接口管理',
api: list,
columns,
canResize:false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name:"接口管理",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
//
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 展开事件
* */
function handleExpand(expanded, record){
expandedRowKeys.value=[];
if (expanded === true) {
expandedRowKeys.value.push(record.id)
}
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value},handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'openapi:open_api:edit'
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft'
},
auth: 'openapi:open_api:delete'
}
]
}
</script>
<style lang="less" scoped>
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
</style>

View File

@ -0,0 +1,36 @@
<template>
<div ref="swaggerUiRef" style="height: 100%;"></div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
// SwaggerUI 使 * as
import SwaggerUI from 'swagger-ui-dist/swagger-ui-bundle'; // 使 ESM
import 'swagger-ui-dist/swagger-ui.css';
import { getOpenApiJson } from './OpenApi.api';
const swaggerUiRef = ref<HTMLElement | null>(null);
const API_DOMAIN = import.meta.env.VITE_GLOB_DOMAIN_URL
onMounted(async () => {
try {
const response = await getOpenApiJson();
const openApiJson = response;
if (swaggerUiRef.value) {
SwaggerUI({
domNode: swaggerUiRef.value,
spec: openApiJson,
});
}
} catch (error) {
console.error('Failed to fetch OpenAPI JSON:', error);
}
});
</script>
<style scoped>
/* 确保容器有高度 */
.swagger-ui-container {
height: 100%;
}
</style>

View File

@ -0,0 +1,154 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<BasicTable @register="registerTable" :rowSelection="rowSelection"> </BasicTable>
</template>
</JFormContainer>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed } from 'vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { permissionAddFunction, getPermissionList, getApiList } from '../OpenApiAuth.api';
import { Form } from 'ant-design-vue';
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
import { BasicTable } from '@/components/Table';
import { useListPage } from '@/hooks/system/useListPage';
import { columns } from '@/views/openapi/OpenApi.data';
const queryParam = reactive<any>({});
//table
const { tableContext } = useListPage({
tableProps: {
title: '授权',
api: getApiList,
columns,
canResize: false,
useSearchForm: false,
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
tableContext;
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({}) },
formBpm: { type: Boolean, default: true },
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
apiAuthId: '',
apiIdList: [],
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = reactive({});
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
//
const disabled = computed(() => {
if (props.formBpm === true) {
if (props.formData.disabled === false) {
return false;
} else {
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
//
formData.apiAuthId = record.id;
//
getPermissionList({ apiAuthId: record.id }).then((res) => {
if (res && res.length > 0) {
let list = res.result.records || res.result;
let ids = [];
list.forEach((item) => {
ids.push(item.apiId);
});
selectedRowKeys.value = ids;
formData.apiIdList = ids;
}
});
});
}
/**
* 提交数据
*/
async function submitForm() {
if(selectedRowKeys.value.length === 0)
return emit('ok');
try {
//
await validate();
} catch ({ errorFields }) {
if (errorFields) {
const firstField = errorFields[0];
if (firstField) {
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
}
}
return Promise.reject(errorFields);
}
confirmLoading.value = true;
//
let model = formData;
// model.apiIdList = selectedRowKeys.value;
let apiId = ""
selectedRowKeys.value.forEach((item) => {
apiId += item +",";
})
model.apiId = apiId;
delete model.apiIdList
await permissionAddFunction(model)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
padding: 14px;
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<j-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<AuthForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></AuthForm>
</j-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import AuthForm from './AuthForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 授权
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '授权';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style lang="less">
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>
<style lang="less" scoped></style>

View File

@ -0,0 +1,175 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol" name="OpenApiAuthForm">
<a-row>
<a-col :span="24">
<a-form-item label="授权名称" v-bind="validateInfos.name" id="OpenApiAuthForm-name" name="name">
<a-input v-model:value="formData.name" placeholder="请输入授权名称" allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="AK" v-bind="validateInfos.ak" id="OpenApiAuthForm-ak" name="ak">
<a-input v-model:value="formData.ak" placeholder="请输入AK" disabled allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="SK" v-bind="validateInfos.sk" id="OpenApiAuthForm-sk" name="sk">
<a-input v-model:value="formData.sk" placeholder="请输入SK" disabled allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="关联系统用户名" v-bind="validateInfos.systemUserId" id="OpenApiAuthForm-systemUserId" name="systemUserId">
<JSearchSelect dict="sys_user,username,id" v-model:value="formData.systemUserId" placeholder="请输入关联系统用户名" allow-clear ></JSearchSelect>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
</JFormContainer>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, } from 'vue';
import { USER_INFO_KEY} from '/@/enums/cacheEnum';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate,getGenAKSK } from '../OpenApiAuth.api';
import { Form } from 'ant-design-vue';
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
import JSearchSelect from '/@/components/Form/src/jeecg/components/JSearchSelect.vue';
import { getAuthCache } from "@/utils/auth";
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({})},
formBpm: { type: Boolean, default: true },
title: { type: String, default: "" },
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
name: '',
ak: '',
sk: '',
systemUserId: '',
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = reactive({
name:[{ required: true, message: '请输入授权名称!'},],
systemUserId:[{ required: true, message: '请输入关联系统用户名!'},],
});
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
//
const disabled = computed(()=>{
if(props.formBpm === true){
if(props.formData.disabled === false){
return false;
}else{
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
async function add() {
edit({});
const AKSKObj = await getGenAKSK({});
formData.ak = AKSKObj[0];
formData.sk = AKSKObj[1];
}
/**
* 编辑
*/
function edit(record) {
const userData = getAuthCache(USER_INFO_KEY)
if(props.title == "新增"){
record.systemUserId = userData.id
}
nextTick(() => {
resetFields();
const tmpData = {};
Object.keys(formData).forEach((key) => {
if(record.hasOwnProperty(key)){
tmpData[key] = record[key]
}
})
//
Object.assign(formData, tmpData);
});
}
/**
* 提交数据
*/
async function submitForm() {
try {
//
await validate();
} catch ({ errorFields }) {
if (errorFields) {
const firstField = errorFields[0];
if (firstField) {
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
}
}
return Promise.reject(errorFields);
}
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
padding: 14px;
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<j-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<OpenApiAuthForm ref="registerForm" @ok="submitCallback" :title="title" :formDisabled="disableSubmit" :formBpm="false"></OpenApiAuthForm>
</j-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import OpenApiAuthForm from './OpenApiAuthForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style lang="less">
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>
<style lang="less" scoped></style>

View File

@ -0,0 +1,177 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="'80%'" @ok="handleSubmit">
<a-row :gutter="24">
<a-col :span="12">
<BasicForm @register="registerForm" ref="formRef" name="OpenApiForm" />
</a-col>
<a-col :span="12">
<a-row :gutter="24">
<a-col :span="24">
<JVxeTable
keep-source
resizable
ref="openApiHeader"
:loading="openApiHeaderTable.loading"
:columns="openApiHeaderTable.columns"
:dataSource="openApiHeaderTable.dataSource"
:height="340"
:disabled="formDisabled"
:rowNumber="true"
:rowSelection="true"
:toolbar="true"
/>
</a-col>
<a-col :span="24">
<JVxeTable
keep-source
resizable
ref="openApiParam"
:loading="openApiParamTable.loading"
:columns="openApiParamTable.columns"
:dataSource="openApiParamTable.dataSource"
:height="340"
:disabled="formDisabled"
:rowNumber="true"
:rowSelection="true"
:toolbar="true"
/>
</a-col>
</a-row>
</a-col>
</a-row>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref, reactive } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { JVxeTable } from '/@/components/jeecg/JVxeTable';
import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts';
import { formSchema, openApiHeaderJVxeColumns, openApiParamJVxeColumns } from '../OpenApi.data';
import { saveOrUpdate, queryOpenApiHeader, queryOpenApiParam, getGenPath } from '../OpenApi.api';
import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils';
import { useMessage } from "@/hooks/web/useMessage";
// Emits
const $message = useMessage();
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const formDisabled = ref(false);
const refKeys = ref(['openApiHeader', 'openApiParam']);
const activeKey = ref('openApiHeader');
const openApiHeader = ref();
const openApiParam = ref();
const tableRefs = { openApiHeader, openApiParam };
const openApiHeaderTable = reactive({
loading: false,
dataSource: [],
columns: openApiHeaderJVxeColumns,
});
const openApiParamTable = reactive({
loading: false,
dataSource: [],
columns: openApiParamJVxeColumns,
});
//
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await reset();
setModalProps({ confirmLoading: false, showCancelBtn: data?.showFooter, showOkBtn: data?.showFooter });
isUpdate.value = !!data?.isUpdate;
formDisabled.value = !data?.showFooter;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
//
// requestSubTableData(queryOpenApiHeader, {id:data?.record?.id}, openApiHeaderTable)
// requestSubTableData(queryOpenApiParam, {id:data?.record?.id}, openApiParamTable)
openApiHeaderTable.dataSource = !!data.record.headersJson?JSON.parse(data.record.headersJson):[];
openApiParamTable.dataSource = !!data.record.paramsJson?JSON.parse(data.record.paramsJson):[];
} else {
// /openapi/genpath
const requestUrlObj = await getGenPath({});
await setFieldsValue({
requestUrl: requestUrlObj.result
});
}
//
setProps({ disabled: !data?.showFooter });
});
//
const [handleChangeTabs, handleSubmit, requestSubTableData, formRef] = useJvxeMethod(
requestAddOrEdit,
classifyIntoFormData,
tableRefs,
activeKey,
refKeys
);
//
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(formDisabled) ? '编辑' : '详情'));
async function reset() {
await resetFields();
activeKey.value = 'openApiHeader';
openApiHeaderTable.dataSource = [];
openApiParamTable.dataSource = [];
}
function classifyIntoFormData(allValues) {
let main = Object.assign({}, allValues.formValue);
return {
...main, //
headersJson: allValues.tablesValue[0].tableData,
paramsJson: allValues.tablesValue[1].tableData,
};
}
//
async function requestAddOrEdit(values) {
let headersJson = !!values.headersJson?JSON.stringify(values.headersJson):null;
let paramsJson = !!values.headersJson?JSON.stringify(values.paramsJson):null;
try {
if (!!values.body){
try {
if (typeof JSON.parse(values.body)!='object'){
$message.createMessage.error("JSON格式化错误,请检查输入数据");
return;
}
} catch (e) {
$message.createMessage.error("JSON格式化错误,请检查输入数据");
return;
}
}
setModalProps({ confirmLoading: true });
values.headersJson = headersJson
values.paramsJson = paramsJson
//
await saveOrUpdate(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<div>
<!--引用表格-->
<BasicTable bordered size="middle" :loading="loading" rowKey="id" :canResize="false" :columns="openApiHeaderColumns" :dataSource="dataSource" :pagination="false">
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
</div>
</template>
<script lang="ts" setup>
import {ref,watchEffect} from 'vue';
import {BasicTable} from '/@/components/Table';
import {openApiHeaderColumns} from '../OpenApi.data';
import {openApiHeaderList} from '../OpenApi.api';
import { downloadFile } from '/@/utils/common/renderUtils';
const props = defineProps({
id: {
type: String,
default: '',
},
})
const loading = ref(false);
const dataSource = ref([]);
watchEffect(() => {
props.id && loadData(props.id);
});
function loadData(id) {
dataSource.value = []
loading.value = true
openApiHeaderList({id}).then((res) => {
if (res.success) {
dataSource.value = res.result.records
}
}).finally(() => {
loading.value = false
})
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<div>
<!--引用表格-->
<BasicTable bordered size="middle" :loading="loading" rowKey="id" :canResize="false" :columns="openApiParamColumns" :dataSource="dataSource" :pagination="false">
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
</div>
</template>
<script lang="ts" setup>
import {ref,watchEffect} from 'vue';
import {BasicTable} from '/@/components/Table';
import {openApiParamColumns} from '../OpenApi.data';
import {openApiParamList} from '../OpenApi.api';
import { downloadFile } from '/@/utils/common/renderUtils';
const props = defineProps({
id: {
type: String,
default: '',
},
})
const loading = ref(false);
const dataSource = ref([]);
watchEffect(() => {
props.id && loadData(props.id);
});
function loadData(id) {
dataSource.value = []
loading.value = true
openApiParamList({id}).then((res) => {
if (res.success) {
dataSource.value = res.result.records
}
}).finally(() => {
loading.value = false
})
}
</script>