12451 b553c4e519 feat: API 统一 + 设备详情补全 + H5 导航优化
- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口
- 二进制改名: api-server -> pms-api(与服务名一致)
- nginx: 合并 /api/ + /pms/api/ 为 /api/pms/
- 新增 docs/API.md 接口文档
- 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段
- Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率)
- DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配)
- 用户管理: 新增创建时间/修改时间列,状态改用 Switch
- 角色管理/用户管理: 操作按钮改为图标
- PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址
- PC 卡片: 通道统计改用 Lucide 图标,颜色统一
- PC 二维码: canvas 渲染,含编号文字,支持右键下载
- H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch)
- H5: 详情页加返回导航条
- H5: 扫码支持摄像头(jsQR)+ ?id= 参数
- H5: 底部 tabBar 在所有页面常显
- H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障)
- H5: 下拉刷新 / 上拉加载
- 产品首页: 添加业务联系
- 文档: 清理过时文件,补充缺失规范章节
2026-07-04 04:03:02 +08:00

4.5 KiB

Plugin Structure: Install Method Requirements

Rule

A Vue plugin must be either an object with an install() method, or a function that serves as the install function. The install function receives the app instance and optional user-provided options.

Why This Matters

  1. API contract: Vue's app.use() expects a specific interface. Incorrect structure causes silent failures or errors.

  2. Options passing: The install method receives options that users pass to app.use(), enabling plugin configuration.

  3. App access: The install method receives the app instance, providing access to app.component(), app.directive(), app.provide(), etc.

Plugin Structures

// plugins/myPlugin.ts
import type { App } from 'vue'

interface PluginOptions {
  prefix?: string
  debug?: boolean
}

const myPlugin = {
  install(app: App, options: PluginOptions = {}) {
    const { prefix = 'my', debug = false } = options

    if (debug) {
      console.log('Installing myPlugin with prefix:', prefix)
    }

    app.provide('myPlugin', { prefix })
  }
}

export default myPlugin

// Usage
app.use(myPlugin, { prefix: 'custom', debug: true })

Function as install (alternative)

// plugins/simplePlugin.ts
import type { App } from 'vue'

function simplePlugin(app: App, options?: { message: string }) {
  app.config.globalProperties.$greet = () => {
    return options?.message ?? 'Hello!'
  }
}

export default simplePlugin

// Usage
app.use(simplePlugin, { message: 'Welcome!' })

Factory function pattern (most flexible)

// plugins/configuredPlugin.ts
import type { App, Plugin } from 'vue'

interface I18nOptions {
  locale: string
  messages: Record<string, Record<string, string>>
  fallbackLocale?: string
}

export function createI18n(options: I18nOptions): Plugin {
  return {
    install(app: App) {
      // Options are captured in closure - no need to pass through app.use()
      const { locale, messages, fallbackLocale = 'en' } = options

      const translate = (key: string): string => {
        return messages[locale]?.[key]
          ?? messages[fallbackLocale]?.[key]
          ?? key
      }

      app.provide('i18n', { translate, locale })
    }
  }
}

// Usage - options passed to factory, not app.use()
const i18n = createI18n({
  locale: 'fr',
  messages: {
    en: { hello: 'Hello' },
    fr: { hello: 'Bonjour' }
  }
})

app.use(i18n)  // No second argument needed

Common Plugin Capabilities

const fullFeaturedPlugin = {
  install(app: App, options: PluginOptions) {
    // 1. Register global components
    app.component('MyButton', MyButtonComponent)
    app.component('MyInput', MyInputComponent)

    // 2. Register global directives
    app.directive('focus', focusDirective)

    // 3. Provide injectable values (recommended)
    app.provide('pluginConfig', options)

    // 4. Add global properties (use sparingly)
    app.config.globalProperties.$myHelper = helperFunction

    // 5. Add global mixins (avoid if possible)
    app.mixin({
      created() {
        // Runs for every component
      }
    })

    // 6. Custom error handling
    app.config.errorHandler = (err, vm, info) => {
      // Handle errors
    }
  }
}

TypeScript: Plugin Type

Use the Plugin type for proper typing:

import type { App, Plugin } from 'vue'

// With options type parameter
interface MyOptions {
  apiKey: string
}

const myPlugin: Plugin<[MyOptions]> = {
  install(app: App, options: MyOptions) {
    // options is typed as MyOptions
  }
}

// Without options
const simplePlugin: Plugin = {
  install(app: App) {
    // No options expected
  }
}

Common Mistakes

Missing install method

// BAD - This is just an object, not a plugin
const notAPlugin = {
  doSomething() { /* ... */ }
}
app.use(notAPlugin)  // Error or silent failure

// GOOD
const actualPlugin = {
  install(app) {
    app.provide('service', { doSomething() { /* ... */ } })
  }
}

Forgetting to use the app parameter

// BAD - Does nothing
const uselessPlugin = {
  install(app, options) {
    const service = createService(options)
    // Forgot to register anything with app!
  }
}

// GOOD
const usefulPlugin = {
  install(app, options) {
    const service = createService(options)
    app.provide('service', service)  // Actually makes it available
  }
}

References