# Uni-App-X 样式规范 - CRMEB 风格指南

## 📚 概述

本文档定义了 mall 项目中所有页面的样式规范，参考 CRMEB 设计系统，使用 uni-app-x 的 `.uvue` 组件和 UTS 语言实现。

---

## 1. 颜色规范

### 1.1 基础色板

```typescript
// 在 uni.scss 中定义，所有 .uvue 文件都可使用

// 主要色系
$primary-color: #1890ff      // 蓝色 - 主交互色
$success-color: #52c41a      // 绿色 - 成功状态
$warning-color: #faad14      // 黄色 - 警告状态
$error-color: #ff4d4f        // 红色 - 错误状态
$info-color: #1890ff         // 信息色
$disabled-color: #bfbfbf     // 禁用色

// 文字色系
$text-primary: #000000       // 主文本（标题、重点内容）
$text-secondary: #666666     // 次文本（辅助信息）
$text-tertiary: #999999      // 三级文本（弱化信息）
$text-disabled: #bfbfbf      // 禁用文本

// 背景色系
$background-primary: #ffffff // 主背景（卡片、模态框）
$background-secondary: #fafafa // 次背景
$background-tertiary: #f5f5f5  // 页面背景

// 边框色系
$border-color: #d9d9d9       // 默认边框色
$border-light: #f0f0f0       // 浅边框（弱化分割）
$border-dark: #bfbfbf        // 深边框（强调分割）
```

### 1.2 使用示例

```uvue
<template>
  <view class="card">
    <text class="title">主标题</text>
    <text class="subtitle">副标题</text>
  </view>
</template>

<style scoped lang="scss">
.card {
  background: $background-primary;
  border: 1px solid $border-color;
  color: $text-primary;
}

.title {
  color: $text-primary;
}

.subtitle {
  color: $text-secondary;
}
</style>
```

---

## 2. 间距规范

### 2.1 间距系统

所有间距（margin、padding）**必须使用** `$space-*` 变量，基准为 **4px**：

```typescript
$space-0: 0          // 无间距
$space-xs: 4px       // 极小 - 图标之间
$space-sm: 8px       // 小 - 小组件间距
$space: 12px         // 基础 - 标准间距
$space-md: 16px      // 中 - 块级元素间距
$space-lg: 24px      // 大 - 大块间距
$space-xl: 32px      // 极大 - 页面级间距
$space-2xl: 48px     // 双倍极大
```

### 2.2 间距使用规则

```scss
// ✅ 正确用法

// 单个方向
.button {
  margin-bottom: $space; // 12px
  padding: $space-md; // 16px
  margin-right: $space-sm; // 8px
}

// 组合方向
.header {
  padding: $space-lg $space-md; // 24px 16px
  margin: $space 0; // 12px 0
}

// ❌ 错误用法 - 不要这样做！
.button {
  margin-bottom: 12px; // 不要使用硬编码值
  padding: 5px; // 不要使用任意值
  margin-right: 15px; // 必须使用变量
}
```

### 2.3 常见间距场景

```scss
// 页面顶层间距
.page {
  padding: $space-lg; // 24px - 页面内边距
}

// 卡片间距
.card {
  padding: $space-md; // 16px
  margin-bottom: $space-lg; // 24px
}

// 表单项目间距
.form-item {
  margin-bottom: $form-item-margin-bottom; // 16px
}

// 列表项目间距
.list-item {
  padding: $space-md;
  border-bottom: 1px solid $border-light;

  &:not(:last-child) {
    margin-bottom: 0; // 用 border 替代
  }
}

// 按钮组间距
.button-group {
  display: flex;
  gap: $space-sm; // 8px
}

// 文字间距
.paragraph {
  line-height: $line-height-lg; // 1.8
  margin-bottom: $space; // 12px
}
```

---

## 3. 圆角规范

### 3.1 圆角系统

```typescript
$radius-0: 0          // 无圆角 - 锐角边缘
$radius-xs: 2px       // 极小 - 微调
$radius-sm: 4px       // 小 - 细微圆角
$radius: 6px          // 默认 - 标准圆角（最常用）
$radius-lg: 8px       // 大 - 明显圆角
$radius-xl: 12px      // 极大 - 大圆角
$radius-2xl: 16px     // 双倍极大
$radius-full: 9999px  // 完全圆形（胶囊形）
```

