Appearance
JPwise-Web 组件库文档 - Claude Code
🔥 必须使用的核心组件
JNPF-table 数据表格
强制使用,替代 el-table
vue
<JNPF-table
:data="tableData"
v-loading="listLoading"
:hasC="true"
@selection-change="handleSelectionChange"
:listQuery="listQuery">
<el-table-column prop="NAME" label="名称" min-width="150" />
<el-table-column prop="STATUS" label="状态" :formatter="formatter" />
</JNPF-table>
核心参数:hasC
(复选框) | listQuery
(分页) | @selection-change
(选择事件)
topOpts + tableOpts 操作按钮
vue
<!-- 顶部操作 -->
<topOpts @add="addOrUpdateHandle()" @delete="handleDelete" :buttonAuthList="buttonAuthList" />
<!-- 行内操作 -->
<template slot-scope="scope">
<tableOpts @edit="addOrUpdateHandle(scope.row.id)" @delete="handleDelete(scope.row.id)" />
</template>
Pagination 分页
vue
<Pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" @pagination="initData" />
🛠️ JPW 业务组件
基础输入组件
vue
<!-- 输入框 -->
<JPWInput v-model="dataForm.name" placeholder="请输入" :maxlength="50" />
<!-- 下拉选择 -->
<JPWSelect v-model="dataForm.type" :options="typeOptions" placeholder="请选择" />
<!-- 级联选择 -->
<JPWCascader v-model="dataForm.category" :options="cascaderOptions" />
选项格式:[{ enCode: "1", fullName: "选项名" }]
选择器组件
vue
<!-- 用户选择 -->
<UserSelect v-model="dataForm.userId" placeholder="选择用户" />
<!-- 部门选择 -->
<DepSelect v-model="dataForm.deptId" placeholder="选择部门" />
<!-- 树形选择 -->
<JNPFTreeSelect v-model="dataForm.treeValue" :options="treeOptions" />
上传组件
vue
<!-- 文件上传 -->
<uploadBtn v-model="dataForm.fileList" :fileSize="10" :limit="5" />
<!-- 图片上传 -->
<JNPFUploadImg v-model="dataForm.imageUrl" :limit="3" />
富功能组件
vue
<!-- 富文本编辑器 -->
<JPWCKEditor v-model="dataForm.content" :height="400" />
<!-- 电子签名 -->
<JPWSignature v-model="dataForm.signature" :width="400" :height="200" />
<!-- 地图组件 -->
<JPWMap v-model="dataForm.location" :zoom="13" />
🌲 树形和布局组件
树形组件
vue
<!-- 普通树 -->
<JPWTree :data="treeData" @node-click="handleNodeClick" />
<!-- 表格树 -->
<JPWTableTree :data="tableTreeData" :tree-props="{children: 'children'}" />
布局组件
vue
<!-- 卡片容器 -->
<JPWCard title="基本信息" :collapsible="true">
<!-- 内容 -->
</JPWCard>
<!-- 标签页 -->
<JPWTabs v-model="activeTab">
<el-tab-pane label="基本信息" name="basic">内容</el-tab-pane>
</JPWTabs>
🔄 流程组件
FlowBox 流程表单
javascript
// 在 openWindow 中使用
openWindow({
url: "views/workFlow/components/FlowBox",
data: { flowId: "流程ID", id: "数据ID", opType: "1" }
});
📦 容器组件
ComponentContainer 自定义组件容器
配合 CCMixin 使用,管理弹窗组件
vue
<template>
<div>
<!-- 触发按钮 -->
<el-button @click="openCustomWindow">打开组件</el-button>
<!-- ComponentContainer容器 -->
<ComponentContainer
v-if="ccVisible"
:popupType="popupType"
:popupTitle="popupTitle_"
:popupWidth="popupWidth_"
:popupHeight="popupHeight_"
:showHeader="showHeader_"
:showFooter="showFooter_"
:componentUrl="componentUrl"
:componentType="componentType"
@cc_close="close"
ref="ComponentContainer"
v-loading.fullscreen.lock="layoutLoading"
>
<template #main>
<component
v-initComponent="{ data: componentData }"
:is="componentName"
:data="componentData"
:config="componentData"
:modelId="modelIdCC"
:isPreview="isPreviewCC"
ref="componentRef"
></component>
</template>
</ComponentContainer>
</div>
</template>
<script>
import CCMixin from '@/mixins/basics/customComponents'
export default {
mixins: [CCMixin],
methods: {
// 打开自定义组件窗口
openCustomWindow() {
this.openWindow({
url: 'views/module/Form', // 组件路径
title: '编辑数据', // 窗口标题
width: '80%', // 窗口宽度
height: '90%', // 窗口高度
popupType: 'general', // 弹窗类型
refresh: true, // 关闭后刷新
data: { // 传递给组件的数据
id: 'xxx',
mode: 'edit'
}
})
}
}
}
</script>
核心属性:
popupType
: 弹窗类型general
(普通) |fullScreen
(全屏) |drawer
(抽屉)componentUrl
: 组件路径,相对于src/
目录componentType
: 组件类型,自动从URL推断或手动指定v-initComponent
: 自定义指令,用于组件初始化
openWindow 参数:
javascript
this.openWindow({
// 必需参数
url: 'views/module/Form', // 组件路径
// 弹窗配置
title: '窗口标题', // 弹窗标题
width: '80%', // 弹窗宽度
height: '90%', // 弹窗高度
popupType: 'general', // general/fullScreen/drawer
// 显示控制
showHeader: true, // 显示头部
showFooter: false, // 显示底部
// 数据和行为
refresh: false, // 关闭后刷新
data: { id: 'xxx' }, // 传递数据
onDestroy: { 'event': callback } // 销毁回调
})
⚡ 使用规范
📦 组件引用优先判断规则
⚠️ 强制要求:引用任何公共组件前必须执行以下检查流程
🔍 第一步:检查组件是否全局注册
必须先检查 src/components/index.js
确认组件是否已全局注册
javascript
// 🔍 检查方法1:查看 src/components/index.js 文件
// 同步加载组件(已全局注册,直接使用)
JNPFTable, // ✅ 已注册,使用 <JNPF-table>
Pagination, // ✅ 已注册,使用 <Pagination>
topOperation, // ✅ 已注册,使用 <topOpts>
tableOperation, // ✅ 已注册,使用 <tableOpts>
// 异步加载组件(已全局注册,直接使用)
UploadImg: () => import("@/components/JNPF-UploadImg"), // ✅ 已注册
JNPFUploadFile: () => import("@/components/JNPF-uploadFile"), // ✅ 已注册
ExportBox: () => import("@/components/JNPF-ExportBox"), // ✅ 已注册
// 🔍 检查方法2:开发环境控制台验证
console.log('全局组件列表:', Object.keys(Vue.options.components))
console.log('组件是否存在:', 'JNPF-table' in Vue.options.components)
⚡ 第二步:全局组件直接使用(无需import)
javascript
// ✅ 已全局注册的组件 - 直接在模板中使用
<JNPF-table /> // 表格组件
<UploadImg /> // 图片上传(别名)
<JNPF-UploadImg /> // 图片上传(全名)
<uploadBtn /> // 文件上传
<Pagination /> // 分页组件
<topOpts /> // 顶部操作
<tableOpts /> // 表格操作
<ExportBox /> // 导出弹窗
<ComponentContainer /> // 组件容器
<JNPFTreeSelect /> // 树形选择
📍 第三步:检查未全局注册组件的正确路径
如果组件未全局注册,必须验证组件文件路径是否正确
javascript
// 🔍 强制检查:组件路径验证流程
// 1. 检查组件文件是否存在
// 2. 确认组件导出方式
// 3. 验证组件名称拼写
// ✅ 正确的路径检查示例
ls src/components/JNPF-userSelect/ // 检查目录是否存在
ls src/components/JNPF-userSelect/index.vue // 检查文件是否存在
// ✅ 常用未全局注册组件的正确路径
import UserSelect from "@/components/JNPF-userSelect" // ✅ 正确
import DepSelect from "@/components/JNPF-depSelect" // ✅ 正确
import JPWSignature from "@/components/JPW-Signature" // ✅ 正确
import JNPFDialog from "@/components/JNPF-dialog" // ✅ 正确
// ❌ 常见错误路径
import UserSelect from "@/components/UserSelect" // ❌ 路径错误
import DepSelect from "@/components/JNPF-DepSelect" // ❌ 大小写错误
import JPWSignature from "@/components/JPWSignature" // ❌ 缺少连字符
🚫 第四步:避免重复引用
javascript
// ❌ 禁止:重复引用已全局注册的组件
import JNPFUploadImg from "@/components/JNPF-UploadImg" // ❌ 已全局注册!
import Pagination from "@/components/Pagination" // ❌ 已全局注册!
import JNPFTable from "@/components/JNPF-table" // ❌ 已全局注册!
// ✅ 正确:直接使用全局组件
<JNPF-UploadImg /> // 直接使用
<UploadImg /> // 或使用别名
<Pagination /> // 直接使用
<JNPF-table /> // 直接使用
🔧 新建组件规范
📋 新建组件前置检查
创建新组件前必须执行以下检查
bash
# 🔍 检查1:确认组件不存在
find src/components -name "*ComponentName*" -type f
grep -r "ComponentName" src/components/
# 🔍 检查2:确认全局注册中没有同名组件
grep -r "ComponentName" src/components/index.js
# 🔍 检查3:检查是否已有类似功能组件
grep -r "similar-function" src/components/
创建公共组件时的全局注册要求
javascript
// 🔍 第一步:验证组件创建完成且路径正确
// ls src/components/JNPF-NewComponent/index.vue # 确认文件存在
// 确认组件有正确的 export default
// 🔍 第二步:在 src/components/index.js 中注册
// 根据组件使用频率选择同步或异步加载
// 方式1:同步加载(核心组件,必须立即可用)
import JNPFNewComponent from './JNPF-NewComponent'
const syncComponents = {
JNPFNewComponent, // 同步注册
// ... 其他同步组件
}
// 方式2:异步加载(按需加载,推荐)
const asyncComponents = {
// ... 其他异步组件
JNPFNewComponent: () =>
import(/* webpackChunkName: "new-component" */ './JNPF-NewComponent'),
}
// 🔍 第三步:考虑别名注册(简化使用)
Vue.component('JNPF-NewComponent', JNPFNewComponent) // 全名
Vue.component('NewComponent', JNPFNewComponent) // 简化别名
// 注意:别名要避免与现有组件冲突
// 🔍 第四步:更新组件列表文档
// 在本文档中添加新组件的使用说明
📁 组件文件命名和目录规范
bash
# ✅ 正确的组件目录结构
src/components/
├── JNPF-ComponentName/ # 通用组件目录
│ ├── index.vue # 主组件文件
│ ├── components/ # 子组件目录(可选)
│ └── README.md # 组件说明(可选)
│
├── JPW-ComponentName/ # 业务组件目录
│ ├── index.vue # 主组件文件
│ ├── components/ # 子组件目录(可选)
│ └── README.md # 组件说明(可选)
│
└── Generator/ # 生成器组件目录
└── components/
└── ComponentName/
└── index.vue
# 📝 命名规则验证
echo "JNPF-userSelect" | grep -E "^JNPF-[a-z][a-zA-Z]*$" # ✅ 通用组件
echo "JPW-Signature" | grep -E "^JPW-[A-Z][a-zA-Z]*$" # ✅ 业务组件
# ❌ 错误的命名示例
# JNPF_userSelect - 使用下划线
# jnpf-userSelect - 首字母小写
# JPWSignature - 缺少连字符
# User-Select - 不符合前缀规范
强制要求
- 列表页面:必须用
JNPF-table
不能用el-table
- 数据选择:必须用对应选择器组件
- 文件上传:必须用
uploadBtn
或JNPF-UploadImg
(已全局注册) - 自定义弹窗:必须用
ComponentContainer
+CCMixin
样式定制
scss
// 正确方式:深度选择器
.my-component {
::v-deep .jnpf-table {
.el-table__header { background: #f5f7fa; }
}
}
🎯 组件使用最佳实践
🔍 强制组件检查流程
每次引用组件前必须执行以下检查
javascript
// 📋 检查清单1:全局注册验证
console.log('全局组件:', Object.keys(Vue.options.components))
console.log('JNPF-table存在:', 'JNPF-table' in Vue.options.components)
// 📋 检查清单2:组件文件存在性验证(未全局注册时)
// 在终端运行以下命令验证路径
// ls src/components/JNPF-userSelect/index.vue
// ls src/components/JPW-Signature/index.vue
// 📋 检查清单3:组件导出验证
// 查看组件文件最后的 export default
const componentPath = '@/components/JNPF-userSelect'
console.log('组件路径检查:', componentPath)
// 📋 检查清单4:避免路径拼写错误
// ✅ 正确命名模式
// JNPF-* : 通用组件,如 JNPF-userSelect
// JPW-* : 业务组件,如 JPW-Signature
// Generator/ : 生成器组件目录
⚠️ 组件引用错误预防
javascript
// 🛡️ 防错措施1:使用IDE的路径提示
// 输入 import 时依赖IDE自动补全,避免手写路径
// 🛡️ 防错措施2:统一的组件检查函数
function checkComponent(componentName, componentPath) {
// 检查是否全局注册
if (componentName in Vue.options.components) {
console.warn(`⚠️ ${componentName} 已全局注册,无需import`)
return false
}
// 检查路径格式
if (!componentPath.startsWith('@/components/')) {
console.error(`❌ ${componentPath} 路径格式错误`)
return false
}
return true
}
// 使用示例
if (checkComponent('JNPF-table', '@/components/JNPF-table')) {
import JNPFTable from '@/components/JNPF-table'
}
📖 标准组件引用示例
严格按照检查流程执行的正确示例
vue
<script>
// 🔍 第一步:已检查 src/components/index.js 确认以下组件状态
// ✅ JNPF-table - 已全局注册(同步)
// ✅ UploadImg - 已全局注册(异步,别名)
// ✅ Pagination - 已全局注册(同步)
// ❌ UserSelect - 未全局注册,需要import
// ❌ DepSelect - 未全局注册,需要import
// ❌ JPWSignature - 未全局注册,需要import
// 🔍 第二步:验证组件路径正确性
// ls src/components/JNPF-userSelect/index.vue ✅ 存在
// ls src/components/JNPF-depSelect/index.vue ✅ 存在
// ls src/components/JPW-Signature/index.vue ✅ 存在
// 🔍 第三步:只引用未全局注册且路径正确的组件
import UserSelect from "@/components/JNPF-userSelect" // ✅ 路径正确
import DepSelect from "@/components/JNPF-depSelect" // ✅ 路径正确
import JPWSignature from "@/components/JPW-Signature" // ✅ 路径正确
// ❌ 以下组件禁止引用 - 已全局注册
// import JNPFTable from "@/components/JNPF-table" // ❌ 已全局注册
// import UploadImg from "@/components/JNPF-UploadImg" // ❌ 已全局注册
// import Pagination from "@/components/Pagination" // ❌ 已全局注册
export default {
components: {
// 🔍 只注册未全局注册的组件
UserSelect, // ✅ 需要注册
DepSelect, // ✅ 需要注册
JPWSignature // ✅ 需要注册
// ❌ 以下组件禁止在此注册 - 已全局注册
// JNPFTable, // ❌ 已全局注册
// UploadImg, // ❌ 已全局注册
// Pagination // ❌ 已全局注册
}
}
</script>
<template>
<!-- 🔍 直接使用已全局注册的组件 -->
<JNPF-table :data="list" /> <!-- ✅ 全局组件 -->
<UploadImg v-model="form.image" /> <!-- ✅ 全局组件(别名)-->
<JNPF-UploadImg v-model="form.pic" /> <!-- ✅ 全局组件(全名)-->
<Pagination :total="total" /> <!-- ✅ 全局组件 -->
<topOpts @add="handleAdd" /> <!-- ✅ 全局组件 -->
<ExportBox ref="exportBox" /> <!-- ✅ 全局组件 -->
<!-- 🔍 使用局部引用的组件 -->
<UserSelect v-model="form.userId" /> <!-- ✅ 局部组件 -->
<DepSelect v-model="form.deptId" /> <!-- ✅ 局部组件 -->
<JPWSignature v-model="form.sign" /> <!-- ✅ 局部组件 -->
</template>
🚨 常见违规示例
vue
<script>
// ❌ 违规1:重复引用全局组件
import JNPFTable from "@/components/JNPF-table" // ❌ 已全局注册!
import UploadImg from "@/components/JNPF-UploadImg" // ❌ 已全局注册!
// ❌ 违规2:组件路径错误
import UserSelect from "@/components/UserSelect" // ❌ 路径不存在
import DepSelect from "@/components/JNPF-DepSelect" // ❌ 大小写错误
// ❌ 违规3:未检查组件是否存在就引用
import MyComponent from "@/components/MyComponent" // ❌ 未验证文件存在
export default {
components: {
JNPFTable, // ❌ 重复注册全局组件
UploadImg, // ❌ 重复注册全局组件
UserSelect, // ❌ 路径错误导致组件无效
MyComponent // ❌ 组件不存在
}
}
</script>
数据绑定
javascript
// v-model 双向绑定
<JPWInput v-model="formData.name" />
// 复杂对象绑定
<JPWSelect :value="formData.type" @input="value => $set(formData, 'type', value)" />
ComponentContainer 使用规范
javascript
// ✅ 正确:使用 CCMixin 管理
export default {
mixins: [CCMixin],
methods: {
openDialog() {
this.openWindow({ url: 'views/module/Form' })
}
}
}
// ❌ 错误:手动管理弹窗状态
export default {
data() {
return { visible: false }
}
}
🔧 组件开发规范
命名规范
- 业务组件:
JPW
开头 - 通用组件:
JNPF
开头
属性定义
javascript
props: {
value: { type: [String, Array], default: '' },
placeholder: { type: String, default: '请输入' },
disabled: { type: Boolean, default: false }
}
组件库核心要点:强制使用规范 + 常用组件 + 基本配置