Skip to content

前端开发

本文档详细介绍 ElasticView 插件前端开发的技术栈、项目结构、开发流程和最佳实践。

技术栈

核心框架

  • Vue 3 - 渐进式 JavaScript 框架
  • Vite - 快速的构建工具和开发服务器

插件 SDK

  • @elasticview/plugin-sdk - ElasticView 官方前端 SDK

项目结构

frontend/
├── src/
│   ├── api/                    # API 接口定义
│   │   ├── es.ts              # Elasticsearch 相关 API
│   │   ├── es-index.ts        # ES 索引 API
│   │   └── ...
│   ├── components/            # 公共组件
│   ├── views/                 # 页面视图
│   ├── router/                # 路由配置
│   │   └── index.ts          # 路由定义
│   ├── lang/                  # 国际化语言包
│   │   ├── en.ts             # 英文语言包
│   │   └── zh-cn.ts          # 中文语言包
│   ├── utils/                 # 工具函数
│   ├── App.vue               # 根组件
│   └── main.ts               # 入口文件
├── package.json              # 依赖配置
├── vite.config.ts            # Vite 配置
├── tsconfig.json             # TypeScript 配置
└── index.html                # HTML 模板

快速开始

1. 安装依赖

bash
pnpm install @elasticview/plugin-sdk

2. 插件初始化

main.ts 中初始化 EV 前端插件:

typescript
import {setupEvPlugin} from '@elasticview/plugin-sdk'
import pluginJson from '../../plugin.json'

import App from "./App.vue";
import router from "./router/index.js"

import enLocale from "./lang/en";
import zhCnLocale from "./lang/zh-cn";

// 引入第三方组件库(可选,但推荐使用,可自动适配主题颜色)
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

// 插件启动时安装第三方插件的初始化钩子
const init = (app) => {
  // 使用 Element Plus(可选)
  app.use(ElementPlus)
  
  return app
}

// 初始化插件
// 参数依次为:plugin.json配置文件,App.vue实例,路由,英文语言包,中文语言包,初始化钩子
setupEvPlugin(pluginJson, App, router, enLocale, zhCnLocale, init)

3. 路由配置

typescript
// src/router/index.ts
import pluginJson from '../../../plugin.json'  //插件配置文件,json格式

export const routes = [
    {
        path: `/${pluginJson.plugin_alias}`,//根目录必须为插件名
        component: ()=>import("@/layouts/Layout.vue"),//默认布局文件
        children: [
            {
                path: 'hello-world',
                component: ()=>import('@/views/helloworld/index.vue'),
                name: 'hello-world',
                meta: {
                    title: '访问es',
                    icon: 'el-icon-coin'
                }
            }
            
        ]
    },
]

/****
 新增页面后如果需要在ElasticView的菜单中展现出来,
 则需要修改plugin.json中frontend_routes配置项,为routes中去除component属性的对应路由
 plugin.json 例子:
 {
 ...
 "frontend_routes":[
  {
                path: 'hello-world',
                name: 'hello-world',
                meta: {
                    title: '访问es',
                    icon: 'el-icon-coin'
                }
          }
 
 }
 
 */

4. 国际化配置

typescript
// src/lang/zh-cn.ts
export default {
  hello: '你好',
  welcome: '欢迎使用 ElasticView 插件',
}

// src/lang/en.ts
export default {
  hello: 'Hello',
  welcome: 'Welcome to ElasticView Plugin',
}

//模板中使用:{{$t('hello')}}

SDK 使用

HTTP 请求

typescript
// src/api/user.ts
import {request} from '@elasticview/plugin-sdk'

// 基础 POST 请求
export function createUser(data: any) {
    return request({
        url: `/api/user/create`,
        method: 'post',
        data
    })
}

// 使用示例
const result = await createUser({
    name: '张三',
    email: 'zhangsan@example.com'
})

SDK 工具方法

typescript
// 在 Vue 组件中使用
<template>
  <div :class="{'mobile-layout': isMobile, 'dark-theme': isDark}">
    <el-button :size="layoutSize" @click="navigateToPage">
      {{ $t('hello') }}
    </el-button>
  </div>
</template>

<script setup lang="ts">
import {computed, onMounted, onUnmounted} from 'vue'
import {sdk} from '@elasticview/plugin-sdk'

// 获取当前布局尺寸
const layoutSize = computed(() => {
    return sdk.getLayoutSize()
})

// 检查是否为移动设备
const isMobile = computed(() => {
    return sdk.IsMobile()
})