### 3.2 圆角使用规则

```scss
// ✅ 正确用法

.card {
  border-radius: $radius; // 6px - 卡片默认值
}

.badge {
  border-radius: $radius-full; // 9999px - 圆形徽章
}

.button {
  border-radius: $radius-sm; // 4px - 按钮圆角
}

.tag {
  border-radius: $radius-sm; // 4px
}

.input {
  border-radius: $radius-xs; // 2px - 输入框微调
}

// ❌ 不要这样做
.card {
  border-radius: 8px; // 不要硬编码
  border-radius: 50%; // 不要使用百分比
}
```

### 3.3 场景应用

```scss
// 页面卡片
.page-card {
  background: $background-primary;
  border-radius: $radius;
  box-shadow: $shadow;
}

// 按钮
.btn {
  border-radius: $radius-sm;
  padding: $space-sm $space-md;
}

// 输入框
.input {
  border-radius: $radius-xs;
  border: 1px solid $border-color;
  padding: $space-sm $space-sm;
}

// 头像（圆形）
.avatar {
  border-radius: $radius-full;
  width: 40px;
  height: 40px;
}

// 标签
.tag {
  display: inline-block;
  padding: $space-xs $space-sm;
  border-radius: $radius-sm;
  background: $background-secondary;
}
```

---

## 4. 阴影规范

### 4.1 阴影系统

```typescript
$shadow-none: none      // 无阴影
$shadow-xs: 0 1px 2px 0 rgba(0,0,0, 0.05)
$shadow-sm: 0 1px 2px 0 rgba(0,0,0, 0.06)
$shadow: 0 4px 6px -1px rgba(0,0,0, 0.1), 0 2px 4px -1px rgba(0,0,0, 0.06)    // 默认
$shadow-md: 0 10px 15px -3px rgba(0,0,0, 0.1), 0 4px 6px -2px rgba(0,0,0, 0.05)
$shadow-lg: 0 20px 25px -5px rgba(0,0,0, 0.1), 0 10px 10px -5px rgba(0,0,0, 0.04)
$shadow-xl: 0 25px 50px -12px rgba(0,0,0, 0.25)    // 强调
```

### 4.2 阴影使用规则

```scss
// ✅ 正确用法

// 卡片 - 使用标准阴影
.card {
  background: $background-primary;
  border-radius: $radius;
  box-shadow: $shadow; // 标准阴影
  padding: $space-md;
}

// 浮动元素 - 使用较强阴影
.floating-btn {
  box-shadow: $shadow-lg; // 强调阴影
}

// 模态框 - 使用最强阴影
.modal {
  box-shadow: $shadow-xl;
}

// 弱化分割线
.divider {
  box-shadow: $shadow-xs; // 极弱阴影
  height: 1px;
}

// ❌ 不要这样做
.card {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); // 不要硬编码
  box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); // 不要使用任意值
}
```

### 4.3 场景应用

| 场景       | 阴影       | 说明     |
| ---------- | ---------- | -------- |
| 页面背景   | none       | 无需阴影 |
| 卡片       | $shadow    | 标准卡片 |
| 列表项     | $shadow-xs | 弱化分割 |
| 下拉菜单   | $shadow-lg | 浮动显示 |
| 模态框背景 | $shadow-xl | 强调焦点 |
| 悬停状态   | $shadow-md | 交互反馈 |
| 输入框     | $shadow-xs | 焦点提示 |

---

## 5. 字体规范

### 5.1 字体大小系统

```typescript
$font-size-xs: 12px         // 极小 - 说明文字
$font-size-sm: 13px         // 小 - 辅助信息
$font-size: 14px            // 默认 - 正文（最常用）
$font-size-md: 16px         // 中 - 卡片标题
$font-size-lg: 18px         // 大 - 页面二级标题
$font-size-xl: 20px         // 极大 - 页面一级标题
$font-size-2xl: 24px        // 双倍极大
$font-size-3xl: 30px        // 三倍极大 - 页面主标题
```

### 5.2 行高和字重

