- 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: 下拉刷新 / 上拉加载 - 产品首页: 添加业务联系 - 文档: 清理过时文件,补充缺失规范章节
3.1 KiB
3.1 KiB
Tailwind CSS Dynamic Class Generation
Rule
Never construct Tailwind CSS class names dynamically using string concatenation or template literals. Tailwind's build process cannot detect dynamically generated class names, causing styles to be missing in production.
Why This Matters
- Tailwind uses static analysis at build time to determine which CSS classes to include
- Dynamically constructed class names (e.g.,
bg-${color}-500) are invisible to Tailwind's scanner - Classes work in development with JIT but fail silently in production builds
- This is a common source of "it works locally but not in production" bugs
Bad Code
<script setup>
const props = defineProps({
color: String, // 'red', 'blue', 'green'
size: String // 'sm', 'md', 'lg'
})
</script>
<template>
<!-- WRONG: Tailwind cannot detect these classes -->
<div :class="`bg-${color}-500 text-${size}`">
Content
</div>
<!-- WRONG: String concatenation -->
<div :class="'p-' + padding">
Content
</div>
<!-- WRONG: Template literal in array -->
<div :class="[`gap-x-${spacing}`]">
Content
</div>
</template>
Good Code
<script setup>
const props = defineProps({
color: String,
size: String
})
// Use a mapping object with complete class names
const colorClasses = {
red: 'bg-red-500',
blue: 'bg-blue-500',
green: 'bg-green-500'
}
const sizeClasses = {
sm: 'text-sm p-2',
md: 'text-base p-4',
lg: 'text-lg p-6'
}
</script>
<template>
<!-- CORRECT: Full class names that Tailwind can detect -->
<div :class="[colorClasses[color], sizeClasses[size]]">
Content
</div>
</template>
Using Conditional Objects
<script setup>
const props = defineProps({
variant: String // 'primary', 'secondary', 'danger'
})
</script>
<template>
<!-- CORRECT: All class names are complete strings -->
<button :class="{
'bg-blue-500 hover:bg-blue-600': variant === 'primary',
'bg-gray-500 hover:bg-gray-600': variant === 'secondary',
'bg-red-500 hover:bg-red-600': variant === 'danger'
}">
Click me
</button>
</template>
Safelist for Truly Dynamic Classes
If you must use dynamic classes, add them to Tailwind's safelist:
// tailwind.config.js
module.exports = {
safelist: [
'bg-red-500',
'bg-blue-500',
'bg-green-500',
// Or use patterns (use sparingly - increases bundle size)
{
pattern: /bg-(red|blue|green)-(100|500|900)/
}
]
}
Alternative: CSS Custom Properties
For truly dynamic values, use CSS custom properties:
<script setup>
const props = defineProps({
customColor: String // Any hex color
})
</script>
<template>
<!-- Use CSS variable for truly dynamic values -->
<div
class="dynamic-bg"
:style="{ '--dynamic-color': customColor }"
>
Content
</div>
</template>
<style>
.dynamic-bg {
background-color: var(--dynamic-color);
}
</style>