重构前端逻辑
This commit is contained in:
parent
a682d5718b
commit
c285d224e4
@ -1,23 +0,0 @@
|
||||
你是一名java高级开发工程师,对你有以下要求
|
||||
1. 缺陷修正:
|
||||
- 在提出修复建议前,应充分分析问题
|
||||
- 提供精准、有针对性的解决方案
|
||||
- 解释bug的根本原因
|
||||
|
||||
2. 保持简单:
|
||||
- 优先考虑可读性和可维护性
|
||||
- 避免过度工程化的解决方案
|
||||
- 尽可能使用标准库和模式
|
||||
- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则
|
||||
|
||||
3. 代码更改:
|
||||
- 在做出改变之前提出一个清晰的计划
|
||||
- 一次将所有修改应用于单个文件
|
||||
- 请勿修改不相关的文件
|
||||
|
||||
4. 新增或者修改初始化数据
|
||||
- 新增或者修改数据库表需在V1.0.0__init_schema.sql、V1.0.1__init_data.sql中补充表结构和初始化数据,不要随意删除
|
||||
|
||||
|
||||
|
||||
记住要始终考虑每个项目的背景和特定需求。
|
||||
@ -1,291 +0,0 @@
|
||||
# 前端接口对接文档
|
||||
|
||||
## 通用说明
|
||||
|
||||
### 1. 接口响应格式
|
||||
|
||||
所有接口统一返回以下格式:
|
||||
```typescript
|
||||
interface Response<T> {
|
||||
success: boolean; // 请求是否成功
|
||||
code: number; // 状态码,200表示成功,其他表示失败
|
||||
message: string; // 提示信息
|
||||
data?: T; // 响应数据,可选
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 分页请求参数
|
||||
```typescript
|
||||
interface PageQuery {
|
||||
pageNum: number; // 页码,从1开始
|
||||
pageSize: number; // 每页大小
|
||||
sortField?: string; // 排序字段,可选
|
||||
sortOrder?: 'asc' | 'desc'; // 排序方式,可选
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 分页响应格式
|
||||
```typescript
|
||||
interface PageResponse<T> {
|
||||
content: T[]; // 数据列表
|
||||
totalElements: number;// 总记录数
|
||||
totalPages: number; // 总页数
|
||||
size: number; // 每页大小
|
||||
number: number; // 当前页码(从0开始)
|
||||
first: boolean; // 是否第一页
|
||||
last: boolean; // 是否最后一页
|
||||
empty: boolean; // 是否为空
|
||||
}
|
||||
```
|
||||
|
||||
## 通用接口
|
||||
|
||||
### 1. 基础CRUD接口
|
||||
所有实体都支持以下基础操作接口:
|
||||
|
||||
#### 1.1 分页查询
|
||||
```typescript
|
||||
GET /api/v1/{module}/page
|
||||
|
||||
请求参数:PageQuery & {
|
||||
// 其他查询条件,根据具体模块定义
|
||||
}
|
||||
|
||||
响应结果:Response<PageResponse<T>>
|
||||
```
|
||||
|
||||
#### 1.2 列表查询
|
||||
```typescript
|
||||
GET /api/v1/{module}/list
|
||||
|
||||
请求参数:{
|
||||
// 查询条件,根据具体模块定义
|
||||
}
|
||||
|
||||
响应结果:Response<T[]>
|
||||
```
|
||||
|
||||
#### 1.3 获取详情
|
||||
```typescript
|
||||
GET /api/v1/{module}/{id}
|
||||
|
||||
响应结果:Response<T>
|
||||
```
|
||||
|
||||
#### 1.4 创建
|
||||
```typescript
|
||||
POST /api/v1/{module}
|
||||
|
||||
请求参数:{
|
||||
// 创建参数,根据具体模块定义
|
||||
}
|
||||
|
||||
响应结果:Response<T>
|
||||
```
|
||||
|
||||
#### 1.5 更新
|
||||
```typescript
|
||||
PUT /api/v1/{module}/{id}
|
||||
|
||||
请求参数:{
|
||||
// 更新参数,根据具体模块定义
|
||||
}
|
||||
|
||||
响应结果:Response<T>
|
||||
```
|
||||
|
||||
#### 1.6 删除
|
||||
```typescript
|
||||
DELETE /api/v1/{module}/{id}
|
||||
|
||||
响应结果:Response<void>
|
||||
```
|
||||
|
||||
#### 1.7 批量删除
|
||||
```typescript
|
||||
DELETE /api/v1/{module}/batch
|
||||
|
||||
请求参数:{
|
||||
ids: number[]; // ID列表
|
||||
}
|
||||
|
||||
响应结果:Response<void>
|
||||
```
|
||||
|
||||
#### 1.8 导出数据
|
||||
```typescript
|
||||
GET /api/v1/{module}/export
|
||||
|
||||
请求参数:{
|
||||
// 查询条件,根据具体模块定义
|
||||
}
|
||||
|
||||
响应结果:二进制文件流
|
||||
```
|
||||
|
||||
### 2. 树形结构接口
|
||||
对于树形结构的数据(如部门、菜单等),还支持以下接口:
|
||||
|
||||
#### 2.1 获取树形数据
|
||||
```typescript
|
||||
GET /api/v1/{module}/tree
|
||||
|
||||
响应结果:Response<TreeNode[]>
|
||||
|
||||
interface TreeNode {
|
||||
id: number;
|
||||
parentId: number | null;
|
||||
children: TreeNode[];
|
||||
// 其他字段根据具体模块定义
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 状态管理接口
|
||||
对于需要状态管理的数据(如租户、用户等),还支持以下接口:
|
||||
|
||||
#### 3.1 获取状态
|
||||
```typescript
|
||||
GET /api/v1/{module}/{id}/enabled
|
||||
|
||||
响应结果:Response<boolean>
|
||||
```
|
||||
|
||||
#### 3.2 更新状态
|
||||
```typescript
|
||||
PUT /api/v1/{module}/{id}/enabled
|
||||
|
||||
请求参数:
|
||||
enabled=true // 是否启用
|
||||
|
||||
响应结果:Response<void>
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 1. 错误码说明
|
||||
- 200:成功
|
||||
- 400:请求参数错误
|
||||
- 401:未认证
|
||||
- 403:无权限
|
||||
- 404:资源不存在
|
||||
- 500:服务器内部错误
|
||||
|
||||
### 2. 错误响应示例
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"code": 400,
|
||||
"message": "请求参数错误",
|
||||
"data": {
|
||||
"field": "name",
|
||||
"message": "名称不能为空"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 接口调用示例
|
||||
|
||||
### TypeScript 示例
|
||||
```typescript
|
||||
// 定义接口返回类型
|
||||
interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
async function getUserList(query: PageQuery & { username?: string }) {
|
||||
const response = await axios.get<Response<PageResponse<User>>>('/api/v1/user/page', {
|
||||
params: query
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
async function createUser(user: Omit<User, 'id'>) {
|
||||
const response = await axios.post<Response<User>>('/api/v1/user', user);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
async function updateUserStatus(id: number, enabled: boolean) {
|
||||
const response = await axios.put<Response<void>>(`/api/v1/user/${id}/enabled`, null, {
|
||||
params: { enabled }
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
```
|
||||
|
||||
### Vue3 + TypeScript 示例
|
||||
```typescript
|
||||
// 在组件中使用
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const userList = ref<User[]>([]);
|
||||
const total = ref(0);
|
||||
const loading = ref(false);
|
||||
|
||||
const queryList = async (query: PageQuery) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await getUserList(query);
|
||||
if (response.success) {
|
||||
userList.value = response.data.content;
|
||||
total.value = response.data.totalElements;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
queryList({
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
userList,
|
||||
total,
|
||||
loading,
|
||||
queryList
|
||||
};
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 请求头要求
|
||||
```typescript
|
||||
{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ${token}' // JWT认证token
|
||||
}
|
||||
```
|
||||
|
||||
2. 日期时间格式
|
||||
- 请求参数:使用ISO 8601格式(YYYY-MM-DDTHH:mm:ss.sssZ)
|
||||
- 响应数据:统一返回ISO 8601格式
|
||||
|
||||
3. 文件上传
|
||||
- 使用multipart/form-data格式
|
||||
- 文件大小限制:10MB
|
||||
|
||||
4. 接口版本
|
||||
- 所有接口统一使用v1版本
|
||||
- URL格式:/api/v1/{module}/{resource}
|
||||
|
||||
5. 安全性
|
||||
- 所有接口都需要JWT认证
|
||||
- Token过期时间:2小时
|
||||
- 需要定期刷新Token
|
||||
|
||||
6. 错误处理
|
||||
- 统一使用axios拦截器处理错误
|
||||
- 401错误跳转到登录页
|
||||
- 其他错误统一提示
|
||||
@ -71,16 +71,17 @@ const getLayoutedElements = (
|
||||
const dagreGraph = new dagre.graphlib.Graph();
|
||||
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
||||
|
||||
const nodeWidth = 180;
|
||||
const nodeHeight = 120;
|
||||
const nodeWidth = 200;
|
||||
const nodeHeight = 150;
|
||||
|
||||
const isHorizontal = direction === 'LR';
|
||||
dagreGraph.setGraph({
|
||||
rankdir: direction,
|
||||
nodesep: 50,
|
||||
ranksep: 80,
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
nodesep: isHorizontal ? 80 : 100, // 同一层节点间距:横向80,纵向100
|
||||
ranksep: isHorizontal ? 150 : 120, // 层级间距:横向150,纵向120
|
||||
marginx: 40,
|
||||
marginy: 40,
|
||||
align: 'UL', // 对齐方式
|
||||
});
|
||||
|
||||
nodes.forEach((node) => {
|
||||
@ -137,57 +138,73 @@ const CustomFlowNode: React.FC<any> = ({ data }) => {
|
||||
const nodeContent = (
|
||||
<div
|
||||
className={cn(
|
||||
'px-3 py-2 rounded-md min-w-[160px] transition-all',
|
||||
isNotStarted && 'border-2 border-dashed',
|
||||
!isNotStarted && 'border-2 border-solid shadow-sm',
|
||||
isRunning && 'animate-pulse',
|
||||
canViewLog && 'cursor-pointer hover:shadow-md hover:scale-[1.02]' // 可查看日志的节点增加交互效果
|
||||
'px-4 py-3 rounded-lg w-[190px] min-h-[140px] transition-all duration-200 relative overflow-hidden flex flex-col',
|
||||
isNotStarted && 'border-2 border-dashed bg-gradient-to-br from-slate-50 to-gray-50',
|
||||
!isNotStarted && 'border-2 border-solid shadow-lg hover:shadow-2xl bg-white',
|
||||
isRunning && 'ring-2 ring-blue-400 ring-opacity-60 shadow-blue-200',
|
||||
canViewLog && 'cursor-pointer hover:shadow-2xl hover:scale-105 active:scale-100'
|
||||
)}
|
||||
style={{
|
||||
borderColor: statusColor,
|
||||
backgroundColor: isNotStarted ? '#f9fafb' : '#ffffff',
|
||||
borderWidth: '3px',
|
||||
}}
|
||||
>
|
||||
{/* 顶部状态指示条 */}
|
||||
{!isNotStarted && (
|
||||
<div
|
||||
className="absolute top-0 left-0 right-0 h-1"
|
||||
style={{ backgroundColor: statusColor, opacity: 0.6 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 节点名称 */}
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<div className="font-medium text-sm truncate">{nodeName}</div>
|
||||
<div className="flex items-center justify-between gap-2 mb-2 mt-0.5">
|
||||
<div className="font-semibold text-sm truncate text-gray-900">{nodeName}</div>
|
||||
{canViewLog && (
|
||||
<FileText className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
|
||||
<FileText className="h-4 w-4 text-blue-500 flex-shrink-0" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 节点状态 */}
|
||||
{/* 节点状态 - 使用徽章样式 */}
|
||||
<div
|
||||
className="text-xs font-medium mb-1"
|
||||
style={{ color: statusColor }}
|
||||
className={cn(
|
||||
"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-bold mb-2",
|
||||
isRunning && "animate-pulse"
|
||||
)}
|
||||
style={{
|
||||
backgroundColor: `${statusColor}20`,
|
||||
color: statusColor,
|
||||
border: `1.5px solid ${statusColor}`
|
||||
}}
|
||||
>
|
||||
{getNodeStatusText(status)}
|
||||
</div>
|
||||
|
||||
{/* 时间信息 */}
|
||||
{!isNotStarted && (
|
||||
<div className="text-xs text-muted-foreground space-y-0.5">
|
||||
{displayDuration && (
|
||||
<div className="font-medium">
|
||||
{isRunning ? '运行: ' : '时长: '}
|
||||
{displayDuration}
|
||||
</div>
|
||||
)}
|
||||
{/* 时间信息 - 更紧凑的显示 */}
|
||||
{!isNotStarted && displayDuration && (
|
||||
<div className="text-xs text-muted-foreground mb-1">
|
||||
<div className="font-medium text-blue-600">
|
||||
⏱️ {displayDuration}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 错误提示 */}
|
||||
{/* 弹性空间,让底部提示始终在底部 */}
|
||||
<div className="flex-1 min-h-[4px]" />
|
||||
|
||||
{/* 错误提示 - 增强样式 */}
|
||||
{hasFailed && errorMessage && (
|
||||
<div className="mt-1 flex items-center gap-1 text-red-600">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
<span className="text-xs">有错误</span>
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 rounded bg-red-50 border border-red-200">
|
||||
<AlertCircle className="h-3.5 w-3.5 text-red-600 flex-shrink-0" />
|
||||
<span className="text-xs font-medium text-red-700">查看错误</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 查看日志提示 */}
|
||||
{canViewLog && (
|
||||
<div className="mt-1 text-xs text-blue-600 flex items-center gap-1">
|
||||
<span>点击查看日志</span>
|
||||
{/* 查看日志提示 - 增强样式 */}
|
||||
{canViewLog && !hasFailed && (
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 rounded bg-blue-50 border border-blue-200">
|
||||
<FileText className="h-3.5 w-3.5 text-blue-600 flex-shrink-0" />
|
||||
<span className="text-xs font-medium text-blue-700">点击查看日志</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -298,35 +315,39 @@ const ProgressCard: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowData
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-2">
|
||||
<span className="text-muted-foreground">已执行</span>
|
||||
<span className="font-medium">
|
||||
{executedNodeCount} / {totalNodeCount} 节点
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<span className="text-sm font-semibold text-blue-600">已执行</span>
|
||||
<span className="text-xl font-bold text-blue-600">
|
||||
{executedNodeCount} / {totalNodeCount}
|
||||
</span>
|
||||
</div>
|
||||
<Progress value={progress} className="h-2" />
|
||||
<div className="text-xs text-muted-foreground mt-1 text-right">
|
||||
{Math.round(progress)}%
|
||||
<div className="relative">
|
||||
<Progress value={progress} className="h-3 bg-blue-100" />
|
||||
<div className="absolute inset-0 flex items-center justify-end pr-2">
|
||||
<span className="text-xs font-bold text-white drop-shadow">
|
||||
{Math.round(progress)}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="grid grid-cols-3 gap-2 text-xs">
|
||||
<div className="flex flex-col items-center p-2 rounded-md bg-green-50">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-600 mb-1" />
|
||||
<span className="text-muted-foreground">成功</span>
|
||||
<span className="font-medium text-green-600">{successNodeCount}</span>
|
||||
<div className="grid grid-cols-3 gap-3 text-xs">
|
||||
<div className="flex flex-col items-center p-3 rounded-lg bg-gradient-to-br from-green-50 to-emerald-50 border border-green-100">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-600 mb-1.5" />
|
||||
<span className="text-muted-foreground text-[10px]">成功</span>
|
||||
<span className="font-bold text-lg text-green-600">{successNodeCount}</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center p-2 rounded-md bg-red-50">
|
||||
<XCircle className="h-4 w-4 text-red-600 mb-1" />
|
||||
<span className="text-muted-foreground">失败</span>
|
||||
<span className="font-medium text-red-600">{failedNodeCount}</span>
|
||||
<div className="flex flex-col items-center p-3 rounded-lg bg-gradient-to-br from-red-50 to-rose-50 border border-red-100">
|
||||
<XCircle className="h-5 w-5 text-red-600 mb-1.5" />
|
||||
<span className="text-muted-foreground text-[10px]">失败</span>
|
||||
<span className="font-bold text-lg text-red-600">{failedNodeCount}</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center p-2 rounded-md bg-blue-50">
|
||||
<Loader2 className="h-4 w-4 text-blue-600 mb-1" />
|
||||
<span className="text-muted-foreground">运行中</span>
|
||||
<span className="font-medium text-blue-600">{runningNodeCount}</span>
|
||||
<div className="flex flex-col items-center p-3 rounded-lg bg-gradient-to-br from-blue-50 to-cyan-50 border border-blue-100">
|
||||
<Loader2 className={cn("h-5 w-5 text-blue-600 mb-1.5", runningNodeCount > 0 && "animate-spin")} />
|
||||
<span className="text-muted-foreground text-[10px]">运行中</span>
|
||||
<span className="font-bold text-lg text-blue-600">{runningNodeCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
@ -433,7 +454,7 @@ const MonitoringAlert: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowDa
|
||||
*/
|
||||
const DeployInfoPanel: React.FC<{ flowData: DeployRecordFlowGraph }> = ({ flowData }) => {
|
||||
return (
|
||||
<div className="w-80 flex-shrink-0 border-r bg-muted/30 p-4 space-y-4 overflow-y-auto">
|
||||
<div className="w-80 flex-shrink-0 border-r-2 border-border bg-gradient-to-b from-muted/20 to-muted/40 p-4 space-y-4 overflow-y-auto shadow-[2px_0_8px_rgba(0,0,0,0.05)]">
|
||||
<MonitoringAlert flowData={flowData} />
|
||||
<BusinessInfoCard flowData={flowData} />
|
||||
<ProgressCard flowData={flowData} />
|
||||
@ -581,7 +602,7 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
return {
|
||||
id: node.id,
|
||||
type: 'custom',
|
||||
position: node.position || { x: 0, y: 0 }, // 使用设计器中保存的坐标
|
||||
position: { x: 0, y: 0 }, // 忽略设计器坐标,使用dagre自动布局
|
||||
data: {
|
||||
nodeName: node.nodeName,
|
||||
nodeType: instance?.nodeType || node.nodeType, // 优先使用运行时的 nodeType
|
||||
@ -617,32 +638,37 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
const targetStatus = targetInstance?.status || 'NOT_STARTED';
|
||||
|
||||
// 根据节点状态确定边的样式
|
||||
let strokeColor = '#d1d5db'; // 默认灰色
|
||||
let strokeWidth = 2;
|
||||
let strokeColor = '#cbd5e1'; // 默认浅灰色
|
||||
let strokeWidth = 3; // 增加连线粗细
|
||||
let animated = false;
|
||||
let strokeDasharray: string | undefined = undefined;
|
||||
|
||||
// 源节点已完成 + 目标节点也已完成/运行中 = 绿色实线
|
||||
if (sourceStatus === 'COMPLETED' && (targetStatus === 'COMPLETED' || targetStatus === 'RUNNING')) {
|
||||
strokeColor = '#10b981'; // 绿色
|
||||
strokeWidth = 3.5;
|
||||
}
|
||||
// 源节点 TERMINATED = 橙色实线
|
||||
else if (sourceStatus === 'TERMINATED') {
|
||||
strokeColor = '#f59e0b'; // 橙色
|
||||
strokeWidth = 3.5;
|
||||
}
|
||||
// 源节点失败 = 红色实线
|
||||
else if (sourceStatus === 'FAILED') {
|
||||
strokeColor = '#ef4444'; // 红色
|
||||
strokeWidth = 3.5;
|
||||
}
|
||||
// 源节点运行中 = 蓝色动画
|
||||
else if (sourceStatus === 'RUNNING') {
|
||||
strokeColor = '#3b82f6'; // 蓝色
|
||||
strokeWidth = 4; // 运行中的线更粗
|
||||
animated = true;
|
||||
}
|
||||
// 源节点完成 + 目标节点未开始 = 虚线(即将执行的路径)
|
||||
else if ((sourceStatus === 'COMPLETED' || sourceStatus === 'TERMINATED') && targetStatus === 'NOT_STARTED') {
|
||||
strokeColor = '#9ca3af'; // 浅灰色
|
||||
strokeDasharray = '5,5';
|
||||
strokeColor = '#94a3b8'; // 稍深的灰色
|
||||
strokeDasharray = '8,4';
|
||||
strokeWidth = 2.5;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -659,8 +685,8 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
markerEnd: {
|
||||
type: 'arrowclosed',
|
||||
color: strokeColor,
|
||||
width: 20,
|
||||
height: 20,
|
||||
width: 24,
|
||||
height: 24,
|
||||
},
|
||||
};
|
||||
});
|
||||
@ -773,16 +799,17 @@ export const DeployFlowGraphModal: React.FC<DeployFlowGraphModalProps> = ({
|
||||
>
|
||||
<Background
|
||||
variant={BackgroundVariant.Dots}
|
||||
gap={16}
|
||||
size={1}
|
||||
className="opacity-30"
|
||||
gap={20}
|
||||
size={1.5}
|
||||
color="#cbd5e1"
|
||||
className="opacity-40"
|
||||
/>
|
||||
<Controls
|
||||
position="bottom-right"
|
||||
showZoom={true}
|
||||
showFitView={true}
|
||||
showInteractive={false}
|
||||
className="!shadow-lg !border !border-border"
|
||||
className="!shadow-xl !border-2 !border-border !rounded-lg !overflow-hidden"
|
||||
/>
|
||||
<MiniMap
|
||||
position="bottom-left"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user