初始化前端目录
This commit is contained in:
@@ -14,12 +14,12 @@ public class AuthInterceptor implements HandlerInterceptor {
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
// HttpSession session = request.getSession();
|
||||
// ApiUser apiUser = (ApiUser) session.getAttribute("Authorization");
|
||||
// if (apiUser == null) {
|
||||
// response.sendRedirect(request.getContextPath() + "/login");
|
||||
// return false;
|
||||
// }
|
||||
HttpSession session = request.getSession();
|
||||
ApiUser apiUser = (ApiUser) session.getAttribute("userInfo");
|
||||
if (apiUser == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/login");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.mini.capi.config;
|
||||
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@@ -13,35 +19,51 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
private final AuthInterceptor authInterceptor;
|
||||
|
||||
// @Override
|
||||
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
// registry.addResourceHandler("/cApi/**")
|
||||
// .addResourceLocations("classpath:/static/")
|
||||
// .setCachePeriod(0);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// public void addViewControllers(ViewControllerRegistry registry) {
|
||||
// registry.addViewController("/cApi/**")
|
||||
// .setViewName("forward:/cApi/index.html");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("forward:/index.html");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/**")
|
||||
.addResourceLocations("classpath:/static/")
|
||||
.resourceChain(true)
|
||||
.addResolver(new PathResourceResolver() {
|
||||
@Override
|
||||
protected Resource getResource(String resourcePath, Resource location) throws IOException {
|
||||
Resource requested = super.getResource(resourcePath, location);
|
||||
// 文件存在就返回,不存在返回 index.html
|
||||
return requested != null ? requested : new ClassPathResource("/static/index.html");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authInterceptor)
|
||||
.addPathPatterns("/**") // 需要拦截的路径
|
||||
.excludePathPatterns( // 排除的路径
|
||||
.addPathPatterns("/**") // 拦截所有请求
|
||||
.excludePathPatterns(
|
||||
// ① 排除 Vue 静态资源(匹配 static 目录下所有 js/css/img 等)
|
||||
"/js/**",
|
||||
"/css/**",
|
||||
"/img/**",
|
||||
"/favicon.ico",
|
||||
"/index.html", // 排除首页(Vue 入口)
|
||||
"/assets/**", // 若 Vue 打包后有 assets 目录,需排除
|
||||
"/resource/**", // 若有其他静态资源目录,需排除
|
||||
"/cApi/index/**",
|
||||
|
||||
"/login",
|
||||
"/index.html",
|
||||
"/assets/**",
|
||||
"/resource/**",
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**",
|
||||
"/Sys/jobs/**",
|
||||
"/Sys/login/**", // 你的登录接口(原 /Sys/login/** 缺少 /cApi 前缀,修复)
|
||||
"/Sys/jobs/**", // 原路径补充 /cApi 前缀
|
||||
"/Sys/hosts/**",
|
||||
"/Sys/dbs/**",
|
||||
"/Sys/login/**"
|
||||
|
||||
"/cApi/swagger-ui/**",
|
||||
"/cApi/v3/api-docs/**"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.mini.capi.job;
|
||||
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.sys.service.DockerService;
|
||||
import com.mini.capi.utils.*;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/jobs")
|
||||
public class taskEnable {
|
||||
|
||||
|
||||
@Resource
|
||||
private DockerService dockerService;
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器主机的磁盘使用情况
|
||||
*/
|
||||
@GetMapping("/getTaskDockerDiskInfo")
|
||||
public ApiResult<?> jobHostDisk(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dockerService.jobHostDisk();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行全部任务数据同步
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbInfo")
|
||||
public ApiResult<?> jobSyncAllTask(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncAllTask();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.mini.capi.model;
|
||||
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ApiResult<T> implements Serializable {
|
||||
@@ -37,6 +39,7 @@ public class ApiResult<T> implements Serializable {
|
||||
this.result = data;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------- 静态工厂方法 ---------------- */
|
||||
|
||||
/**
|
||||
|
||||
124
src/main/java/com/mini/capi/sys/Api/apiController.java
Normal file
124
src/main/java/com/mini/capi/sys/Api/apiController.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package com.mini.capi.sys.Api;
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.TabResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.sys.service.DockerService;
|
||||
import com.mini.capi.sys.service.HostService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/api")
|
||||
public class apiController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
@Resource
|
||||
private HostService hostService;
|
||||
|
||||
|
||||
@Resource
|
||||
private DockerService dockerService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取MySQL的当前连接下的所有数据表
|
||||
*/
|
||||
@GetMapping("/getApiSourceTables")
|
||||
public ApiResult<List<TabResult>> listSourceTables(String token, String dbId) {
|
||||
// 1. 验证token有效性
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.listSourceTables(dbId);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/getApiInfo")
|
||||
public ApiResult<List<HostService.SnapshotDTO>> getApiInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getApiInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器列表
|
||||
*/
|
||||
@GetMapping("/getApiDockerInfo")
|
||||
public ApiResult<?> getDockerInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getDockerInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启动容器
|
||||
*/
|
||||
@GetMapping("/getApiStartDockerInfo")
|
||||
public ApiResult<?> startDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.startDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止容器
|
||||
*/
|
||||
@GetMapping("/getApiStopDockerInfo")
|
||||
public ApiResult<?> stopDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.stopDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器主机的磁盘使用情况
|
||||
*/
|
||||
@GetMapping("/getTaskDockerDiskInfo")
|
||||
public ApiResult<?> jobHostDisk(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dockerService.jobHostDisk();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行全部任务数据同步
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbInfo")
|
||||
public ApiResult<?> jobSyncAllTask(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncAllTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行单个任务
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbByInfo")
|
||||
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncOneTask(taskId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +1,32 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.DbConfig;
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import com.mini.capi.biz.domain.SyncTask;
|
||||
import com.mini.capi.biz.service.DbConfigService;
|
||||
import com.mini.capi.biz.service.SyncTablesViewService;
|
||||
import com.mini.capi.biz.service.SyncTaskService;
|
||||
import com.mini.capi.config.DataSourceConfig;
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.domain.SelectOption;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Data;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RestController
|
||||
@RequestMapping("/Sys/data")
|
||||
public class dataController {
|
||||
|
||||
|
||||
@@ -26,12 +35,11 @@ public class dataController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbConfigService dbConfigService;
|
||||
private DbConfigService configService;
|
||||
|
||||
@GetMapping("/Sys/data/list")
|
||||
public String listPage() {
|
||||
return "views/data/list";
|
||||
}
|
||||
|
||||
@Resource
|
||||
private SyncTablesViewService tablesViewService;
|
||||
|
||||
|
||||
@Data
|
||||
@@ -73,6 +81,28 @@ public class dataController {
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
static class TableInfo implements Serializable {
|
||||
private TabDetail tabDetail;
|
||||
private List<TabColumns> tabColumns;
|
||||
private long pkCnt;
|
||||
private long idxCnt;
|
||||
private long colCnt;
|
||||
private String ddlSql;
|
||||
private String selectSql;
|
||||
|
||||
public TableInfo(TabDetail tabDetail, List<TabColumns> tabColumns, long pkCnt, long idxCnt, long colCnt, String ddlSql, String selectSql) {
|
||||
this.tabDetail = tabDetail;
|
||||
this.tabColumns = tabColumns;
|
||||
this.pkCnt = pkCnt;
|
||||
this.idxCnt = idxCnt;
|
||||
this.colCnt = colCnt;
|
||||
this.ddlSql = ddlSql;
|
||||
this.selectSql = selectSql;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String buildSelect(List<TabColumns> columns, TabDetail table) {
|
||||
if (columns == null || columns.isEmpty() || table == null) {
|
||||
return "-- no columns or table info";
|
||||
@@ -160,18 +190,78 @@ public class dataController {
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/Sys/data/getTableDetail")
|
||||
public String getTableDetail(String taskId, Model model) {
|
||||
SyncTask task = syncTaskService.getById(taskId);
|
||||
DbConfig dbConfig = dbConfigService.getById(task.getSourceDbId());
|
||||
List<TabDetail> data;
|
||||
List<TabColumns> columns;
|
||||
/**
|
||||
* 获取数据配置表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getDbList")
|
||||
public ApiResult<List<SelectOption>> getDbList() {
|
||||
try {
|
||||
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
// 补充参数传递
|
||||
String querySql = "SELECT CREATE_TIME,TABLE_NAME,TABLE_COMMENT,MAX_DATA_LENGTH,UPDATE_TIME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
List<DbConfig> configs = configService.list();
|
||||
List<SelectOption> selectOptions = configs.stream()
|
||||
.map(config -> new SelectOption(
|
||||
config.getDbId(), // 下拉框value(绑定值)
|
||||
config.getDbName(), // 下拉框label(显示文本)
|
||||
false // 【关键注释】说明禁用原因(如:所有数据库默认禁用选择,需申请后启用)
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
return ApiResult.success(selectOptions);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据字段表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/getTableList")
|
||||
public ApiResult<List<SyncTablesView>> getTableList(String dbId, String targetTable) {
|
||||
try {
|
||||
List<SyncTablesView> tablesViews = tablesViewService.list(
|
||||
new QueryWrapper<SyncTablesView>()
|
||||
.eq(StringUtils.hasText(dbId), "db_id", dbId)
|
||||
.and(StringUtils.hasText(targetTable),
|
||||
w -> w.like("target_table", targetTable)
|
||||
.or()
|
||||
.like("task_name", targetTable))
|
||||
.orderByDesc("create_time")
|
||||
);
|
||||
return ApiResult.success(tablesViews);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据表属性
|
||||
*
|
||||
* @param taskId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/Sys/data/getTableDetail")
|
||||
public ApiResult<TableInfo> getTableDetail(String taskId) {
|
||||
// 获取基础数据
|
||||
SyncTask task = syncTaskService.getById(taskId);
|
||||
DbConfig dbConfig = configService.getById(task.getSourceDbId());
|
||||
JdbcTemplate jdbcTemplate;
|
||||
try {
|
||||
// 统一创建JdbcTemplate,避免重复初始化
|
||||
jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
} catch (Exception e) {
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
|
||||
// 查询表基本信息
|
||||
List<TabDetail> data;
|
||||
try {
|
||||
String tableQuerySql = "SELECT CREATE_TIME,TABLE_NAME,TABLE_COMMENT,MAX_DATA_LENGTH,UPDATE_TIME " +
|
||||
"FROM information_schema.TABLES " +
|
||||
"WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
data = jdbcTemplate.query(
|
||||
querySql,
|
||||
tableQuerySql,
|
||||
(rs, rowNum) -> new TabDetail(
|
||||
rs.getString("CREATE_TIME"),
|
||||
dbConfig.getDbName(),
|
||||
@@ -185,16 +275,17 @@ public class dataController {
|
||||
);
|
||||
data.sort(Comparator.comparing(TabDetail::getTableName));
|
||||
} catch (Exception e) {
|
||||
data = Collections.emptyList();
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
// 查询表列信息
|
||||
List<TabColumns> columns;
|
||||
try {
|
||||
JdbcTemplate jdbcTemplate = DataSourceConfig.createJdbcTemplate(dbConfig);
|
||||
// 补充参数传递
|
||||
String querySql = "SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,COLUMN_TYPE,COLUMN_COMMENT,COLUMN_KEY FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
String columnQuerySql = "SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,COLUMN_TYPE,COLUMN_COMMENT,COLUMN_KEY " +
|
||||
"FROM information_schema.COLUMNS " +
|
||||
"WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
|
||||
columns = jdbcTemplate.query(
|
||||
querySql,
|
||||
columnQuerySql,
|
||||
(rs, rowNum) -> new TabColumns(
|
||||
rs.getString("TABLE_NAME"),
|
||||
rs.getInt("ORDINAL_POSITION"),
|
||||
@@ -208,26 +299,29 @@ public class dataController {
|
||||
);
|
||||
columns.sort(Comparator.comparing(TabColumns::getSort));
|
||||
} catch (Exception e) {
|
||||
columns = Collections.emptyList();
|
||||
System.out.println(e.getMessage());
|
||||
return ApiResult.error(401, e.getMessage());
|
||||
}
|
||||
// 在查询完表结构后
|
||||
|
||||
// 计算表结构统计信息
|
||||
long primaryKeyCnt = columns.stream()
|
||||
.filter(c -> "PRI".equalsIgnoreCase(c.getKeyType()))
|
||||
.count();
|
||||
long indexCnt = columns.stream()
|
||||
.filter(c -> !"PRI".equalsIgnoreCase(c.getKeyType()) && !c.getKeyType().isBlank())
|
||||
.count()
|
||||
+ 1; // 主键索引也算 1 个
|
||||
.count() + 1; // 包含主键索引
|
||||
long colCnt = columns.size();
|
||||
model.addAttribute("pkCnt", primaryKeyCnt);
|
||||
model.addAttribute("idxCnt", indexCnt);
|
||||
model.addAttribute("colCnt", colCnt);
|
||||
model.addAttribute("data", data);
|
||||
model.addAttribute("columns", columns);
|
||||
model.addAttribute("ddlSql", buildDDL(columns, data.get(0)));
|
||||
model.addAttribute("selectSql", buildSelect(columns, data.get(0)));
|
||||
return "views/data/detail";
|
||||
|
||||
// 构建返回结果
|
||||
TableInfo tableInfo = new TableInfo(
|
||||
data.get(0),
|
||||
columns,
|
||||
primaryKeyCnt,
|
||||
indexCnt,
|
||||
colCnt,
|
||||
buildDDL(columns, data.get(0)),
|
||||
buildSelect(columns, data.get(0))
|
||||
);
|
||||
return ApiResult.success(tableInfo);
|
||||
}
|
||||
|
||||
|
||||
9
src/main/java/com/mini/capi/sys/App/hostController.java
Normal file
9
src/main/java/com/mini/capi/sys/App/hostController.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/hosts")
|
||||
public class hostController {
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
package com.mini.capi.sys.App;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.ApiMenus;
|
||||
@@ -10,6 +10,7 @@ import com.mini.capi.biz.service.ApiUserService;
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.auth.Result;
|
||||
import com.mini.capi.sys.domain.ModuleMenuDTO;
|
||||
import com.mini.capi.utils.KeyUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.Data;
|
||||
@@ -20,10 +21,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/login")
|
||||
public class loginPageController {
|
||||
public class loginController {
|
||||
|
||||
|
||||
@Resource
|
||||
@@ -58,11 +58,14 @@ public class loginPageController {
|
||||
*/
|
||||
private String uname;
|
||||
|
||||
private String token;
|
||||
|
||||
// 构造方法(从实体类转换)
|
||||
public ApiUserDTO(ApiUser apiUser) {
|
||||
public ApiUserDTO(ApiUser apiUser, String token) {
|
||||
this.userId = apiUser.getUserId();
|
||||
this.username = apiUser.getApiUser();
|
||||
this.uname = apiUser.getUname();
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +94,25 @@ public class loginPageController {
|
||||
// 可记录登录失败日志,用于后续风控
|
||||
return Result.error(102, "账户或密码错误");
|
||||
}
|
||||
session.setAttribute("token", apiUser);
|
||||
ApiUserDTO userDTO = new ApiUserDTO(apiUser);
|
||||
session.setAttribute("userInfo", apiUser);
|
||||
ApiUserDTO userDTO = new ApiUserDTO(apiUser, KeyUtil.ObjKey(32, 0));
|
||||
return Result.success("登录成功", userDTO);
|
||||
} catch (Exception e) {
|
||||
return Result.error(103, "登录失败,请稍后重试");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/userLogout")
|
||||
public Result loginOut(HttpSession session) {
|
||||
try {
|
||||
session.removeAttribute("userInfo"); // 只清 token
|
||||
session.invalidate();
|
||||
return Result.error(200, "退出成功");
|
||||
} catch (Exception e) {
|
||||
return Result.error(500, "退出失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/getModules")
|
||||
public ApiResult<List<ModuleMenuDTO>> getModules() {
|
||||
@@ -1,31 +1,40 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest; // 注意这里
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
public class CustomErrorController implements ErrorController {
|
||||
|
||||
@RequestMapping("/error")
|
||||
public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) {
|
||||
public Object handleError(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
|
||||
// 1. 前端路由:统一转发到 index.html
|
||||
if (uri.startsWith("/cApi/index/")) {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
|
||||
// 2. 其他 404:返回 JSON
|
||||
HttpStatus status = getStatus(request);
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("status", status.value());
|
||||
body.put("error", status.getReasonPhrase());
|
||||
body.put("message", "访问的资源不存在");
|
||||
body.put("path", request.getRequestURI());
|
||||
return ResponseEntity.status(status).body(body);
|
||||
return ResponseEntity
|
||||
.status(status)
|
||||
.body(Map.of(
|
||||
"status", status.value(),
|
||||
"error", status.getReasonPhrase(),
|
||||
"message", "访问的资源不存在",
|
||||
"path", uri
|
||||
));
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
Integer code = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
|
||||
return (code != null) ? HttpStatus.valueOf(code) : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
return code != null ? HttpStatus.valueOf(code) : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class hostController {
|
||||
|
||||
|
||||
/**
|
||||
* 主机登录
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/Sys/app/host")
|
||||
public String listPage() {
|
||||
return "views/ssh/index";
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class loginController {
|
||||
|
||||
@GetMapping("/login")
|
||||
public String loginPage() {
|
||||
return "forward:/index.html";
|
||||
}
|
||||
|
||||
//
|
||||
// /**
|
||||
// * 退出登录:清空 session 并返回到退出成功页面
|
||||
// */
|
||||
// @GetMapping("/userLogout")
|
||||
// public String logout(HttpSession session) {
|
||||
// session.invalidate();
|
||||
// return "index";
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 主页
|
||||
// */
|
||||
// @GetMapping("/welcome")
|
||||
// public String welcomePage() {
|
||||
// return "views/demo";
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 系统首页-控制台
|
||||
// */
|
||||
// @GetMapping("/home")
|
||||
// public String homePage() {
|
||||
// return "views/home";
|
||||
// }
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class sysController {
|
||||
|
||||
|
||||
@GetMapping("/Sys/sys/icon")
|
||||
public String getIcon() {
|
||||
return "views/icon";
|
||||
}
|
||||
}
|
||||
28
src/main/java/com/mini/capi/sys/domain/SelectOption.java
Normal file
28
src/main/java/com/mini/capi/sys/domain/SelectOption.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.mini.capi.sys.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class SelectOption implements Serializable {
|
||||
|
||||
|
||||
private String value;
|
||||
|
||||
|
||||
private String label;
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
public SelectOption() {
|
||||
}
|
||||
|
||||
// 全参构造函数
|
||||
public SelectOption(String value, String label, boolean disabled) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mini.capi.biz.domain.DbConfig;
|
||||
import com.mini.capi.biz.domain.SyncTablesView;
|
||||
import com.mini.capi.biz.service.DbConfigService;
|
||||
import com.mini.capi.biz.service.SyncTablesViewService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController // ← 关键
|
||||
@RequestMapping("/Sys/data")
|
||||
public class dataPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbConfigService configService;
|
||||
|
||||
|
||||
@Resource
|
||||
private SyncTablesViewService tablesViewService;
|
||||
|
||||
|
||||
@GetMapping("/getDbList")
|
||||
public List<DbConfig> getDbList() {
|
||||
return configService.list();
|
||||
}
|
||||
|
||||
@GetMapping("/getTableList")
|
||||
public List<SyncTablesView> getTableList(String dbId, String targetTable) {
|
||||
return tablesViewService.list(
|
||||
new QueryWrapper<SyncTablesView>()
|
||||
.eq(StringUtils.hasText(dbId), "db_id", dbId)
|
||||
.and(StringUtils.hasText(targetTable),
|
||||
w -> w.like("target_table", targetTable)
|
||||
.or()
|
||||
.like("task_name", targetTable))
|
||||
.orderByDesc("create_time")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.model.TabResult;
|
||||
import com.mini.capi.sys.service.DbService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/dbs")
|
||||
public class dbPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private DbService dbService;
|
||||
|
||||
/**
|
||||
* 获取MySQL的当前连接下的所有数据表
|
||||
*/
|
||||
@GetMapping("/getApiSourceTables")
|
||||
public ApiResult<List<TabResult>> listSourceTables(String token, String dbId) {
|
||||
// 1. 验证token有效性
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.listSourceTables(dbId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 运行单个任务
|
||||
*/
|
||||
@GetMapping("/getTaskSyncDbByInfo")
|
||||
public ApiResult<?> jobSyncOneTask(String token, String taskId) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return dbService.jobSyncOneTask(taskId);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.mini.capi.sys.pageController;
|
||||
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.sys.service.HostService;
|
||||
import com.mini.capi.utils.vToken;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/hosts")
|
||||
public class hostPageController {
|
||||
|
||||
|
||||
@Resource
|
||||
private HostService hostService;
|
||||
|
||||
|
||||
@GetMapping("/getApiInfo")
|
||||
public ApiResult<List<HostService.SnapshotDTO>> getApiInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getApiInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取容器列表
|
||||
*/
|
||||
@GetMapping("/getApiDockerInfo")
|
||||
public ApiResult<?> getDockerInfo(String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.getDockerInfo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启动容器
|
||||
*/
|
||||
@GetMapping("/getApiStartDockerInfo")
|
||||
public ApiResult<?> startDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.startDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止容器
|
||||
*/
|
||||
@GetMapping("/getApiStopDockerInfo")
|
||||
public ApiResult<?> stopDockerInfo(String id, String token) {
|
||||
if (vToken.isValidToken(token)) {
|
||||
return ApiResult.error(401, "无效的访问令牌");
|
||||
}
|
||||
return hostService.stopDockerInfo(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
81
src/main/java/com/mini/capi/utils/AESUtil.java
Normal file
81
src/main/java/com/mini/capi/utils/AESUtil.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package com.mini.capi.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.commons.net.util.Base64;
|
||||
|
||||
public class AESUtil {
|
||||
public static String key = "AD42F6697B035B7580E4FEF93BE20BAD";
|
||||
private static String charset = "utf-8";
|
||||
// 偏移量
|
||||
private static int offset = 16;
|
||||
private static String transformation = "AES/CBC/PKCS5Padding";
|
||||
private static String algorithm = "AES";
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static String encrypt(String content) {
|
||||
return encrypt(content, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static String decrypt(String content) {
|
||||
return decrypt(content, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param content 需要加密的内容
|
||||
* @param key 加密密码
|
||||
* @return
|
||||
*/
|
||||
public static String encrypt(String content, String key) {
|
||||
try {
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
|
||||
IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
|
||||
Cipher cipher = Cipher.getInstance(transformation);
|
||||
byte[] byteContent = content.getBytes(charset);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
|
||||
byte[] result = cipher.doFinal(byteContent);
|
||||
return new Base64().encodeToString(result).replaceAll("[\\s*\t\n\r]", ""); // 加密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* AES(256)解密
|
||||
*
|
||||
* @param content 待解密内容
|
||||
* @param key 解密密钥
|
||||
* @return 解密之后
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String decrypt(String content, String key) {
|
||||
try {
|
||||
|
||||
SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
|
||||
IvParameterSpec iv = new IvParameterSpec(key.getBytes(charset), 0, offset);
|
||||
Cipher cipher = Cipher.getInstance(transformation);
|
||||
cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化
|
||||
byte[] result = cipher.doFinal(new Base64().decode(content));
|
||||
return new String(result).replaceAll("[\\s*\t\n\r]", ""); // 解密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
48
src/main/java/com/mini/capi/utils/KeyUtil.java
Normal file
48
src/main/java/com/mini/capi/utils/KeyUtil.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.mini.capi.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class KeyUtil {
|
||||
|
||||
public static String ObjKey(int length, int type) {
|
||||
Random random = new Random();
|
||||
StringBuffer key = new StringBuffer();
|
||||
if (type == 1) {
|
||||
String str = "0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(10);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else if (type == 2) {
|
||||
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(36);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else if (type == 3) {
|
||||
String str = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(36);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
} else {
|
||||
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
//从62个的数字或字母中选择
|
||||
int number = random.nextInt(62);
|
||||
//将产生的数字通过length次承载到key中
|
||||
key.append(str.charAt(number));
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,5 @@ webssh.file.upload-max-size=100MB
|
||||
webssh.file.temp-dir=/ogsapp/temp/webssh-uploads
|
||||
webssh.collaboration.enabled=true
|
||||
webssh.collaboration.max-participants=10
|
||||
webssh.collaboration.session-timeout=3600000
|
||||
webssh.collaboration.session-timeout=3600000
|
||||
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
|
||||
@@ -1 +0,0 @@
|
||||
const n={};n.render=function(n,e){return null};export{n as default};
|
||||
@@ -1 +0,0 @@
|
||||
@charset "UTF-8";.login-wrapper[data-v-c93922d0]{height:100vh;display:flex;align-items:center;justify-content:flex-end;padding-right:200px;background:linear-gradient(120deg,rgba(79,172,254,.7) 0%,rgba(0,242,254,.7) 50%,rgba(122,90,248,.7) 100%),url(/cApi/assets/backImg.5cfc718b.jpg) center center no-repeat;background-blend-mode:overlay;background-size:cover}.login-text[data-v-c93922d0]{text-align:center;color:#fff;width:800px;padding:32px 48px;border-radius:8px}.login-card[data-v-c93922d0]{width:520px;padding:32px 48px;border-radius:8px;box-shadow:0 8px 24px #0000001f}.login-header[data-v-c93922d0]{text-align:center;margin-bottom:32px}.login-header .logo[data-v-c93922d0]{width:64px;height:64px;margin-bottom:12px}.login-header h1[data-v-c93922d0]{font-size:24px;font-weight:600;margin:0}.login-header p[data-v-c93922d0]{font-size:14px;color:#8c8c8c;margin:8px 0 0}
|
||||
1
src/main/resources/static/assets/Login.2dfba5c8.css
Normal file
1
src/main/resources/static/assets/Login.2dfba5c8.css
Normal file
@@ -0,0 +1 @@
|
||||
@charset "UTF-8";.login-wrapper[data-v-c077d3e4]{height:100vh;display:flex;align-items:center;justify-content:flex-end;padding-right:200px;background:linear-gradient(120deg,rgba(79,172,254,.7) 0%,rgba(0,242,254,.7) 50%,rgba(122,90,248,.7) 100%),url(/cApi/assets/backImg.5cfc718b.jpg) center center no-repeat;background-blend-mode:overlay;background-size:cover}.login-text[data-v-c077d3e4]{text-align:center;color:#fff;width:800px;padding:32px 48px;border-radius:8px}.login-card[data-v-c077d3e4]{width:520px;padding:32px 48px;border-radius:8px;box-shadow:0 8px 24px #0000001f}.login-header[data-v-c077d3e4]{text-align:center;margin-bottom:32px}.login-header .logo[data-v-c077d3e4]{width:64px;height:64px;margin-bottom:12px}.login-header h1[data-v-c077d3e4]{font-size:24px;font-weight:600;margin:0}.login-header p[data-v-c077d3e4]{font-size:14px;color:#8c8c8c;margin:8px 0 0}
|
||||
File diff suppressed because one or more lines are too long
1
src/main/resources/static/assets/Login.b6228c81.js
Normal file
1
src/main/resources/static/assets/Login.b6228c81.js
Normal file
@@ -0,0 +1 @@
|
||||
import{d as S,_ as E,a as h,u as D,r as f,b as k,o as w,c as y,e as u,w as o,f as s,g as c,h as _,U as x,L as b,i as L,m}from"./index.04365c99.js";import{a as N}from"./auth.545ce83f.js";var O="/cApi/assets/logo.03d6d6da.png";const U=S("auth",{state:()=>({token:localStorage.getItem("token")||null,userInfo:localStorage.getItem("userInfo")?JSON.parse(localStorage.getItem("userInfo")):null}),actions:{setAuthInfo(i,r){this.token=i,this.userInfo=r,localStorage.setItem("token",i),localStorage.setItem("userInfo",JSON.stringify(r))},clearAuthInfo(){this.token=null,this.userInfo=null,localStorage.removeItem("token"),localStorage.removeItem("userInfo")}}});const J={class:"login-wrapper"},R=h({__name:"Login",setup(i){const r=D(),g=f(),n=f(!1),t=k({account:"",password:""}),F={account:[{required:!0,message:"\u8BF7\u8F93\u5165\u7528\u6237\u540D"}],password:[{required:!0,message:"\u8BF7\u8F93\u5165\u5BC6\u7801"}]},B=async()=>{if(n.value)return;n.value=!0;const p=U();try{const e=await N(t);if(e.code===200&&e.data){const l=e.data.token,a=JSON.stringify(e.data);localStorage.setItem("token",l),localStorage.setItem("userInfo",a),p.setAuthInfo(l,a),m.success(e.msg||"\u767B\u5F55\u6210\u529F"),setTimeout(()=>{r.replace("/index/console")},800);return}m.error(e.msg||"\u767B\u5F55\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u8D26\u53F7\u5BC6\u7801")}catch(e){console.error("\u767B\u5F55\u8BF7\u6C42\u5F02\u5E38:",e),m.error("\u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u540E\u91CD\u8BD5")}finally{n.value=!1}};return(p,e)=>{const l=s("a-input"),a=s("a-form-item"),v=s("a-input-password"),I=s("a-button"),A=s("a-form"),C=s("a-card");return w(),y("div",J,[u(C,{class:"login-card",bordered:!1},{default:o(()=>[e[3]||(e[3]=c("div",{class:"login-header"},[c("img",{class:"logo",src:O,alt:"logo"}),c("h1",null,"cApi\u7BA1\u7406\u7CFB\u7EDF"),c("p",null,"\u5B89\u5168\u3001\u9AD8\u6548\u7684\u4E00\u7AD9\u5F0F\u7BA1\u7406\u89E3\u51B3\u65B9\u6848\uFF0C\u4E3A\u60A8\u7684\u4E1A\u52A1\u4FDD\u9A7E\u62A4\u822A")],-1)),u(A,{ref_key:"formRef",ref:g,model:t,rules:F,size:"large",onFinish:B},{default:o(()=>[u(a,{name:"account"},{default:o(()=>[u(l,{value:t.account,"onUpdate:value":e[0]||(e[0]=d=>t.account=d),placeholder:"\u8BF7\u8F93\u5165\u7528\u6237\u540D","allow-clear":""},{prefix:o(()=>[u(_(x))]),_:1},8,["value"])]),_:1}),u(a,{name:"password"},{default:o(()=>[u(v,{value:t.password,"onUpdate:value":e[1]||(e[1]=d=>t.password=d),placeholder:"\u8BF7\u8F93\u5165\u5BC6\u7801","allow-clear":""},{prefix:o(()=>[u(_(b))]),_:1},8,["value"])]),_:1}),u(a,null,{default:o(()=>[u(I,{type:"primary","html-type":"submit",loading:n.value,block:""},{default:o(()=>[...e[2]||(e[2]=[L(" \u767B\u5F55 ",-1)])]),_:1},8,["loading"])]),_:1})]),_:1},8,["model"])]),_:1})])}}});var T=E(R,[["__scopeId","data-v-c077d3e4"]]);export{T as default};
|
||||
1
src/main/resources/static/assets/Main.44989b63.js
Normal file
1
src/main/resources/static/assets/Main.44989b63.js
Normal file
@@ -0,0 +1 @@
|
||||
import{_ as r}from"./index.04365c99.js";const e={};function j(_,c){return" jjjjjjjjj "}var t=r(e,[["render",j]]);export{t as default};
|
||||
1
src/main/resources/static/assets/NotFound.4eaa0d77.js
Normal file
1
src/main/resources/static/assets/NotFound.4eaa0d77.js
Normal file
@@ -0,0 +1 @@
|
||||
import{_ as r}from"./index.04365c99.js";const e={};function t(_,c){return" \u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876\u9876 "}var o=r(e,[["render",t]]);export{o as default};
|
||||
6
src/main/resources/static/assets/auth.545ce83f.js
Normal file
6
src/main/resources/static/assets/auth.545ce83f.js
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/static/assets/icon.704eed01.css
Normal file
1
src/main/resources/static/assets/icon.704eed01.css
Normal file
@@ -0,0 +1 @@
|
||||
.icon-gallery[data-v-64d10c62]{width:100%;box-sizing:border-box}.search-input[data-v-64d10c62]{max-width:400px}.icons-grid[data-v-64d10c62]{width:100%;box-sizing:border-box}.icon-item[data-v-64d10c62]:hover{border-color:#1890ff;box-shadow:0 2px 8px #00000014}.icon-name[data-v-64d10c62]{font-size:12px;color:#595959;text-align:center;word-break:break-all;max-width:100%}.copy-buttons[data-v-64d10c62]{display:flex;gap:8px;margin-top:8px;width:100%;justify-content:center}.copy-btn[data-v-64d10c62]{padding:2px 8px!important;font-size:12px!important}.empty-state[data-v-64d10c62]{padding:40px 0;text-align:center}.copy-message[data-v-64d10c62]{position:fixed;bottom:24px;left:50%;transform:translate(-50%);z-index:1000}
|
||||
1
src/main/resources/static/assets/icon.a450540c.js
Normal file
1
src/main/resources/static/assets/icon.a450540c.js
Normal file
@@ -0,0 +1 @@
|
||||
import{_ as U,a as W,I as q,r as a,n as u,o as s,c as l,j as g,t as p,g as w,F as G,y as H,A as m,e as r,f as y,z as J,v as K,w as S,h as F,D as T,i as z,k as B}from"./index.04365c99.js";const Q=["onMouseenter"],X={class:"icon-name"},Y={key:0,class:"copy-buttons"},Z={key:1,class:"empty-state"},ee=W({__name:"icon",props:{showSearch:{type:Boolean,default:!0},searchSize:{type:String,default:"middle"},columns:{type:Number,default:6},iconSize:{type:Number,default:24},itemPadding:{type:String,default:"16px"},messageDuration:{type:Number,default:2e3}},setup(c){const n=c,N=["createFromIconfontCN","getTwoToneColor","setTwoToneColor","default","CopyOutlined"],_=Object.entries(q).filter(([e])=>!N.includes(e)).map(([e,t])=>({name:e,component:t})),i=a(""),C=u(()=>i.value?_.filter(({name:e})=>e.toLowerCase().includes(i.value.toLowerCase())):_),f=a(""),v=a(!1),h=a(""),D=a("success");function M(e){f.value=e}function $(){f.value=""}function E(e){const t=`<${e} />`;x(t).then(()=>{d(`\u5DF2\u590D\u5236: ${t}`,"success")}).catch(()=>{d("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u590D\u5236","error")})}function I(e){x(e).then(()=>{d(`\u5DF2\u590D\u5236: ${e}`,"success")}).catch(()=>{d("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u590D\u5236","error")})}async function x(e){try{return await navigator.clipboard.writeText(e),!0}catch(t){return console.error("\u65E0\u6CD5\u590D\u5236\u6587\u672C: ",t),!1}}function d(e,t){h.value=e,D.value=t,v.value=!0,setTimeout(()=>{v.value=!1},n.messageDuration)}const L=u(()=>({padding:"16px",backgroundColor:"#f5f5f5",borderRadius:"4px"})),A=u(()=>({display:"grid",gridTemplateColumns:`repeat(${n.columns}, 1fr)`,gap:"12px",marginTop:n.showSearch?"16px":0})),V=u(()=>({display:"flex",flexDirection:"column",alignItems:"center",backgroundColor:"#fff",border:"1px solid #e8e8e8",borderRadius:"6px",padding:n.itemPadding,cursor:"pointer",transition:"all 0.2s"})),O=u(()=>({fontSize:`${n.iconSize}px`,color:"#262626",marginBottom:"8px"}));return(e,t)=>{const j=y("a-input"),b=y("a-button"),P=y("a-empty"),R=y("a-message");return s(),l("div",{class:"icon-gallery",style:m(L.value)},[c.showSearch?(s(),g(j,{key:0,value:i.value,"onUpdate:value":t[0]||(t[0]=o=>i.value=o),placeholder:"\u641C\u7D22\u56FE\u6807\u540D\u79F0...","allow-clear":"",class:"search-input",size:c.searchSize},null,8,["value","size"])):p("",!0),w("div",{class:"icons-grid",style:m(A.value)},[(s(!0),l(G,null,H(C.value,o=>(s(),l("div",{key:o.name,class:"icon-item",style:m(V.value),onMouseenter:k=>M(o.name),onMouseleave:$},[(s(),g(J(o.component),{class:"icon",style:m(O.value)},null,8,["style"])),w("span",X,K(o.name),1),f.value===o.name?(s(),l("div",Y,[r(b,{type:"primary",size:"small",onClick:B(k=>E(o.name),["stop"]),class:"copy-btn"},{default:S(()=>[r(F(T),{class:"mr-1"}),t[1]||(t[1]=z("\u6807\u7B7E ",-1))]),_:1},8,["onClick"]),r(b,{type:"default",size:"small",onClick:B(k=>I(o.name),["stop"]),class:"copy-btn"},{default:S(()=>[r(F(T),{class:"mr-1"}),t[2]||(t[2]=z("\u540D\u79F0 ",-1))]),_:1},8,["onClick"])])):p("",!0)],44,Q))),128))],4),C.value.length===0?(s(),l("div",Z,[r(P,{description:"\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u56FE\u6807"})])):p("",!0),v.value?(s(),g(R,{key:2,content:h.value,type:D.value,duration:c.messageDuration,class:"copy-message"},null,8,["content","type","duration"])):p("",!0)],4)}}});var oe=U(ee,[["__scopeId","data-v-64d10c62"]]);export{oe as default};
|
||||
1
src/main/resources/static/assets/index.02dafd63.js
Normal file
1
src/main/resources/static/assets/index.02dafd63.js
Normal file
@@ -0,0 +1 @@
|
||||
import{_ as r}from"./index.04365c99.js";const e={};function _(c,n){return" app "}var a=r(e,[["render",_]]);export{a as default};
|
||||
574
src/main/resources/static/assets/index.04365c99.js
Normal file
574
src/main/resources/static/assets/index.04365c99.js
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/static/assets/index.19f796de.css
Normal file
1
src/main/resources/static/assets/index.19f796de.css
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/static/assets/index.531b96f1.js
Normal file
1
src/main/resources/static/assets/index.531b96f1.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type="range"]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
||||
1
src/main/resources/static/assets/index.737965c1.css
Normal file
1
src/main/resources/static/assets/index.737965c1.css
Normal file
@@ -0,0 +1 @@
|
||||
.empty-page-container[data-v-2de931e9]{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:#fff;border-radius:8px;box-shadow:0 1px 2px #0000000d}.empty-content[data-v-2de931e9]{width:100%;max-width:600px;padding:48px 24px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:20px}.empty-icon[data-v-2de931e9]{width:80px;height:80px;border-radius:50%;background-color:#e8f4ff;display:flex;align-items:center;justify-content:center;color:#1890ff}.empty-icon[data-v-2de931e9] svg{width:40px;height:40px}.empty-title[data-v-2de931e9]{font-size:18px;font-weight:500;color:#333;margin:0}.empty-desc[data-v-2de931e9]{font-size:14px;color:#666;line-height:1.6;margin:0}.empty-actions[data-v-2de931e9]{display:flex;gap:12px;margin-top:8px}.empty-meta[data-v-2de931e9]{margin-top:16px;display:flex;flex-wrap:wrap;justify-content:center;gap:16px;font-size:12px;color:#999}@media (max-width: 768px){.empty-content[data-v-2de931e9]{padding:32px 16px;gap:16px}.empty-icon[data-v-2de931e9]{width:64px;height:64px}.empty-icon[data-v-2de931e9] svg{width:32px;height:32px}.empty-title[data-v-2de931e9]{font-size:16px}.empty-meta[data-v-2de931e9]{flex-direction:column;gap:8px}}
|
||||
@@ -1 +0,0 @@
|
||||
import{r as e,o as r,c as t,a as o,b as n,d as s,A as i}from"./vendor.a8167e4a.js";!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver((e=>{for(const t of e)if("childList"===t.type)for(const e of t.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&r(e)})).observe(document,{childList:!0,subtree:!0})}function r(e){if(e.ep)return;e.ep=!0;const r=function(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerpolicy&&(r.referrerPolicy=e.referrerpolicy),"use-credentials"===e.crossorigin?r.credentials="include":"anonymous"===e.crossorigin?r.credentials="omit":r.credentials="same-origin",r}(e);fetch(e.href,r)}}();const c={};c.render=function(o,n){const s=e("router-view");return r(),t(s)};const a={},d=function(e,r){return r&&0!==r.length?Promise.all(r.map((e=>{if((e=`/cApi/${e}`)in a)return;a[e]=!0;const r=e.endsWith(".css"),t=r?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${e}"]${t}`))return;const o=document.createElement("link");return o.rel=r?"stylesheet":"modulepreload",r||(o.as="script",o.crossOrigin=""),o.href=e,document.head.appendChild(o),r?new Promise(((e,r)=>{o.addEventListener("load",e),o.addEventListener("error",r)})):void 0}))).then((()=>e())):e()},l=[{path:"/",redirect:"/login"},{path:"/login",name:"Login",component:()=>d((()=>import("./Login.ab12ce3d.js")),["assets/Login.ab12ce3d.js","assets/Login.008b81ee.css","assets/vendor.a8167e4a.js"])},{path:"/dashboard",name:"Dashboard",component:()=>d((()=>import("./Dashboard.cd76d04c.js")),[]),meta:{requiresAuth:!0}}],u=o({history:n("/cApi/"),routes:l});s(c).use(i).use(u).mount("#app");
|
||||
4
src/main/resources/static/assets/index.bc67c2d1.js
Normal file
4
src/main/resources/static/assets/index.bc67c2d1.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import{_ as B,a as E,r as d,o as p,c as r,g as e,e as t,h as a,E as A,i as s,w as F,f as m,P as c,Q as C}from"./index.04365c99.js";const _={class:"empty-page-container"},D={class:"empty-content"},v={class:"empty-icon"},y={class:"empty-actions"},f=E({__name:"index",setup(x){const n=d("\u7A7A\u767D\u6A21\u677F\u9875\u9762"),l=()=>{console.log(`[${n.value}] \u89E6\u53D1\u300C\u521B\u5EFA\u5185\u5BB9\u300D\u64CD\u4F5C`),alert("\u53EF\u5728\u6B64\u5904\u5B9E\u73B0\u300C\u521B\u5EFA\u5185\u5BB9\u300D\u7684\u4E1A\u52A1\u903B\u8F91")},i=()=>{console.log(`[${n.value}] \u67E5\u770B\u4F7F\u7528\u6307\u5357`),alert(`\u4F7F\u7528\u6307\u5357\uFF1A
|
||||
1. \u6B64\u9875\u9762\u5DF2\u9002\u914D\u7236\u5BB9\u5668\u81EA\u9002\u5E94\u5C3A\u5BF8
|
||||
2. \u53EF\u5728 empty-content \u5185\u6DFB\u52A0\u4E1A\u52A1\u7EC4\u4EF6
|
||||
3. \u6837\u5F0F\u53EF\u53C2\u8003\u539F\u9879\u76EE\u89C4\u8303\u8C03\u6574`)};return(g,u)=>{const o=m("a-button");return p(),r("div",_,[e("div",D,[e("div",v,[t(a(A))]),u[2]||(u[2]=e("h2",{class:"empty-title"},"\u8FD9\u662F\u4E00\u4E2A\u7A7A\u767D\u9875\u9762",-1)),u[3]||(u[3]=e("p",{class:"empty-desc"},[s(" \u4F60\u53EF\u4EE5\u5728\u8FD9\u91CC\u6269\u5C55\u529F\u80FD\uFF0C\u6BD4\u5982\u6DFB\u52A0\u6570\u636E\u5C55\u793A\u3001\u8868\u5355\u63D0\u4EA4\u3001\u56FE\u8868\u5206\u6790\u7B49\u5185\u5BB9"),e("br"),s(" \u9875\u9762\u5DF2\u9002\u914D\u7236\u5BB9\u5668\u5C3A\u5BF8\uFF0C\u652F\u6301\u9AD8\u5EA6/\u5BBD\u5EA6\u81EA\u9002\u5E94 ")],-1)),e("div",y,[t(o,{type:"primary",onClick:l},{default:F(()=>[t(a(c),{class:"mr-2"}),u[0]||(u[0]=s(" \u521B\u5EFA\u5185\u5BB9 ",-1))]),_:1}),t(o,{onClick:i,style:{"margin-left":"12px"}},{default:F(()=>[t(a(C),{class:"mr-2"}),u[1]||(u[1]=s(" \u67E5\u770B\u4F7F\u7528\u6307\u5357 ",-1))]),_:1})]),u[4]||(u[4]=e("div",{class:"empty-meta"},[e("span",{class:"meta-item"},"\u9875\u9762\u8DEF\u5F84\uFF1A@/views/EmptyTemplatePage.vue"),e("span",{class:"meta-item"},"\u9002\u914D\u573A\u666F\uFF1A\u5217\u8868\u9875\u3001\u8BE6\u60C5\u9875\u3001\u8868\u5355\u9875\u7B49\u521D\u59CB\u6A21\u677F")],-1))])])}}});var N=B(f,[["__scopeId","data-v-2de931e9"]]);export{N as default};
|
||||
1
src/main/resources/static/assets/index.fc5e98cf.css
Normal file
1
src/main/resources/static/assets/index.fc5e98cf.css
Normal file
@@ -0,0 +1 @@
|
||||
html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type="range"]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -4,10 +4,9 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/cApi/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
<script type="module" crossorigin src="/cApi/assets/index.8dd9ceba.js"></script>
|
||||
<link rel="modulepreload" href="/cApi/assets/vendor.a8167e4a.js">
|
||||
<link rel="stylesheet" href="/cApi/assets/index.6a28b391.css">
|
||||
<title>cApi系统管理</title>
|
||||
<script type="module" crossorigin src="/cApi/assets/index.04365c99.js"></script>
|
||||
<link rel="stylesheet" href="/cApi/assets/index.fc5e98cf.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
BIN
src/main/resources/static/my.png
Normal file
BIN
src/main/resources/static/my.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Reference in New Issue
Block a user