更新规则和uipro
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
This commit is contained in:
@@ -84,8 +84,8 @@ alwaysApply: true
|
||||
|
||||
```ts
|
||||
export const STATUS_OPTIONS = [
|
||||
{ label: '启用', value: 1 },
|
||||
{ label: '禁用', value: 0 },
|
||||
{ label: '启用', value: 0 },
|
||||
{ label: '禁用', value: 1 },
|
||||
];
|
||||
```
|
||||
|
||||
|
||||
231
.cursor/rules/Vben-Components.mdc
Normal file
231
.cursor/rules/Vben-Components.mdc
Normal file
@@ -0,0 +1,231 @@
|
||||
---
|
||||
description: nl-admin-view Vben 官方组件用法规范(Page/Form/Modal/Drawer/VxeTable 等)
|
||||
globs: apps/web-antd/**/*.{vue,ts}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Vben 组件规则(对齐官方文档 + 本仓库约定)
|
||||
|
||||
文档来源:https://doc.vben.pro/components/
|
||||
业务页统一在 `apps/web-antd`;表单/表格必须走本仓库适配器,不要直接依赖底层实现细节。
|
||||
|
||||
## 选型速查
|
||||
|
||||
| 场景 | 用什么 | 不要用 |
|
||||
|---|---|---|
|
||||
| 页面外壳 | `Page`(`@vben/common-ui`) | 自写页面头/底容器 |
|
||||
| 列表+搜索 | `useVbenVxeGrid`(`#/adapter/vxe-table`) | 直接 `new VxeGrid` / antd `Table` |
|
||||
| 表单 | `useVbenForm`(`#/adapter/form`) | antd `Form` / 手写校验 |
|
||||
| 复杂弹窗(表单/多步) | `useVbenModal` | antd `Modal` |
|
||||
| 侧滑面板 | `useVbenDrawer` | antd `Drawer` |
|
||||
| 轻量确认/提示/单输入 | `alert` / `confirm` / `prompt` | 为简单确认再开 Modal |
|
||||
| 表格行/工具栏按钮 | `#/components/table-action` 的 `TableAction` | 散落一排 `Button` |
|
||||
| 远程下拉/树选 | 适配器里的 `ApiSelect` / `ApiTreeSelect`(底层 `ApiComponent`) | 页面里手写 options 拉取逻辑 |
|
||||
| 超长文本 | `EllipsisText` | CSS 省略后无 Tooltip |
|
||||
| 只读详情字段组 | `VbenDescriptions` | 手写 label-value 网格 |
|
||||
| 头像/固定比例裁剪 | `VCropper` | 无裁剪直接上传原图(需要裁剪时) |
|
||||
| 富文本 | `VbenTiptap`(`@vben/plugins/tiptap`) | 再引一套编辑器 |
|
||||
|
||||
---
|
||||
|
||||
## Page
|
||||
|
||||
- 业务页根节点用 `<Page>`;列表页常见:`<Page auto-content-height title="xxx">`
|
||||
- `title` / `description` / `#extra` 都没有内容时,头部不渲染
|
||||
- `autoContentHeight`:内容区按可视高度自动扣减头/底;额外偏移用 `heightOffset`(px)
|
||||
- `appendToMain` 的 Modal/Drawer 挂到内容区时,**Page 必须开 `auto-content-height`**,否则高度计算不对
|
||||
- 插槽:`default` / `title` / `description` / `extra` / `footer`
|
||||
|
||||
---
|
||||
|
||||
## Modal(`useVbenModal`)
|
||||
|
||||
```ts
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
connectedComponent: ExtraModal, // 复杂内容抽离子组件
|
||||
draggable: true,
|
||||
// overflow: true, // 需要拖出可视区时再开
|
||||
});
|
||||
```
|
||||
|
||||
强制约定:
|
||||
|
||||
- 复杂弹窗用 `connectedComponent`;内外共享 `modalApi`
|
||||
- **严禁覆盖 `#footer`**(会丢掉默认取消/确定与 loading)
|
||||
- 扩展底部只用:`prepend-footer` / `center-footer` / `append-footer`
|
||||
- 提交防重复:`modalApi.lock()` / `unlock()`(或 `setState({ confirmLoading: true })`)
|
||||
- 回填:`modalApi.setData(data).open()`;内部 `onOpenChange` 里 `modalApi.getData()`
|
||||
- 参数优先级:`slot` > `props` > `state`;`connectedComponent` 时同名事件**以内侧为准**(`onOpenChange` 内外都会触发)
|
||||
- 默认属性可在 `apps/web-antd/src/bootstrap.ts` 的 `setDefaultModalProps` 统一改
|
||||
- 动画:`animationType: 'slide' | 'scale'`(默认 slide)
|
||||
|
||||
常用 API:`open` / `close` / `setState` / `setData` / `getData` / `lock` / `unlock`
|
||||
|
||||
---
|
||||
|
||||
## Drawer(`useVbenDrawer`)
|
||||
|
||||
- API 形态与 Modal 基本一致:`connectedComponent`、`setData/getData`、`lock/unlock`、footer 三插槽
|
||||
- **同样严禁覆盖 `#footer`**
|
||||
- `placement`: `left | right | top | bottom`(默认 `right`)
|
||||
- 关闭前校验用 `onBeforeClose`(支持 Promise);需要重置内部状态可开 `destroyOnClose`
|
||||
- 挂内容区同样要配合 Page 的 `auto-content-height`
|
||||
- 默认属性:`setDefaultDrawerProps`
|
||||
|
||||
---
|
||||
|
||||
## Alert(轻量提示)
|
||||
|
||||
来自 `@vben/common-ui`:`alert` / `confirm` / `prompt` / `useAlertContext`
|
||||
|
||||
- **简单确认、提示、单字段输入**用这套;复杂表单/多控件仍用 Modal
|
||||
- `confirm().then/catch`;异步关闭用 `beforeClose`,返回 `false` 可阻止关闭
|
||||
- `prompt` 可传 `component` + `componentProps`(antd Select 需 `popupClassName: 'pointer-events-auto'`)
|
||||
- 自定义内容里需要主动确认/取消:`useAlertContext().doConfirm/doCancel`(仅 setup/函数组件)
|
||||
- 动态创建的 Alert **不支持 HMR**,改代码后需关掉重开
|
||||
|
||||
---
|
||||
|
||||
## Form(`useVbenForm` from `#/adapter/form`)
|
||||
|
||||
```ts
|
||||
const [Form, formApi] = useVbenForm({
|
||||
schema: [
|
||||
{
|
||||
fieldName: 'nick_name', // 与后端 snake_case 对齐
|
||||
label: '昵称',
|
||||
component: 'Input',
|
||||
rules: 'required', // 选择类用 selectRequired
|
||||
componentProps: { placeholder: '请输入' },
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
强制约定:
|
||||
|
||||
- 只从 `#/adapter/form` 引入,不直接玩 TanStack Form 实例
|
||||
- 动态改字段:`formApi.updateSchema([...])`;**没有** `setComponentProps`
|
||||
- 重置:`formApi.resetForm()`;**禁止** `resetFields()`(antd API,会报错)
|
||||
- 取值/赋值:`getValues()` / `setValues()`;需要提交编解码时用 `codec` / `getRawValues()`
|
||||
- 校验:`formApi.validate().then(e => { if (e.valid) ... })` 或 `validateAndSubmitForm()`
|
||||
- 字段自定义 slot:控件绑定用 `v-bind="slotProps.componentProps"`(不要再 `v-bind="slotProps"`)
|
||||
- 联动优先 `dependencies.resolve(context)` 一次返回 `show/disabled/rules/componentProps...`
|
||||
- 远程 options:打开时拉取后 `updateSchema` 注入;或用 `ApiSelect`/`ApiTreeSelect`
|
||||
- 密码字段用 `InputPassword`(适配器组件名),不要 `Input` + `type="password"`
|
||||
|
||||
---
|
||||
|
||||
## Vxe Table(`useVbenVxeGrid` from `#/adapter/vxe-table`)
|
||||
|
||||
```ts
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions, // 搜索表单(Vben Form)
|
||||
gridOptions: {
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
// 返回适配器约定结构
|
||||
return { items: [], total: 0 };
|
||||
},
|
||||
},
|
||||
},
|
||||
toolbarConfig: { search: true },
|
||||
},
|
||||
gridEvents,
|
||||
});
|
||||
```
|
||||
|
||||
强制约定:
|
||||
|
||||
- 远程列表走 `proxyConfig.ajax.query`,禁止自己 fetch 再赋 `data`
|
||||
- 响应结构对齐适配器:`{ items, total }`(见 `apps/web-antd/src/adapter/vxe-table.ts`)
|
||||
- 分页从 `{ page }` 取 `currentPage` / `pageSize`
|
||||
- 刷新:`gridApi.query()` 保留页;`gridApi.reload()` 回第一页
|
||||
- loading:`gridApi.setLoading(bool)`
|
||||
- 工具栏插槽:`toolbar-actions`(左)/ `toolbar-tools`(右)
|
||||
- 操作列:列上 `slots: { default: 'action' }`,页面 `<template #action="{ row }">`,**禁止**列 render 写 JSX
|
||||
- 需要原生能力时用 `gridApi.grid`(如树展开 `setAllTreeExpand`)
|
||||
|
||||
---
|
||||
|
||||
## ApiComponent / ApiSelect
|
||||
|
||||
- 一般不直接用 `ApiComponent`;优先用适配器包装好的 `ApiSelect` / `ApiTreeSelect`
|
||||
- 关键映射:`api` / `params` / `resultField` / `labelField` / `valueField` / `childrenField`
|
||||
- `immediate: false` + `visibleEvent`:展开时再请求
|
||||
- 同页多实例同数据源:用 TanStack Query/`useQuery` 包一层再传 `api`,避免 N 次请求
|
||||
- `autoSelect`: `'first' | 'last' | 'one' | fn | false`(不要用在多选)
|
||||
|
||||
---
|
||||
|
||||
## TableAction(本仓库)
|
||||
|
||||
本仓库列表页已统一用本地封装:
|
||||
|
||||
```ts
|
||||
import { TableAction } from '#/components/table-action';
|
||||
```
|
||||
|
||||
- 字段习惯:`label`(不是官方 demo 的 `text`)、`drop-down-actions`、`popConfirm`、`auth`、`ifShow`
|
||||
- 放在 `#toolbar-actions` 与 `#action` 插槽中
|
||||
- 若改用官方 `VbenTableAction`(`@vben/common-ui` / `#/adapter/vxe-table`),注意其字段为 `text` / `dropdownActions`,并优先走适配器以自动注入权限
|
||||
|
||||
---
|
||||
|
||||
## EllipsisText
|
||||
|
||||
```vue
|
||||
<EllipsisText :max-width="240" :line="2" :tooltip-when-ellipsis="true">
|
||||
{{ text }}
|
||||
</EllipsisText>
|
||||
```
|
||||
|
||||
- 表格/卡片超长文案优先用它;需要展开收起开 `expand`
|
||||
- `tooltipWhenEllipsis`:仅截断时显示提示,避免短文本也弹层
|
||||
|
||||
---
|
||||
|
||||
## VbenDescriptions
|
||||
|
||||
- 详情/预览优先 `:items="[{ label, content, span }]"` 数据驱动
|
||||
- `span: 'filled'` 占满当前行剩余;`column` 可传断点对象
|
||||
- `bordered` + `title` + `#extra` 做带操作的信息块
|
||||
- `layout="vertical"` 标签在上;也可用 `VbenDescriptionsItem` 子组件(`items` 优先)
|
||||
|
||||
---
|
||||
|
||||
## VCropper
|
||||
|
||||
```ts
|
||||
const blob = await cropperRef.value?.getCropImage('image/jpeg', 0.9, 'blob');
|
||||
```
|
||||
|
||||
- Props:`img`(必填)、`width`/`height`、`aspectRatio`(如 `'1:1'` `'16:9'`)
|
||||
- blob URL 用完/`onBeforeUnmount` 要 `URL.revokeObjectURL`,防泄漏
|
||||
- 网络图导出需 CORS;头像场景常用固定比例 + 指定 `targetWidth/targetHeight`
|
||||
|
||||
---
|
||||
|
||||
## VbenTiptap(`@vben/plugins/tiptap`)
|
||||
|
||||
```vue
|
||||
<VbenTiptap v-model="html" :image-upload="imageUpload" />
|
||||
<VbenTiptapPreview :content="html" />
|
||||
```
|
||||
|
||||
- 内容为 HTML 字符串;只读展示用 `VbenTiptapPreview`
|
||||
- 上传必须配 `imageUpload.upload(file, onProgress) => Promise<url>`,走本项目上传接口
|
||||
- 上传中不要拿 `getHTML()` 去保存(可能是临时 blob URL)
|
||||
- 自定义 `extensions` 会覆盖默认扩展,且图片上传能力不可用——非必要不要自定义
|
||||
|
||||
---
|
||||
|
||||
## 与本仓库踩坑清单(必守)
|
||||
|
||||
1. Form 无 `setComponentProps` / 无 `resetFields`
|
||||
2. Modal/Drawer 禁止覆盖 `#footer`;提交用 `lock/unlock`
|
||||
3. 表格返回必须是 `{ items, total }`;刷新分清 `query` vs `reload`
|
||||
4. 字段名 `fieldName` 用后端 snake_case(如 `created_at`、`nick_name`)
|
||||
5. 状态枚举与后端一致:**0 正常 / 1 禁用**
|
||||
6. 暗色主题:业务样式用 CSS 变量,禁止写死亮色色值(见 `Code-Standards.mdc`)
|
||||
@@ -89,7 +89,7 @@
|
||||
"node": ">=20.10.0",
|
||||
"pnpm": ">=9.12.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.10.0",
|
||||
"packageManager": "pnpm@10.2.0",
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"allowedVersions": {
|
||||
|
||||
21782
pnpm-lock.yaml
generated
21782
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user