```typescript
// 行高
$line-height-xs: 1.2        // 紧凑 - 标题
$line-height-sm: 1.4        // 小
$line-height: 1.6           // 默认 - 正文
$line-height-lg: 1.8        // 大
$line-height-xl: 2          // 特大 - 宽松

// 字重
$font-weight-normal: 400     // 常规
$font-weight-medium: 500     // 中等（用于强调）
$font-weight-semibold: 600   // 半粗体（用于标题）
$font-weight-bold: 700       // 粗体（强调标题）
```

### 5.3 排版规范

```scss
// ✅ 正确用法

// 页面主标题
.page-title {
  font-size: $font-size-lg;
  font-weight: $font-weight-bold;
  color: $text-primary;
  margin-bottom: $space-md;
}

// 卡片标题
.card-title {
  font-size: $font-size-md;
  font-weight: $font-weight-semibold;
  color: $text-primary;
}

// 正文
.content {
  font-size: $font-size;
  line-height: $line-height;
  color: $text-secondary;
}

// 说明文字
.description {
  font-size: $font-size-sm;
  color: $text-tertiary;
  line-height: $line-height-sm;
}

// ❌ 不要这样做
.title {
  font-size: 18px; // 不要硬编码
  font-weight: bold; // 不要使用 bold
  line-height: 1.5; // 不要硬编码
}
```

### 5.4 排版场景

```scss
// 标题层级
h1 {
  font-size: $font-size-3xl;
  font-weight: $font-weight-bold;
}
h2 {
  font-size: $font-size-xl;
  font-weight: $font-weight-bold;
}
h3 {
  font-size: $font-size-lg;
  font-weight: $font-weight-semibold;
}
h4 {
  font-size: $font-size-md;
  font-weight: $font-weight-medium;
}

// 段落
p {
  font-size: $font-size;
  line-height: $line-height;
  margin-bottom: $space-md;
}

// 列表项
li {
  font-size: $font-size;
  line-height: $line-height;
  margin-bottom: $space-sm;
}

// 表格
td {
  font-size: $font-size;
  line-height: $line-height;
  padding: $space-sm;
}
```

---

## 6. 动画和过渡

### 6.1 过渡系统

```typescript
$transition-duration-fast: 0.1s
$transition-duration: 0.3s                        // 默认
$transition-duration-slow: 0.5s

$transition-timing-linear: linear                 // 匀速
$transition-timing: cubic-bezier(0.645, 0.045, 0.355, 1)  // 标准缓动（推荐）
$transition-timing-ease-in: cubic-bezier(0.4, 0, 1, 1)
$transition-timing-ease-out: cubic-bezier(0, 0, 0.2, 1)
$transition-timing-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1)
```

### 6.2 过渡使用

```scss
// ✅ 正确用法

// 悬停效果
.button {
  background: $primary-color;
  transition: all $transition-duration $transition-timing;

  &:active {
    opacity: 0.8;
  }
}

// 展开/折叠
.collapse {
  transition: height $transition-duration $transition-timing;
}

// 淡入淡出
.fade-enter-active,
.fade-leave-active {
  transition: opacity $transition-duration $transition-timing;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
```

---

## 7. 响应式设计

### 7.1 断点系统

```typescript
$breakpoint-xs: 320px    // 极小屏幕
$breakpoint-sm: 576px    // 小屏（平板）
$breakpoint-md: 768px    // 中屏（平板）
$breakpoint-lg: 992px    // 大屏（笔记本）
$breakpoint-xl: 1200px   // 特大屏（桌面）
$breakpoint-2xl: 1600px  // 超大屏
```

### 7.2 媒体查询使用

```scss
// 手机优先设计

.page {
  padding: $space; // 手机：12px

  @media (min-width: $breakpoint-sm) {
    padding: $space-md; // 平板：16px
  }

  @media (min-width: $breakpoint-lg) {
    padding: $space-lg; // 桌面：24px
  }
}

// 栅格布局
.grid {
  display: grid;
  grid-template-columns: 1fr; // 手机：1列

  @media (min-width: $breakpoint-sm) {
    grid-template-columns: repeat(2, 1fr); // 平板：2列
  }

  @media (min-width: $breakpoint-lg) {
    grid-template-columns: repeat(3, 1fr); // 桌面：3列
  }
}
```

