docs(guide): 完善项目开发规范和图标使用指南
文档更新: - 更新项目名称为Coi Admin,保持品牌一致性 - 新增完整的图标使用规范和最佳实践 - 添加render函数中图标渲染的详细指导 - 提供图标语义映射表和使用示例 - 明确图标使用的强制要求和禁止行为 规范内容: - 统一使用icon-park-outline图标库 - 模板中直接使用图标组件的正确方式 - render函数中图标组件的导入和使用规范 - 常用操作图标的语义化映射关系 - 完整的代码示例和错误示范对比
This commit is contained in:
parent
66fe7e6b87
commit
3d39ef37e2
324
CLAUDE.md
324
CLAUDE.md
@ -32,7 +32,7 @@ DRY (Don't Repeat Yourself):绝不复制代码片段。通过抽象(如函
|
||||
|
||||
## 项目概述
|
||||
|
||||
Nova Admin 是一个基于 Vue3、Vite5、TypeScript 和 Naive UI 的简洁后台管理模板,实现了完整的认证、权限管理、路由管理等功能。
|
||||
Coi Admin 是一个基于 Vue3、Vite5、TypeScript 和 Naive UI 的简洁后台管理模板,实现了完整的认证、权限管理、路由管理等功能。
|
||||
|
||||
## 常用命令
|
||||
|
||||
@ -251,6 +251,328 @@ coiMsgBox('确定要删除吗?', '删除确认').then(() => {
|
||||
})
|
||||
```
|
||||
|
||||
## 📝 图标使用规范(强制要求)
|
||||
|
||||
**项目中的图标使用规范,所有按钮和操作界面必须严格遵守**
|
||||
|
||||
### 核心原则
|
||||
1. **所有按钮必须配备图标** - 提升用户体验和界面美观度
|
||||
2. **图标必须语义化** - 图标含义要与按钮功能高度匹配
|
||||
3. **统一的图标库** - 统一使用 `icon-park-outline` 图标库
|
||||
|
||||
### 图标添加方式
|
||||
|
||||
**✅ 正确方式:直接在模板中使用图标组件**
|
||||
```vue
|
||||
<template>
|
||||
<!-- 基础按钮 -->
|
||||
<NButton type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<icon-park-outline:plus />
|
||||
</NIcon>
|
||||
</template>
|
||||
新增
|
||||
</NButton>
|
||||
|
||||
<!-- 条件图标显示 -->
|
||||
<NButton type="primary" @click="handleAction">
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<icon-park-outline:refresh v-if="hasSearchConditions()" />
|
||||
<icon-park-outline:plus v-else />
|
||||
</NIcon>
|
||||
</template>
|
||||
{{ actionText }}
|
||||
</NButton>
|
||||
|
||||
<!-- 在组件插槽中使用 -->
|
||||
<NovaEmpty>
|
||||
<template #action>
|
||||
<NButton type="primary" round>
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<icon-park-outline:plus />
|
||||
</NIcon>
|
||||
</template>
|
||||
新增数据
|
||||
</NButton>
|
||||
</template>
|
||||
</NovaEmpty>
|
||||
</template>
|
||||
```
|
||||
|
||||
**❌ 错误方式:字符串传递或复杂处理**
|
||||
```vue
|
||||
<!-- 错误:不要通过字符串传递图标 -->
|
||||
<MyComponent :icon="'icon-park-outline:plus'" />
|
||||
|
||||
<!-- 错误:不要通过h()函数处理图标 -->
|
||||
<MyComponent :icon="h('icon-park-outline:plus')" />
|
||||
|
||||
<!-- 错误:不要在组件内部处理字符串图标 -->
|
||||
<component :is="iconString" />
|
||||
```
|
||||
|
||||
### 常用图标语义映射
|
||||
|
||||
| 操作类型 | 推荐图标 | 示例场景 |
|
||||
|---------|---------|---------|
|
||||
| 新增/添加 | `icon-park-outline:plus` | 新增用户、添加数据 |
|
||||
| 编辑/修改 | `icon-park-outline:edit` | 编辑信息、修改配置 |
|
||||
| 删除 | `icon-park-outline:delete` | 删除记录、移除项目 |
|
||||
| 搜索 | `icon-park-outline:search` | 搜索按钮、查询操作 |
|
||||
| 刷新/重置 | `icon-park-outline:refresh` | 重置表单、刷新数据 |
|
||||
| 保存 | `icon-park-outline:check` | 保存设置、确认操作 |
|
||||
| 取消 | `icon-park-outline:close` | 取消操作、关闭弹框 |
|
||||
| 导出 | `icon-park-outline:download` | 导出数据、下载文件 |
|
||||
| 导入 | `icon-park-outline:upload` | 导入数据、上传文件 |
|
||||
| 设置 | `icon-park-outline:setting` | 系统设置、配置管理 |
|
||||
| 查看 | `icon-park-outline:preview-open` | 查看详情、预览内容 |
|
||||
| 复制 | `icon-park-outline:copy` | 复制内容、克隆数据 |
|
||||
|
||||
### 图标使用要求
|
||||
|
||||
**1. 必须添加图标的场景**
|
||||
- ✅ 所有操作按钮(新增、编辑、删除、保存等)
|
||||
- ✅ 搜索和重置按钮
|
||||
- ✅ 导入导出按钮
|
||||
- ✅ 空状态组件的操作按钮
|
||||
- ✅ 表单提交和取消按钮
|
||||
|
||||
**2. 图标尺寸规范**
|
||||
- 默认按钮:无需指定尺寸
|
||||
- 大按钮:可根据需要调整
|
||||
- 小按钮:保持图标清晰可见
|
||||
|
||||
**3. 图标样式要求**
|
||||
```vue
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<!-- 图标组件直接使用,无需额外样式 -->
|
||||
<icon-park-outline:plus />
|
||||
</NIcon>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 严格禁止行为
|
||||
- ❌ 按钮不添加图标
|
||||
- ❌ 使用字符串方式传递图标
|
||||
- ❌ 在JavaScript中动态处理图标组件
|
||||
- ❌ 使用其他图标库(除非特殊需求)
|
||||
- ❌ 图标与功能语义不匹配
|
||||
|
||||
### 示例:完整的页面按钮实现
|
||||
```vue
|
||||
<template>
|
||||
<div class="page-actions">
|
||||
<!-- 主要操作按钮 -->
|
||||
<NButton v-permission="PERMISSIONS.USER.ADD" type="primary" @click="handleAdd">
|
||||
<template #icon>
|
||||
<NIcon><icon-park-outline:plus /></NIcon>
|
||||
</template>
|
||||
新增
|
||||
</NButton>
|
||||
|
||||
<!-- 批量操作按钮 -->
|
||||
<NButton type="error" :disabled="selectedRows.length === 0" @click="handleBatchDelete">
|
||||
<template #icon>
|
||||
<NIcon><icon-park-outline:delete /></NIcon>
|
||||
</template>
|
||||
删除
|
||||
</NButton>
|
||||
|
||||
<!-- 功能按钮 -->
|
||||
<NButton @click="handleExport">
|
||||
<template #icon>
|
||||
<NIcon><icon-park-outline:download /></NIcon>
|
||||
</template>
|
||||
导出
|
||||
</NButton>
|
||||
|
||||
<!-- 搜索重置按钮 -->
|
||||
<NButton type="primary" @click="handleSearch">
|
||||
<template #icon>
|
||||
<NIcon><icon-park-outline:search /></NIcon>
|
||||
</template>
|
||||
搜索
|
||||
</NButton>
|
||||
|
||||
<NButton @click="handleReset">
|
||||
<template #icon>
|
||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
||||
</template>
|
||||
重置
|
||||
</NButton>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
**遵循此规范可确保项目界面的一致性和专业性!**
|
||||
|
||||
### 🚀 render函数中图标渲染规范(强制要求)
|
||||
|
||||
**在DataTable等组件的render函数中使用图标时,必须遵循以下规范**
|
||||
|
||||
#### 问题背景
|
||||
在render函数中,不能使用模板语法 `<icon-park-outline:edit />`,必须使用正确的组件引用方式。
|
||||
|
||||
#### 正确的render函数图标使用方式
|
||||
|
||||
**✅ 步骤1:导入具体的图标组件**
|
||||
```typescript
|
||||
// 从 ~icons 路径导入具体图标组件
|
||||
import IconParkOutlineEdit from '~icons/icon-park-outline/edit'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import IconParkOutlineRefresh from '~icons/icon-park-outline/refresh'
|
||||
import IconParkOutlineSetting from '~icons/icon-park-outline/setting'
|
||||
```
|
||||
|
||||
**✅ 步骤2:在render函数中使用组件引用**
|
||||
```typescript
|
||||
// 表格列定义中的正确用法
|
||||
const columns: DataTableColumns<UserVo> = [
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
render: (row) => {
|
||||
const buttons = []
|
||||
|
||||
// 编辑按钮 - 正确方式
|
||||
buttons.push(h(NButton, {
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => handleEdit(row),
|
||||
}, {
|
||||
icon: () => h(NIcon, { size: 14 }, { default: () => h(IconParkOutlineEdit) }),
|
||||
default: () => '编辑',
|
||||
}))
|
||||
|
||||
// 删除按钮 - 正确方式
|
||||
buttons.push(h(NButton, {
|
||||
type: 'error',
|
||||
size: 'small',
|
||||
onClick: () => handleDelete(row),
|
||||
}, {
|
||||
icon: () => h(NIcon, { size: 14 }, { default: () => h(IconParkOutlineDelete) }),
|
||||
default: () => '删除',
|
||||
}))
|
||||
|
||||
return h('div', { class: 'flex gap-2' }, buttons)
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**❌ 错误方式:使用字符串引用**
|
||||
```typescript
|
||||
// 这种方式在render函数中无效
|
||||
icon: () => h(NIcon, {}, { default: () => h('icon-park-outline:edit') })
|
||||
|
||||
// 这种方式也无效
|
||||
icon: () => h(NIcon, {}, { default: () => h('IconParkOutlineEdit') })
|
||||
```
|
||||
|
||||
#### 常用图标的正确导入方式
|
||||
|
||||
```typescript
|
||||
// 操作类图标
|
||||
import IconParkOutlineEdit from '~icons/icon-park-outline/edit' // 编辑
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete' // 删除
|
||||
import IconParkOutlineRefresh from '~icons/icon-park-outline/refresh' // 刷新/重置
|
||||
import IconParkOutlineSetting from '~icons/icon-park-outline/setting' // 设置/分配
|
||||
|
||||
// 功能类图标
|
||||
import IconParkOutlinePlus from '~icons/icon-park-outline/plus' // 新增
|
||||
import IconParkOutlineSearch from '~icons/icon-park-outline/search' // 搜索
|
||||
import IconParkOutlineDownload from '~icons/icon-park-outline/download' // 下载/导出
|
||||
import IconParkOutlineUpload from '~icons/icon-park-outline/upload' // 上传/导入
|
||||
import IconParkOutlinePreviewOpen from '~icons/icon-park-outline/preview-open' // 查看
|
||||
```
|
||||
|
||||
#### 完整示例:表格操作列实现
|
||||
|
||||
```typescript
|
||||
import { h } from 'vue'
|
||||
import { NButton, NIcon, NPopconfirm } from 'naive-ui'
|
||||
import IconParkOutlineEdit from '~icons/icon-park-outline/edit'
|
||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||
import IconParkOutlineSetting from '~icons/icon-park-outline/setting'
|
||||
|
||||
const columns: DataTableColumns<DataType> = [
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 280,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render: (row) => {
|
||||
const buttons = []
|
||||
|
||||
// 编辑按钮
|
||||
if (hasPermission('edit')) {
|
||||
buttons.push(h(NButton, {
|
||||
type: 'primary',
|
||||
size: 'small',
|
||||
onClick: () => handleEdit(row),
|
||||
}, {
|
||||
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, {
|
||||
default: () => h(IconParkOutlineEdit)
|
||||
}),
|
||||
default: () => '编辑',
|
||||
}))
|
||||
}
|
||||
|
||||
// 删除按钮(带确认)
|
||||
if (hasPermission('delete')) {
|
||||
buttons.push(h(NPopconfirm, {
|
||||
onPositiveClick: () => handleDelete(row.id),
|
||||
negativeText: '取消',
|
||||
positiveText: '确定',
|
||||
}, {
|
||||
default: () => '确定删除此项吗?',
|
||||
trigger: () => h(NButton, {
|
||||
type: 'error',
|
||||
size: 'small',
|
||||
}, {
|
||||
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, {
|
||||
default: () => h(IconParkOutlineDelete)
|
||||
}),
|
||||
default: () => '删除',
|
||||
}),
|
||||
}))
|
||||
}
|
||||
|
||||
// 设置按钮
|
||||
if (hasPermission('setting')) {
|
||||
buttons.push(h(NButton, {
|
||||
type: 'warning',
|
||||
size: 'small',
|
||||
onClick: () => handleSetting(row),
|
||||
}, {
|
||||
icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, {
|
||||
default: () => h(IconParkOutlineSetting)
|
||||
}),
|
||||
default: () => '设置',
|
||||
}))
|
||||
}
|
||||
|
||||
return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
#### 核心要点总结
|
||||
|
||||
1. **导入方式**:使用 `~icons/icon-park-outline/图标名` 导入具体组件
|
||||
2. **组件引用**:在render函数中使用 `h(IconComponent)` 而非字符串
|
||||
3. **命名规范**:图标组件名采用 `IconParkOutline + 图标名(首字母大写)` 格式
|
||||
4. **样式调整**:可通过 `style` 属性微调图标位置和样式
|
||||
5. **尺寸设置**:通过 `NIcon` 的 `size` 属性控制图标大小
|
||||
|
||||
**遵循此规范确保render函数中的图标能正确显示!**
|
||||
|
||||
## 开发注意事项
|
||||
|
||||
### 添加新页面
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "nova-admin",
|
||||
"name": "coi-admin",
|
||||
"version": "0.9.15",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user