docs(claude): 清理和优化CLAUDE.md项目文档规范
优化CLAUDE.md文档结构,移除重复和过时的示例代码,提高文档的可读性和实用性。 主要变更: - 删除重复的按钮示例代码片段 - 精简弹框组件使用示例 - 优化图标使用规范的代码示例 - 统一代码样式和格式 - 保持核心规范要求不变 文档优化后更加简洁明了,便于开发团队参考和遵循。
This commit is contained in:
parent
4264ef36b7
commit
0f98692b25
331
CLAUDE.md
331
CLAUDE.md
@ -368,54 +368,6 @@ coiMsgBox('确定要删除吗?', '删除确认').then(() => {
|
|||||||
- ❌ 图标与功能语义不匹配
|
- ❌ 图标与功能语义不匹配
|
||||||
- ❌ 在表格列表页面使用圆角按钮(`round` 属性)
|
- ❌ 在表格列表页面使用圆角按钮(`round` 属性)
|
||||||
|
|
||||||
### 示例:完整的页面按钮实现
|
|
||||||
```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函数中图标渲染规范(强制要求)
|
### 🚀 render函数中图标渲染规范(强制要求)
|
||||||
|
|
||||||
**在DataTable等组件的render函数中使用图标时,必须遵循以下规范**
|
**在DataTable等组件的render函数中使用图标时,必须遵循以下规范**
|
||||||
@ -528,41 +480,6 @@ const columns: DataTableColumns<DataType> = [
|
|||||||
default: () => '编辑',
|
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)
|
return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -780,40 +697,6 @@ const deleteDialogRef = ref()
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</CoiDialog>
|
</CoiDialog>
|
||||||
|
|
||||||
<!-- 仅查看类弹框示例(无确认按钮) -->
|
|
||||||
<CoiDialog
|
|
||||||
ref="viewDialogRef"
|
|
||||||
title="查看详情"
|
|
||||||
:width="600"
|
|
||||||
height="auto"
|
|
||||||
cancel-text="关闭"
|
|
||||||
:show-confirm="false"
|
|
||||||
@coi-cancel="handleClose"
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<div class="p-3">
|
|
||||||
<!-- 查看内容 -->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</CoiDialog>
|
|
||||||
|
|
||||||
<!-- 禁用ESC键关闭的弹框示例 -->
|
|
||||||
<CoiDialog
|
|
||||||
ref="criticalDialogRef"
|
|
||||||
title="重要操作确认"
|
|
||||||
:width="600"
|
|
||||||
:close-on-esc="false"
|
|
||||||
:mask-closable="false"
|
|
||||||
@coi-confirm="handleCriticalConfirm"
|
|
||||||
@coi-cancel="handleCriticalCancel"
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<div class="p-3">
|
|
||||||
<p class="text-red-600">此操作不可逆,请谨慎操作!</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</CoiDialog>
|
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1069,20 +952,6 @@ var(--info-color) /* 信息色 */
|
|||||||
</template>
|
</template>
|
||||||
新增
|
新增
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|
||||||
<NButton type="error" @click="handleDelete">
|
|
||||||
<template #icon>
|
|
||||||
<NIcon><icon-park-outline:delete /></NIcon>
|
|
||||||
</template>
|
|
||||||
删除
|
|
||||||
</NButton>
|
|
||||||
|
|
||||||
<NButton @click="handleExport">
|
|
||||||
<template #icon>
|
|
||||||
<NIcon><icon-park-outline:download /></NIcon>
|
|
||||||
</template>
|
|
||||||
导出
|
|
||||||
</NButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 数据表格 - 表头不加粗,使用默认样式 -->
|
<!-- 数据表格 - 表头不加粗,使用默认样式 -->
|
||||||
@ -1349,62 +1218,6 @@ import { coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
|||||||
</template>
|
</template>
|
||||||
新增
|
新增
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|
||||||
<NButton type="error" @click="handleDelete">
|
|
||||||
<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>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 错误示例(严格禁止)
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<template>
|
|
||||||
<div class="page-actions">
|
|
||||||
<!-- ❌ 错误:使用圆角按钮 -->
|
|
||||||
<NButton type="primary" round @click="handleAdd">
|
|
||||||
<template #icon>
|
|
||||||
<NIcon><icon-park-outline:plus /></NIcon>
|
|
||||||
</template>
|
|
||||||
新增
|
|
||||||
</NButton>
|
|
||||||
|
|
||||||
<!-- ❌ 错误:只有文字没有图标 -->
|
|
||||||
<NButton type="primary" @click="handleAdd">
|
|
||||||
新增
|
|
||||||
</NButton>
|
|
||||||
|
|
||||||
<!-- ❌ 错误:只有图标没有文字 -->
|
|
||||||
<NButton type="primary" @click="handleAdd">
|
|
||||||
<template #icon>
|
|
||||||
<NIcon><icon-park-outline:plus /></NIcon>
|
|
||||||
</template>
|
|
||||||
</NButton>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
@ -1750,3 +1563,147 @@ import { coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi'
|
|||||||
- Node.js 21.x
|
- Node.js 21.x
|
||||||
- pnpm 10.x
|
- pnpm 10.x
|
||||||
- 现代浏览器支持ES6+
|
- 现代浏览器支持ES6+
|
||||||
|
|
||||||
|
## 🔢 雪花ID和大数字处理规范(强制要求)
|
||||||
|
|
||||||
|
**项目使用雪花ID算法生成唯一标识,必须严格按照以下规范处理大数字精度问题**
|
||||||
|
|
||||||
|
### 问题背景
|
||||||
|
|
||||||
|
**JavaScript数字精度限制**:
|
||||||
|
- 雪花ID长度:19位数字(如:`194285920715864064`)
|
||||||
|
- JavaScript安全整数范围:`Number.MAX_SAFE_INTEGER = 9007199254740991`(16位数字)
|
||||||
|
- **超过安全整数范围的数字会发生精度丢失**
|
||||||
|
|
||||||
|
**典型问题示例**:
|
||||||
|
```text
|
||||||
|
// 精度丢失示例
|
||||||
|
194285920715864064 变成 194285920715864060 // 末尾数字被修改
|
||||||
|
```
|
||||||
|
|
||||||
|
### 核心原则
|
||||||
|
|
||||||
|
1. **全链路字符串保持**:从数据库到前端,再到API调用,都保持字符串格式
|
||||||
|
2. **后端安全转换**:只在后端业务逻辑中进行字符串到Long的转换
|
||||||
|
3. **前端零转换**:前端严禁将大数字ID转换为Number类型
|
||||||
|
4. **向后兼容**:同时支持短ID和长ID的处理
|
||||||
|
|
||||||
|
### 强制实施规范
|
||||||
|
|
||||||
|
#### 1. **前端API接口设计**
|
||||||
|
|
||||||
|
**✅ 正确的API设计**:
|
||||||
|
```typescript
|
||||||
|
// 接收和发送都使用字符串格式
|
||||||
|
export function saveRoleMenuPermission(roleId: string, menuIds: string[]) {
|
||||||
|
const menuIdsStr = menuIds.length > 0 ? menuIds : ['-1']
|
||||||
|
return request.Post<Service.ResponseResult<string>>('/coder/sysMenu/saveRoleMenu', {
|
||||||
|
roleId, // 字符串格式
|
||||||
|
menuIds: menuIdsStr // 字符串数组格式
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**❌ 错误的API设计**:
|
||||||
|
```typescript
|
||||||
|
// 不要在前端进行数字转换
|
||||||
|
export function saveRoleMenuPermission(roleId: string, menuIds: string[]) {
|
||||||
|
const menuIdsLong = menuIds.map(id => Number(id)) // ❌ 会造成精度丢失
|
||||||
|
return request.Post('/api/save', {
|
||||||
|
roleId: Number(roleId), // ❌ 会造成精度丢失
|
||||||
|
menuIds: menuIdsLong // ❌ 会造成精度丢失
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. **前端类型定义规范**
|
||||||
|
|
||||||
|
**✅ 正确的类型定义**:
|
||||||
|
```typescript
|
||||||
|
// 所有ID相关字段使用字符串类型
|
||||||
|
export interface RoleMenuPermissionBo {
|
||||||
|
roleId: string // 字符串格式避免精度丢失
|
||||||
|
menuIds: string[] // 字符串数组格式避免精度丢失
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserVo {
|
||||||
|
userId: string // 字符串格式
|
||||||
|
roleId: string // 字符串格式
|
||||||
|
menuIds: string[] // 字符串数组格式
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**❌ 错误的类型定义**:
|
||||||
|
```typescript
|
||||||
|
// 不要使用number类型处理大数字ID
|
||||||
|
export interface RoleMenuPermissionBo {
|
||||||
|
roleId: number // ❌ 会造成精度丢失
|
||||||
|
menuIds: number[] // ❌ 会造成精度丢失
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. **前端数据处理规范**
|
||||||
|
|
||||||
|
**✅ 正确的数据处理**:
|
||||||
|
```typescript
|
||||||
|
// 保持字符串格式进行比较和处理
|
||||||
|
function handleRowSelectionChange(rowKeys: (string | number)[]) {
|
||||||
|
const stringKeys = rowKeys.map(key => String(key))
|
||||||
|
selectedRows.value = tableData.value.filter(row =>
|
||||||
|
stringKeys.includes(String(row.roleId))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送API请求时保持字符串格式
|
||||||
|
const response = await saveRoleMenuPermission(
|
||||||
|
String(currentRole.roleId),
|
||||||
|
selectedMenuIds // 已经是字符串数组
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**❌ 错误的数据处理**:
|
||||||
|
```typescript
|
||||||
|
// 不要将字符串ID转换为数字
|
||||||
|
function handleRowSelectionChange(rowKeys: (string | number)[]) {
|
||||||
|
const numericKeys = rowKeys.map(key => Number(key)) // ❌ 精度丢失
|
||||||
|
selectedRows.value = tableData.value.filter(row =>
|
||||||
|
numericKeys.includes(Number(row.roleId)) // ❌ 精度丢失
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不要在发送前进行数字转换
|
||||||
|
const menuIds = selectedMenuIds.map(id => Number(id)) // ❌ 精度丢失
|
||||||
|
const response = await saveRoleMenuPermission(
|
||||||
|
Number(currentRole.roleId), // ❌ 精度丢失
|
||||||
|
menuIds
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 检查清单
|
||||||
|
|
||||||
|
**开发新功能时,必须确保**:
|
||||||
|
- [ ] 前端类型定义中所有ID字段使用string类型
|
||||||
|
- [ ] 前端API调用保持字符串格式,不进行Number转换
|
||||||
|
- [ ] 前端数据处理中避免parseInt()、Number()等数字转换
|
||||||
|
- [ ] 后端BO类提供字符串接收和Long转换的安全方法
|
||||||
|
- [ ] 后端控制器使用安全转换方法
|
||||||
|
- [ ] 后端服务层对无效ID进行过滤处理
|
||||||
|
|
||||||
|
### 常见问题排查
|
||||||
|
|
||||||
|
**当遇到大数字ID相关问题时,按以下步骤排查**:
|
||||||
|
1. **检查前端是否进行了数字转换**:搜索`Number(`、`parseInt(`、`parseFloat(`
|
||||||
|
2. **检查API调用参数格式**:确认发送的是字符串而非数字
|
||||||
|
3. **检查后端BO类设计**:确认使用字符串接收和安全转换
|
||||||
|
4. **检查数据库表字段类型**:确认使用`bigint`类型存储
|
||||||
|
5. **检查序列化配置**:确认JSON序列化时大数字转为字符串
|
||||||
|
|
||||||
|
### 历史修复案例
|
||||||
|
|
||||||
|
**案例:菜单权限分配失败**
|
||||||
|
- **问题**:雪花ID在前端Number转换时精度丢失
|
||||||
|
- **症状**:部门管理等新菜单权限无法保存
|
||||||
|
- **解决**:全链路改为字符串格式,后端安全转换
|
||||||
|
- **文件**:`SysRoleMenuBo.java`、`saveRoleMenuPermission API`、角色管理页面
|
||||||
|
|
||||||
|
**遵循此规范可彻底避免大数字精度丢失问题,确保系统稳定运行!**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user