---

## 8. Z-index 管理

### 8.1 Z-index 系统

```typescript
$z-index-hide: -1
$z-index-base: 0

// 导航
$z-index-navbar: 100
$z-index-sidebar: 99
$z-index-sticky: 50

// 浮层
$z-index-dropdown: 1000
$z-index-popover: 1010
$z-index-tooltip: 1020
$z-index-modal-backdrop: 1040
$z-index-modal: 1050
$z-index-popconfirm: 1060
$z-index-notification: 1070
```

### 8.2 使用规则

```scss
.navbar {
  z-index: $z-index-navbar; // 导航栏始终在最上
}

.modal-backdrop {
  z-index: $z-index-modal-backdrop;
}

.modal {
  z-index: $z-index-modal; // 模态框在背景上方
}

.tooltip {
  z-index: $z-index-tooltip; // 提示框最高层
}
```

---

## 9. 常见组件样式

### 9.1 卡片（Card）

```uvue
<template>
  <view class="card">
    <view class="card-header">
      <text class="card-title">卡片标题</text>
    </view>
    <view class="card-body">
      <!-- 内容 -->
    </view>
    <view class="card-footer">
      <!-- 底部 -->
    </view>
  </view>
</template>

<style scoped lang="scss">
.card {
  background: $background-primary;
  border-radius: $radius;
  box-shadow: $shadow;
  overflow: hidden;
}

.card-header {
  padding: $space-md;
  border-bottom: 1px solid $border-light;
}

.card-title {
  font-size: $font-size-md;
  font-weight: $font-weight-semibold;
  color: $text-primary;
}

.card-body {
  padding: $space-md;
}

.card-footer {
  padding: $space-md;
  border-top: 1px solid $border-light;
  display: flex;
  gap: $space-sm;
  justify-content: flex-end;
}
</style>
```

### 9.2 按钮（Button）

```scss
.btn {
  height: $btn-height;
  padding: 0 $space-md;
  border: none;
  border-radius: $radius-sm;
  font-size: $font-size;
  font-weight: $font-weight-medium;
  cursor: pointer;
  transition: all $transition-duration $transition-timing;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: $space-xs;

  // 主按钮
  &.btn-primary {
    background: $primary-color;
    color: #fff;

    &:active {
      opacity: 0.8;
    }
  }

  // 次按钮
  &.btn-default {
    background: $background-secondary;
    color: $text-primary;
    border: 1px solid $border-color;

    &:active {
      background: $border-light;
    }
  }

  // 危险按钮
  &.btn-danger {
    background: $error-color;
    color: #fff;

    &:active {
      opacity: 0.8;
    }
  }

  // 尺寸
  &.btn-sm {
    height: $btn-height-sm;
    font-size: $font-size-sm;
    padding: 0 $space-sm;
  }

  &.btn-lg {
    height: $btn-height-lg;
    font-size: $font-size-md;
    padding: 0 $space-lg;
  }

  // 禁用状态
  &:disabled,
  &.disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}
```

### 9.3 输入框（Input）

```scss
.input {
  height: $input-height;
  padding: 0 $space-sm;
  border: 1px solid $border-color;
  border-radius: $radius-xs;
  font-size: $font-size;
  color: $text-primary;
  background: $background-primary;
  transition: border-color $transition-duration $transition-timing;

  &::placeholder {
    color: $text-tertiary;
  }

  &:focus {
    outline: none;
    border-color: $primary-color;
    box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
  }

  &:disabled {
    background: $background-secondary;
    color: $text-disabled;
    cursor: not-allowed;
  }

  // 尺寸变体
  &.input-sm {
    height: $input-height-sm;
  }

  &.input-lg {
    height: $input-height-lg;
  }
}
```

---

## 10. 完整示例：列表页面