// 检查是否为暗色主题
const isDark = computed(() => {
    return sdk.isDarkTheme()
})

// 获取当前语言
const currentLanguage = computed(() => {
    return sdk.getLanguage()
})

// 获取路由实例
const router = sdk.getRouter()

// 编程式导航
const navigateToPage = () => {
    router.push('/some-path')
}

// 获取事件总线实例
const eventBus = sdk.getEventBus()
const BusEnum = sdk.getBusEnum()

// 监听系统设置变更
onMounted(() => {
    eventBus.on(BusEnum.changeEvSettings, (newSettings) => {
        console.log('系统设置已更改:', newSettings)
        // 处理设置变更逻辑
    })
    
    eventBus.on(BusEnum.changeEvAppConfig, (newConfig) => {
        console.log('应用配置已更改:', newConfig)
        // 处理配置变更逻辑
    })
})

// 获取当前选中的数据源连接 ID
const currentConnId = computed(() => {
    return sdk.GetSelectEsConnID()
})

// 获取当前用户所拥有的数据源列表
const handleLinkOperation = async () => {
    try {
        const result = await sdk.LinkOptAction()
        console.log('您拥有的数据源:', result)
    } catch (error) {
        console.error('获取失败:', error)
    }
}

// 调用其他插件的 API
const callAnotherPluginApi = async (data) => {
    const response = await sdk.CallAnotherPluginApi('other-plugin-alias', {
        url: `/api/DbInsert`,
        method: 'post',
        data
    })
    return response
}

// 插件长连接通信
onMounted(() => {
    // 订阅频道消息
    sdk.SubToChannel('my-channel', (message) => {
        console.log('收到频道消息:', message)
    })
})

// 发送频道消息
const sendChannelMessage = () => {
    sdk.CallToChannel('my-channel', {
        type: 'notification',
        content: 'Hello from plugin!'
    })
}

// 取消订阅(组件卸载时)
onUnmounted(() => {
    sdk.UnSubscribeToChannel('my-channel')
})

// 获取当前用户 ID
const currentUserId = computed(() => {
    return sdk.GetUserId()
})
</script>

尺寸枚举使用

typescript
<template>
  <el-button :size="componentSize">按钮</el-button>
</template>

<script setup lang="ts">
import {computed} from 'vue'
import {sdk} from '@elasticview/plugin-sdk'

// 获取尺寸枚举
const SizeEnum = sdk.getSizeEnum()

// 尺寸值:
// SizeEnum.DEFAULT = "default"
// SizeEnum.LARGE = "large" 
// SizeEnum.SMALL = "small"

// 根据尺寸设置样式
const componentSize = computed(() => {
    const size = sdk.getLayoutSize()
    switch(size) {
        case SizeEnum.LARGE:
            return 'large'
        case SizeEnum.SMALL:
            return 'small'
        default:
            return 'default'
    }
})
</script>

主题适配

vue
<template>
  <div class="theme-container" :class="themeClass">
    <el-card>
      <h3>主题自适应卡片</h3>
      <p>根据系统主题自动调整样式</p>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { sdk } from '@elasticview/plugin-sdk'

const isDark = computed(() => sdk.isDarkTheme())

const themeClass = computed(() => ({
  'dark-theme': isDark.value,
  'light-theme': !isDark.value
}))
</script>

<style scoped>
.light-theme {
  background-color: #ffffff;
  color: #333333;
}

.dark-theme {
  background-color: #1a1a1a;
  color: #ffffff;
}

.dark-theme .el-card {
  background-color: #2d2d2d;
  border-color: #4d4d4d;
}
</style>

常见问题

Q: 为什么我的代码没有问题,但是插件页面一片空白?

A: 可能是因为plugin.json中的frontend_debug选项没有设置为true。

Q: 为什么我的代码没有问题,但是插件的菜单栏里没有具体页面入口?

A: 可能是因为plugin.json中的frontend_debug选项没有添加路由。

注意事项

  1. SDK 初始化 - 确保在 setupEvPlugin 初始化后再使用 SDK 方法
  2. 事件清理 - 组件卸载时需要清理事件监听器,避免内存泄漏
  3. 响应式设计 - 使用 sdk.IsMobile() 适配移动端布局
  4. 主题适配 - 使用 sdk.isDarkTheme() 支持深色主题
  5. 国际化 - 合理使用语言包,支持多语言切换
  6. API 路径 - 请求 URL 路径需要与后端插件接口路径一致

下一步