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

3.7 KiB

name, description
name description
component-props Declare and use props with type safety and validation

Component Props

Props are custom attributes for passing data from parent to child components.

Use TypeScript interfaces with defineProps:

<script setup lang="ts">
interface Props {
  title: string
  count?: number
  items: string[]
}

const props = defineProps<Props>()
</script>

Reactive Props Destructure (3.5+)

Destructure props while keeping reactivity:

<script setup lang="ts">
interface Props {
  msg?: string
  count?: number
}

const { msg = 'hello', count = 0 } = defineProps<Props>()

// Both msg and count are reactive
watchEffect(() => {
  console.log(msg, count)
})
</script>

Passing destructured props to functions

const { foo } = defineProps(['foo'])

// ❌ Won't work - passes value not reactive source
watch(foo, /* ... */)

// ✅ Wrap in getter
watch(() => foo, /* ... */)

// ✅ For composables
useComposable(() => foo)

Default Values with withDefaults (3.4 and below)

<script setup lang="ts">
interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two'] // Factory function for objects/arrays
})
</script>

Runtime Declaration

For runtime validation without TypeScript:

<script setup lang="ts">
const props = defineProps({
  // Basic type check
  propA: Number,
  // Multiple types
  propB: [String, Number],
  // Required
  propC: { type: String, required: true },
  // With default
  propD: { type: Number, default: 100 },
  // Object with factory default
  propE: {
    type: Object,
    default: () => ({ message: 'hello' })
  },
  // Custom validator
  propF: {
    validator(value: string) {
      return ['success', 'warning', 'danger'].includes(value)
    }
  }
})
</script>

Prop Types

Supported type values:

  • String, Number, Boolean, Array, Object
  • Date, Function, Symbol, Error
  • Custom classes (uses instanceof)
class Person {
  constructor(public name: string) {}
}

defineProps({
  author: Person // instanceof check
})

Nullable Props

defineProps({
  id: {
    type: [String, null],
    required: true
  }
})

Boolean Casting

Boolean props have special casting rules:

<script setup lang="ts">
defineProps({
  disabled: Boolean
})
</script>

<!-- equivalent to :disabled="true" -->
<MyComponent disabled />

<!-- equivalent to :disabled="false" -->
<MyComponent />

One-Way Data Flow

Props form a one-way binding: parent → child. Never mutate props directly.

const props = defineProps(['initialCounter'])

// ❌ Don't mutate props
props.initialCounter = 5

// ✅ Use local state initialized from prop
const counter = ref(props.initialCounter)

// ✅ Or use computed for transformations
const normalizedSize = computed(() => props.size.trim().toLowerCase())

Passing Props

<!-- Static -->
<BlogPost title="My Post" />

<!-- Dynamic -->
<BlogPost :title="post.title" />

<!-- Number (requires v-bind) -->
<BlogPost :likes="42" />

<!-- Boolean -->
<BlogPost is-published />
<BlogPost :is-published="false" />

<!-- Object spread -->
<BlogPost v-bind="post" />
<!-- equivalent to -->
<BlogPost :id="post.id" :title="post.title" />

Prop Name Casing

  • Declare with camelCase in JavaScript
  • Use kebab-case in templates
defineProps({
  greetingMessage: String
})
<MyComponent greeting-message="hello" />