```uvue
<template>
  <view class="list-page">
    <!-- 页面标题 -->
    <view class="page-header">
      <text class="page-title">数据列表</text>
      <view class="page-actions">
        <button class="btn btn-primary">新增</button>
        <button class="btn btn-default">导出</button>
      </view>
    </view>

    <!-- 搜索表单 -->
    <view class="search-card">
      <view class="form-item">
        <text class="form-label">搜索:</text>
        <input class="input" placeholder="请输入关键词" />
      </view>
    </view>

    <!-- 列表内容 -->
    <view class="list-card">
      <view class="list-item" v-for="item in items" :key="item.id">
        <view class="list-item-header">
          <text class="list-item-title">{{ item.name }}</text>
          <text class="list-item-status">{{ item.status }}</text>
        </view>
        <text class="list-item-desc">{{ item.description }}</text>
        <view class="list-item-footer">
          <text class="list-item-time">{{ item.createTime }}</text>
          <view class="list-item-actions">
            <button class="btn-link">编辑</button>
            <button class="btn-link btn-danger">删除</button>
          </view>
        </view>
      </view>
    </view>

    <!-- 分页 -->
    <view class="pagination">
      <button class="btn btn-sm">上一页</button>
      <text>第 1 页，共 10 页</text>
      <button class="btn btn-sm">下一页</button>
    </view>
  </view>
</template>

<script setup lang="uts">
import { ref } from 'vue'

const items = ref([
  { id: 1, name: '项目1', status: '进行中', description: '描述文本', createTime: '2024-01-01' },
  { id: 2, name: '项目2', status: '已完成', description: '描述文本', createTime: '2024-01-02' },
])
</script>

<style scoped lang="scss">
.list-page {
  padding: $space-lg;
  background: $background-tertiary;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: $space-lg;
}

.page-title {
  font-size: $font-size-lg;
  font-weight: $font-weight-bold;
  color: $text-primary;
}

.page-actions {
  display: flex;
  gap: $space-sm;
}

.search-card {
  background: $background-primary;
  border-radius: $radius;
  padding: $space-md;
  margin-bottom: $space-lg;
  box-shadow: $shadow;
}

.form-item {
  display: flex;
  align-items: center;
  gap: $space-md;
}

.form-label {
  color: $text-secondary;
  font-size: $font-size-sm;
}

.input {
  height: $input-height;
  padding: 0 $space-sm;
  border: 1px solid $border-color;
  border-radius: $radius-xs;
  flex: 1;
}

.list-card {
  background: $background-primary;
  border-radius: $radius;
  overflow: hidden;
  box-shadow: $shadow;
  margin-bottom: $space-lg;
}

.list-item {
  padding: $space-md;
  border-bottom: 1px solid $border-light;

  &:last-child {
    border-bottom: none;
  }
}

.list-item-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: $space-sm;
}

.list-item-title {
  font-size: $font-size-md;
  font-weight: $font-weight-medium;
  color: $text-primary;
}

.list-item-status {
  font-size: $font-size-xs;
  background: $background-secondary;
  color: $text-secondary;
  padding: $space-xs $space-sm;
  border-radius: $radius-xs;
}

.list-item-desc {
  font-size: $font-size-sm;
  color: $text-secondary;
  margin-bottom: $space-sm;
}

.list-item-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.list-item-time {
  font-size: $font-size-xs;
  color: $text-tertiary;
}

.list-item-actions {
  display: flex;
  gap: $space-sm;
}

.btn-link {
  background: none;
  border: none;
  color: $primary-color;
  padding: 0;
  font-size: $font-size-sm;
  cursor: pointer;

  &.btn-danger {
    color: $error-color;
  }
}

.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: $space-md;
  padding: $space-lg 0;
}
</style>
```

---

## 总结

✅ **必须遵循的规范**:

1. 所有色值必须使用 `$color-*` 变量
2. 所有间距必须使用 `$space-*` 变量
3. 所有圆角必须使用 `$radius-*` 变量
4. 所有阴影必须使用 `$shadow-*` 变量
5. 所有字体大小必须使用 `$font-size-*` 变量
6. 所有过渡必须使用 `$transition-*` 变量

❌ **禁止**:

- 硬编码任何数值（色值、尺寸、间距等）
- 使用不规范的命名
- 创建局部样式变量与系统冲突

📝 **维护建议**:

- 定期审查样式规范的使用情况
- 在新增样式变量前，检查是否已有相近的
- 保持设计系统的一致性和可维护性

---

**文档版本**: 1.0  
**最后更新**: 2026-01-31  
**维护者**: AI Assistant
