Compare commits
10 Commits
849ff71393
...
0f98692b25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f98692b25 | ||
|
|
4264ef36b7 | ||
|
|
f5b06cb9b9 | ||
|
|
0fa1451e27 | ||
|
|
ed949fbdb3 | ||
|
|
7b322a3da5 | ||
|
|
1b2191fc2f | ||
|
|
dc2162d36e | ||
|
|
d84ec11a32 | ||
|
|
b430f4ef1e |
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`、角色管理页面
|
||||||
|
|
||||||
|
**遵循此规范可彻底避免大数字精度丢失问题,确保系统稳定运行!**
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "nova-admin",
|
"name": "coi-admin",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.9.15",
|
"version": "0.9.15",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@ -5,12 +5,12 @@
|
|||||||
<div class="coi-empty__icon-wrapper">
|
<div class="coi-empty__icon-wrapper">
|
||||||
<div class="coi-empty__icon-bg" />
|
<div class="coi-empty__icon-bg" />
|
||||||
<NIcon class="coi-empty__icon" :size="iconSize" :color="iconColor">
|
<NIcon class="coi-empty__icon" :size="iconSize" :color="iconColor">
|
||||||
<icon-park-outline:inbox v-if="currentType === 'default'" />
|
<icon-park-outline-inbox v-if="currentType === 'default'" />
|
||||||
<icon-park-outline:search v-else-if="currentType === 'search'" />
|
<icon-park-outline-search v-else-if="currentType === 'search'" />
|
||||||
<icon-park-outline:folder-close v-else-if="currentType === 'network'" />
|
<icon-park-outline-folder-close v-else-if="currentType === 'network'" />
|
||||||
<icon-park-outline:lock v-else-if="currentType === 'permission'" />
|
<icon-park-outline-lock v-else-if="currentType === 'permission'" />
|
||||||
<icon-park-outline:folder-close v-else-if="currentType === 'custom'" />
|
<icon-park-outline-folder-close v-else-if="currentType === 'custom'" />
|
||||||
<icon-park-outline:inbox v-else />
|
<icon-park-outline-inbox v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -36,8 +36,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="coi-empty__action-icon">
|
<NIcon class="coi-empty__action-icon">
|
||||||
<icon-park-outline:refresh v-if="currentType === 'search'" />
|
<icon-park-outline-refresh v-if="currentType === 'search'" />
|
||||||
<icon-park-outline:plus v-else />
|
<icon-park-outline-plus v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ actionText }}
|
{{ actionText }}
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
@click="handlePageChange(1)"
|
@click="handlePageChange(1)"
|
||||||
>
|
>
|
||||||
<NIcon size="14">
|
<NIcon size="14">
|
||||||
<icon-park-outline:go-start />
|
<icon-park-outline-go-start />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -44,7 +44,7 @@
|
|||||||
@click="handlePageChange(currentPage - 1)"
|
@click="handlePageChange(currentPage - 1)"
|
||||||
>
|
>
|
||||||
<NIcon size="14">
|
<NIcon size="14">
|
||||||
<icon-park-outline:left />
|
<icon-park-outline-left />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -74,7 +74,7 @@
|
|||||||
@click="handlePageChange(currentPage + 1)"
|
@click="handlePageChange(currentPage + 1)"
|
||||||
>
|
>
|
||||||
<NIcon size="14">
|
<NIcon size="14">
|
||||||
<icon-park-outline:right />
|
<icon-park-outline-right />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@ -85,7 +85,7 @@
|
|||||||
@click="handlePageChange(totalPages)"
|
@click="handlePageChange(totalPages)"
|
||||||
>
|
>
|
||||||
<NIcon size="14">
|
<NIcon size="14">
|
||||||
<icon-park-outline:go-end />
|
<icon-park-outline-go-end />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -54,7 +54,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 0,
|
id: 0,
|
||||||
type: 0,
|
type: 0,
|
||||||
title: 'Admin 已经完成40%了!',
|
title: 'Admin 已经完成40%了!',
|
||||||
icon: 'icon-park-outline:tips-one',
|
icon: 'icon-park-outline-tips-one',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
tagType: 'info',
|
tagType: 'info',
|
||||||
description: '项目稳定推进中,很快就能看到正式版了',
|
description: '项目稳定推进中,很快就能看到正式版了',
|
||||||
@ -64,7 +64,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 1,
|
id: 1,
|
||||||
type: 0,
|
type: 0,
|
||||||
title: 'Admin 已经添加通知功能!',
|
title: 'Admin 已经添加通知功能!',
|
||||||
icon: 'icon-park-outline:comment-one',
|
icon: 'icon-park-outline-comment-one',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
tagType: 'success',
|
tagType: 'success',
|
||||||
date: '2022-2-2 12:22',
|
date: '2022-2-2 12:22',
|
||||||
@ -73,7 +73,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 2,
|
id: 2,
|
||||||
type: 0,
|
type: 0,
|
||||||
title: 'Admin 已经添加路由功能!',
|
title: 'Admin 已经添加路由功能!',
|
||||||
icon: 'icon-park-outline:message-emoji',
|
icon: 'icon-park-outline-message-emoji',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
tagType: 'warning',
|
tagType: 'warning',
|
||||||
description: '项目稳定推进中...',
|
description: '项目稳定推进中...',
|
||||||
@ -84,7 +84,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
type: 0,
|
type: 0,
|
||||||
title:
|
title:
|
||||||
'Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!',
|
'Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!Admin 已经添加菜单导航功能!',
|
||||||
icon: 'icon-park-outline:tips-one',
|
icon: 'icon-park-outline-tips-one',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
tagType: 'error',
|
tagType: 'error',
|
||||||
description:
|
description:
|
||||||
@ -95,7 +95,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 4,
|
id: 4,
|
||||||
type: 0,
|
type: 0,
|
||||||
title: 'Admin开始启动了!',
|
title: 'Admin开始启动了!',
|
||||||
icon: 'icon-park-outline:tips-one',
|
icon: 'icon-park-outline-tips-one',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
description: '项目稳定推进中...',
|
description: '项目稳定推进中...',
|
||||||
date: '2022-2-5 18:32',
|
date: '2022-2-5 18:32',
|
||||||
@ -104,7 +104,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 5,
|
id: 5,
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '相见恨晚??',
|
title: '相见恨晚??',
|
||||||
icon: 'icon-park-outline:comment',
|
icon: 'icon-park-outline-comment',
|
||||||
description: '项目稳定推进中,很快就能看到正式版了',
|
description: '项目稳定推进中,很快就能看到正式版了',
|
||||||
date: '2022-2-2 12:22',
|
date: '2022-2-2 12:22',
|
||||||
},
|
},
|
||||||
@ -112,7 +112,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 6,
|
id: 6,
|
||||||
type: 1,
|
type: 1,
|
||||||
title: '动态路由已完成!',
|
title: '动态路由已完成!',
|
||||||
icon: 'icon-park-outline:comment',
|
icon: 'icon-park-outline-comment',
|
||||||
description: '项目稳定推进中,很快就能看到正式版了',
|
description: '项目稳定推进中,很快就能看到正式版了',
|
||||||
date: '2022-2-25 12:22',
|
date: '2022-2-25 12:22',
|
||||||
},
|
},
|
||||||
@ -120,7 +120,7 @@ const MassageData = ref<Entity.Message[]>([
|
|||||||
id: 7,
|
id: 7,
|
||||||
type: 2,
|
type: 2,
|
||||||
title: '接下来需要完善一些',
|
title: '接下来需要完善一些',
|
||||||
icon: 'icon-park-outline:beach-umbrella',
|
icon: 'icon-park-outline-beach-umbrella',
|
||||||
tagTitle: '未开始',
|
tagTitle: '未开始',
|
||||||
description: '项目稳定推进中,很快就能看到正式版了',
|
description: '项目稳定推进中,很快就能看到正式版了',
|
||||||
date: '2022-2-2 12:22',
|
date: '2022-2-2 12:22',
|
||||||
|
|||||||
@ -16,6 +16,7 @@ export type {
|
|||||||
MenuQueryBo,
|
MenuQueryBo,
|
||||||
MenuRouterBo,
|
MenuRouterBo,
|
||||||
MenuVo,
|
MenuVo,
|
||||||
|
RoleMenuPermissionBo,
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
// 兼容性类型别名
|
// 兼容性类型别名
|
||||||
@ -120,8 +121,14 @@ export function getMenuIdsByRoleId(roleId: string) {
|
|||||||
* 保存角色和菜单权限之间的关系
|
* 保存角色和菜单权限之间的关系
|
||||||
*/
|
*/
|
||||||
export function saveRoleMenuPermission(roleId: string, menuIds: string[]) {
|
export function saveRoleMenuPermission(roleId: string, menuIds: string[]) {
|
||||||
const menuIdsStr = menuIds.length > 0 ? menuIds.join(',') : '-1'
|
// 空数组时传递 ["-1"] 表示取消所有权限
|
||||||
return request.Post<Service.ResponseResult<string>>(`/coder/sysMenu/saveRoleMenu/${roleId}/${menuIdsStr}`)
|
// 保持字符串格式避免精度丢失
|
||||||
|
const menuIdsStr = menuIds.length > 0 ? menuIds : ['-1']
|
||||||
|
|
||||||
|
return request.Post<Service.ResponseResult<string>>('/coder/sysMenu/saveRoleMenu', {
|
||||||
|
roleId,
|
||||||
|
menuIds: menuIdsStr,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 兼容性导出 - 保持原有函数名以确保向后兼容
|
// 兼容性导出 - 保持原有函数名以确保向后兼容
|
||||||
|
|||||||
@ -95,3 +95,9 @@ export interface MenuNormalResponse {
|
|||||||
menuList: MenuVo[]
|
menuList: MenuVo[]
|
||||||
spreadList: string[] // 改为字符串数组避免大整数精度丢失
|
spreadList: string[] // 改为字符串数组避免大整数精度丢失
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 角色菜单权限分配请求参数
|
||||||
|
export interface RoleMenuPermissionBo {
|
||||||
|
roleId: string // 字符串格式避免精度丢失
|
||||||
|
menuIds: string[] // 字符串格式避免精度丢失
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { local } from '@/utils'
|
import { local } from '@/utils'
|
||||||
import { coiMsgWarning } from '@/utils/coi'
|
import { coiMsgError } from '@/utils/coi'
|
||||||
import { createAlova } from 'alova'
|
import { createAlova } from 'alova'
|
||||||
import { createServerTokenAuthentication } from 'alova/client'
|
import { createServerTokenAuthentication } from 'alova/client'
|
||||||
import adapterFetch from 'alova/fetch'
|
import adapterFetch from 'alova/fetch'
|
||||||
@ -105,7 +105,7 @@ export function createAlovaInstance(
|
|||||||
userMessage = '文件大小超出限制,请选择较小的文件'
|
userMessage = '文件大小超出限制,请选择较小的文件'
|
||||||
}
|
}
|
||||||
|
|
||||||
coiMsgWarning(userMessage)
|
coiMsgError(userMessage)
|
||||||
},
|
},
|
||||||
|
|
||||||
onComplete: async (_method) => {
|
onComplete: async (_method) => {
|
||||||
|
|||||||
@ -110,7 +110,7 @@ const rules = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
const formValue = ref({
|
const formValue = ref({
|
||||||
account: 'admin',
|
account: 'yuadmin',
|
||||||
pwd: '000000',
|
pwd: '000000',
|
||||||
rePwd: '000000',
|
rePwd: '000000',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -82,13 +82,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:upload />
|
<icon-park-outline-upload />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
上传文件
|
上传文件
|
||||||
@ -125,7 +125,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
批量删除
|
批量删除
|
||||||
@ -136,7 +136,7 @@
|
|||||||
<span>共 {{ pagination.itemCount }} 条</span>
|
<span>共 {{ pagination.itemCount }} 条</span>
|
||||||
<NButton text @click="handleRefresh">
|
<NButton text @click="handleRefresh">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -250,7 +250,7 @@
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<NIcon size="48" class="text-blue-500">
|
<NIcon size="48" class="text-blue-500">
|
||||||
<icon-park-outline:upload />
|
<icon-park-outline-upload />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</div>
|
</div>
|
||||||
<NText class="text-base">
|
<NText class="text-base">
|
||||||
@ -313,6 +313,7 @@ import {
|
|||||||
import type { SysFileQueryBo, SysFileSearchForm, SysFileVo } from '@/service/api/system/file'
|
import type { SysFileQueryBo, SysFileSearchForm, SysFileVo } from '@/service/api/system/file'
|
||||||
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
|
||||||
import IconParkOutlineDownload from '~icons/icon-park-outline/download'
|
import IconParkOutlineDownload from '~icons/icon-park-outline/download'
|
||||||
|
import { FILE_SERVICE_DB_OPTIONS } from '@/service/api/system/file/types'
|
||||||
|
|
||||||
// 文件分类图标组件
|
// 文件分类图标组件
|
||||||
const StarIcon = () => h('span', { class: 'text-yellow-500' }, '✨')
|
const StarIcon = () => h('span', { class: 'text-yellow-500' }, '✨')
|
||||||
|
|||||||
@ -85,13 +85,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
删除
|
删除
|
||||||
@ -125,7 +125,7 @@
|
|||||||
<span>共 {{ pagination.itemCount }} 条</span>
|
<span>共 {{ pagination.itemCount }} 条</span>
|
||||||
<NButton text @click="getLoginLogList">
|
<NButton text @click="getLoginLogList">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -168,7 +168,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:refresh />
|
<icon-park-outline-refresh />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ getEmptyActionText() }}
|
{{ getEmptyActionText() }}
|
||||||
|
|||||||
@ -53,13 +53,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<NButton v-if="hasButton(PERMISSIONS.MENU.ADD)" type="primary" size="medium" class="px-3 flex items-center" @click="handleAdd">
|
<NButton v-if="hasButton(PERMISSIONS.MENU.ADD)" type="primary" size="medium" class="px-3 flex items-center" @click="handleAdd">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:plus />
|
<IconParkOutlinePlus />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
新增
|
新增
|
||||||
@ -92,7 +92,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
删除
|
删除
|
||||||
@ -101,8 +101,8 @@
|
|||||||
<NButton size="medium" class="px-3 flex items-center" @click="handleExpandToggle">
|
<NButton size="medium" class="px-3 flex items-center" @click="handleExpandToggle">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:expand-up v-if="isAllExpanded" />
|
<icon-park-outline-expand-up v-if="isAllExpanded" />
|
||||||
<icon-park-outline:expand-down v-else />
|
<icon-park-outline-expand-down v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ isAllExpanded ? '全部折叠' : '全部展开' }}
|
{{ isAllExpanded ? '全部折叠' : '全部展开' }}
|
||||||
@ -112,7 +112,7 @@
|
|||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<NButton type="tertiary" @click="handleRefresh">
|
<NButton type="tertiary" @click="handleRefresh">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -159,8 +159,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:refresh v-if="hasSearchConditions()" />
|
<icon-park-outline-refresh v-if="hasSearchConditions()" />
|
||||||
<icon-park-outline:plus v-else />
|
<IconParkOutlinePlus v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ getEmptyActionText() }}
|
{{ getEmptyActionText() }}
|
||||||
@ -213,7 +213,7 @@
|
|||||||
>
|
>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:down />
|
<icon-park-outline-down />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
</n-input>
|
</n-input>
|
||||||
@ -281,7 +281,7 @@
|
|||||||
({{ menu.children.length }})
|
({{ menu.children.length }})
|
||||||
</span>
|
</span>
|
||||||
<NIcon v-if="menu.children?.length" class="expand-icon">
|
<NIcon v-if="menu.children?.length" class="expand-icon">
|
||||||
<icon-park-outline:right />
|
<icon-park-outline-right />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -85,13 +85,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
删除
|
删除
|
||||||
@ -128,7 +128,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
清空
|
清空
|
||||||
@ -139,7 +139,7 @@
|
|||||||
<span>共 {{ pagination.itemCount }} 条</span>
|
<span>共 {{ pagination.itemCount }} 条</span>
|
||||||
<NButton text @click="getOperLogList">
|
<NButton text @click="getOperLogList">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -182,7 +182,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:refresh />
|
<icon-park-outline-refresh />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ getEmptyActionText() }}
|
{{ getEmptyActionText() }}
|
||||||
|
|||||||
@ -82,13 +82,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:upload />
|
<icon-park-outline-upload />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
上传图片
|
上传图片
|
||||||
@ -125,7 +125,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
批量删除
|
批量删除
|
||||||
@ -138,8 +138,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:switch v-if="viewMode === 'table'" />
|
<icon-park-outline-switch v-if="viewMode === 'table'" />
|
||||||
<icon-park-outline:list v-else />
|
<icon-park-outline-list v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ viewMode === 'table' ? '图库视图' : '表格视图' }}
|
{{ viewMode === 'table' ? '图库视图' : '表格视图' }}
|
||||||
@ -150,7 +150,7 @@
|
|||||||
<span>共 {{ pagination.itemCount }} 条</span>
|
<span>共 {{ pagination.itemCount }} 条</span>
|
||||||
<NButton text @click="handleRefresh">
|
<NButton text @click="handleRefresh">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -219,7 +219,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon size="12">
|
<NIcon size="12">
|
||||||
<icon-park-outline:download />
|
<IconParkOutlineDownload />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -233,7 +233,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon size="12">
|
<NIcon size="12">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -280,7 +280,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:plus />
|
<icon-park-outline-plus />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
上传图片
|
上传图片
|
||||||
@ -376,7 +376,7 @@
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<NIcon size="48" class="text-blue-500">
|
<NIcon size="48" class="text-blue-500">
|
||||||
<icon-park-outline:camera />
|
<icon-park-outline-camera />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</div>
|
</div>
|
||||||
<NText class="text-base">
|
<NText class="text-base">
|
||||||
|
|||||||
@ -74,13 +74,13 @@
|
|||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton type="primary" @click="handleSearch">
|
<NButton type="primary" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:search /></NIcon>
|
<NIcon><icon-park-outline-search /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
搜索
|
搜索
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton @click="handleReset">
|
<NButton @click="handleReset">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
重置
|
重置
|
||||||
</NButton>
|
</NButton>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<NButton v-button="PERMISSIONS.ROLE.ADD" type="primary" class="px-3 flex items-center" @click="handleAdd">
|
<NButton v-button="PERMISSIONS.ROLE.ADD" type="primary" class="px-3 flex items-center" @click="handleAdd">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:plus />
|
<icon-park-outline-plus />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
新增
|
新增
|
||||||
@ -112,7 +112,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:edit />
|
<icon-park-outline-edit />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
修改
|
修改
|
||||||
@ -127,7 +127,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:delete />
|
<IconParkOutlineDelete />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
删除
|
删除
|
||||||
@ -142,7 +142,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
<NIcon class="mr-1" style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:key />
|
<IconParkOutlineKey />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
分配权限
|
分配权限
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<span>共 {{ pagination.itemCount }} 条</span>
|
<span>共 {{ pagination.itemCount }} 条</span>
|
||||||
<NButton text @click="getRoleList">
|
<NButton text @click="getRoleList">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:refresh /></NIcon>
|
<NIcon><icon-park-outline-refresh /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@ -196,8 +196,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:refresh v-if="hasSearchConditions()" />
|
<icon-park-outline-refresh v-if="hasSearchConditions()" />
|
||||||
<icon-park-outline:plus v-else />
|
<icon-park-outline-plus v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ getEmptyActionText() }}
|
{{ getEmptyActionText() }}
|
||||||
@ -338,8 +338,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon style="transform: translateY(-1px)">
|
<NIcon style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:minus v-if="allExpanded" />
|
<icon-park-outline-minus v-if="allExpanded" />
|
||||||
<icon-park-outline:plus v-else />
|
<icon-park-outline-plus v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ allExpanded ? '折叠' : '展开' }}
|
{{ allExpanded ? '折叠' : '展开' }}
|
||||||
@ -352,8 +352,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon style="transform: translateY(-1px)">
|
<NIcon style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:close v-if="allSelected" />
|
<icon-park-outline-close v-if="allSelected" />
|
||||||
<icon-park-outline:check v-else />
|
<icon-park-outline-check v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ allSelected ? '全不选' : '全选' }}
|
{{ allSelected ? '全不选' : '全选' }}
|
||||||
@ -366,7 +366,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon style="transform: translateY(-1px)">
|
<NIcon style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:link />
|
<icon-park-outline-link />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
父子联动
|
父子联动
|
||||||
@ -379,7 +379,7 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon style="transform: translateY(-1px)">
|
<NIcon style="transform: translateY(-1px)">
|
||||||
<icon-park-outline:battery-charge />
|
<icon-park-outline-battery-charge />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
权限标识
|
权限标识
|
||||||
@ -403,7 +403,7 @@
|
|||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-2">
|
<div class="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-2">
|
||||||
<NIcon size="16" class="text-gray-400">
|
<NIcon size="16" class="text-gray-400">
|
||||||
<icon-park-outline:folder-close />
|
<icon-park-outline-folder-close />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500">
|
||||||
@ -816,8 +816,9 @@ async function handleReset() {
|
|||||||
|
|
||||||
// 行选择变化
|
// 行选择变化
|
||||||
function handleRowSelectionChange(rowKeys: (string | number)[]) {
|
function handleRowSelectionChange(rowKeys: (string | number)[]) {
|
||||||
const numericKeys = rowKeys.map(key => typeof key === 'string' ? Number.parseInt(key) : key)
|
// 保持字符串格式避免精度丢失
|
||||||
selectedRows.value = tableData.value.filter(row => numericKeys.includes(row.roleId))
|
const stringKeys = rowKeys.map(key => String(key))
|
||||||
|
selectedRows.value = tableData.value.filter(row => stringKeys.includes(String(row.roleId)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量修改(选中一个角色进行修改)
|
// 批量修改(选中一个角色进行修改)
|
||||||
@ -1078,9 +1079,8 @@ async function handleConfirmAssignMenu() {
|
|||||||
// 确保选中子菜单时父菜单也被包含
|
// 确保选中子菜单时父菜单也被包含
|
||||||
const completeMenuIds = ensureParentMenusIncluded(checkedKeys.value, menuData.value)
|
const completeMenuIds = ensureParentMenusIncluded(checkedKeys.value, menuData.value)
|
||||||
|
|
||||||
// 将字符串格式的key转换为数字格式发送给后端
|
// 保持字符串格式避免精度丢失
|
||||||
const menuIds = completeMenuIds.map(key => Number.parseInt(String(key)))
|
const response = await saveRoleMenuPermission(String(currentAssignRole.value.roleId), completeMenuIds)
|
||||||
const response = await saveRoleMenuPermission(currentAssignRole.value.roleId, menuIds)
|
|
||||||
|
|
||||||
if (response.isSuccess) {
|
if (response.isSuccess) {
|
||||||
coiMsgSuccess('菜单权限分配成功')
|
coiMsgSuccess('菜单权限分配成功')
|
||||||
|
|||||||
@ -240,8 +240,8 @@
|
|||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon>
|
<NIcon>
|
||||||
<icon-park-outline:refresh v-if="hasSearchConditions()" />
|
<IconParkOutlineRefresh v-if="hasSearchConditions()" />
|
||||||
<icon-park-outline:plus v-else />
|
<icon-park-outline-plus v-else />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
</template>
|
</template>
|
||||||
{{ getEmptyActionText() }}
|
{{ getEmptyActionText() }}
|
||||||
@ -625,7 +625,7 @@
|
|||||||
<NUploadDragger>
|
<NUploadDragger>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<NIcon size="48" :depth="3" class="mb-2">
|
<NIcon size="48" :depth="3" class="mb-2">
|
||||||
<icon-park-outline:file-excel />
|
<icon-park-outline-file-excel />
|
||||||
</NIcon>
|
</NIcon>
|
||||||
<div class="text-lg font-medium mb-1">
|
<div class="text-lg font-medium mb-1">
|
||||||
点击或拖拽上传Excel文件
|
点击或拖拽上传Excel文件
|
||||||
@ -690,7 +690,7 @@
|
|||||||
@click="handleDownloadTemplate"
|
@click="handleDownloadTemplate"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<NIcon><icon-park-outline:download /></NIcon>
|
<NIcon><IconParkOutlineDownload /></NIcon>
|
||||||
</template>
|
</template>
|
||||||
下载模板
|
下载模板
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user