@zhouwei941017/system-user-management
v1.0.0-beta.1
Published
Vue3用户管理完整组件(包含列表、表单、增删改查)
Maintainers
Readme
@zhouwei941017/system-management
Vue3 用户管理完整组件(一个组件搞定所有功能)
核心特性
✅ 一个组件:<UserManagement /> 搞定用户管理的所有功能
✅ 零配置:开箱即用,不需要创建多个文件
✅ 完整功能:列表展示、增删改查、表单验证、权限控制
✅ 灵活适配:可对接任意后端API
安装
npm install @zhouwei941017/system-management
# 或
pnpm add @zhouwei941017/system-management
# 或
yarn add @zhouwei941017/system-management简单使用
<!-- 在你的项目中 -->
<script setup>
import { UserManagement } from '@zhouwei941017/system-management';
import { $t, hasAccessByCodes } from '#/utils'; // 你的国际化函数
import { requestClient } from '#/api/request'; // 你的请求客户端
// 自定义API客户端
const apiClient = {
get: (url) => requestClient.get(url),
post: (url, data) => requestClient.post(url, data),
put: (url, data) => requestClient.put(url, data),
delete: (url) => requestClient.delete(url),
};
</script>
<template>
<div class="page-container">
<UserManagement
:t="$t"
:has-access-by-codes="hasAccessByCodes"
:api-client="apiClient"
base-url="/api/user"
show-title
/>
</div>
</template>完整示例(Vben框架项目)
如果你的项目使用Vben框架(与spark-fe相同):
<!-- src/views/system/user/index.vue -->
<template>
<UserManagement
:t="$t"
:has-access-by-codes="hasAccessByCodes"
:api-client="vbenApiClient"
/>
</template>
<script setup>
import { UserManagement } from '@zhouwei941017/system-management';
import { $t, useAccess } from '#/constants/common-imports';
import { requestClient } from '#/api/request';
const { hasAccessByCodes } = useAccess();
// Vben框架API客户端
const vbenApiClient = {
get: (url) => requestClient.get(url),
post: (url, data) => requestClient.post(url, data),
put: (url, data) => requestClient.put(url, data),
delete: (url) => requestClient.delete(url),
};
</script>Props配置
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| t | (key: string) => string | key => key | 国际化函数 |
| hasAccessByCodes | (codes: string[]) => boolean | () => true | 权限检查函数 |
| apiClient | ApiClient | 必填 | API请求客户端 |
| baseUrl | string | /sys/user/v1 | API基础路径 |
| i18nKey | string | system.user | 国际化key前缀 |
| showTitle | boolean | false | 是否显示标题 |
| storageKey | string | system-user | 查询条件存储key |
与其他方案对比
| 方案 | 文件数 | 使用方式 | 维护性 |
|------|--------|----------|--------|
| 传统方式 | 4个文件 | list.vue、ModalForm.vue、api.ts、config | 每个项目都要复制 |
| 配置包方式 | 2个文件 + npm包 | 安装包 + 创建ModalForm.vue | 类型集中管理 |
| 本组件方式 | 1个文件 | <UserManagement /> | 最优维护性 |
项目文件变化
原项目需要4个文件:
list.vue- 主页面ModalForm.vue- 表单模态框api.ts- API定义config/index.ts- 配置函数
现在只需要:
UserManagement.vue(在npm包中)- 在你的项目中:
<UserManagement />组件
依赖说明
本组件需要项目中已安装以下依赖:
- Vue3
- Vben框架相关组件(如果是Vben项目)
- 或自定义实现以下组件:
DynamicListPage(列表组件)Button(按钮组件)useVbenModal(模态框hooks)useVbenForm(表单hooks)
如果项目中没有这些组件,可以自定义适配器。
API客户端示例
1. Vben项目
import { requestClient } from '#/api/request';
const apiClient = {
get: (url) => requestClient.get(url),
post: (url, data) => requestClient.post(url, data),
put: (url, data) => requestClient.put(url, data),
delete: (url) => requestClient.delete(url),
};2. 普通Vue项目
import axios from 'axios';
const apiClient = {
get: (url) => axios.get(url),
post: (url, data) => axios.post(url, data),
put: (url, data) => axios.put(url, data),
delete: (url) => axios.delete(url),
};事件
| 事件名 | 参数 | 说明 |
|--------|------|------|
| success | 无 | 操作成功时触发 |
| error | error | 发生错误时触发 |
| loading | boolean | 加载状态变化时触发 |
方法
通过ref访问组件方法:
<script setup>
import { ref } from 'vue';
import { UserManagement } from '@zhouwei941017/system-management';
const userManagementRef = ref();
// 刷新列表
const refreshUsers = () => {
userManagementRef.value?.refresh();
};
// 打开新增模态框
const openCreateModal = () => {
userManagementRef.value?.openCreateModal();
};
</script>
<template>
<UserManagement ref="userManagementRef" />
</template>开发
cd vue3-zw-package
npm run dev # 开发模式
npm run build # 构建License
ISC
安装
npm install @zhouwei941017/system-management
# 或
pnpm add @zhouwei941017/system-management
# 或
yarn add @zhouwei941017/system-management包含内容
- 类型定义 (
UserEntity) - 用户实体类型 - API 定义 - 增删改查API函数
- 配置生成器 (
createUserConfig) - 生成用户管理配置 - 表单 Schema (
getUserFormSchema) - 用户表单schema生成器
在项目中使用的完整示例
第1步:在项目中使用API
// 原项目中的 api.ts 会被替换为:
import {
createUserApi,
updateUserApi,
deleteUserApi,
getUserListApi,
getUserDetailApi
} from '@zhouwei941017/system-management';
// 直接使用这些API函数
// 它们已经包含了正确的参数和返回类型第2步:创建表单组件 (ModalForm.vue)
<!-- src/views/system/user/modules/ModalForm.vue -->
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useVbenModal, isSuccessResponse } from '@vben/common-ui';
import { useVbenForm } from '#/components/form';
import { $t } from '#/locales';
import { message } from 'ant-design-vue';
// 从npm包导入
import {
getUserFormSchema,
createUserApi,
updateUserApi,
getUserDetailApi
} from '@zhouwei941017/system-management';
const emit = defineEmits<{
success: []
}>();
const formData = ref();
const schema = computed(() => getUserFormSchema({ t: $t }));
const [BaseForm, formApi] = useVbenForm({
compact: true,
commonConfig: {
componentProps: { class: 'w-full' },
formItemClass: 'col-span-2',
labelClass: 'w-32',
wrapperClass: 'flex-1',
},
schema: schema.value,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
try {
modalApi.setState({ confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const values = await formApi.getValues();
// 处理数据格式转换
values.avatar = values.avatar?.[0]?.url || '';
values.roleIds = values.roleIdsStr?.split(',').map(item => item.trim()) || [];
delete values.roleIdsStr;
if (formData.value?.id) {
const result = await updateUserApi(formData.value.id, values);
if (isSuccessResponse(result.code)) {
message.success($t('ui.actionMessage.operationSuccess'));
modalApi.close();
emit('success');
}
} else {
const result = await createUserApi(values);
if (isSuccessResponse(result.code)) {
message.success($t('ui.actionMessage.operationSuccess'));
modalApi.close();
emit('success');
}
}
} finally {
modalApi.setState({ confirmLoading: false });
}
},
async onOpenChange(isOpen) {
if (isOpen) {
const data = modalApi.getData();
if (data?.id) {
const result = await getUserDetailApi(data.id);
if (isSuccessResponse(result.code) && result.data) {
formData.value = result.data;
const values = {
...result.data,
avatar: result.data.avatar ? [{ url: result.data.avatar }] : [],
roleIdsStr: result.data.roleIds?.join(',') || ''
};
formApi.setValues(values);
}
} else {
formData.value = undefined;
formApi.resetForm();
}
}
},
});
</script>
<template>
<Modal :title="formData?.id ? $t('common.edit') : $t('common.add')" class="w-[600px]">
<BaseForm />
</Modal>
</template>第3步:创建配置文件 (config/index.ts)
// src/views/system/user/config/index.ts
import type { UserEntity } from '@zhouwei941017/system-management';
import { DynamicListPage, ref, useVbenModal } from '#/constants/common-imports';
import { useCrudActions } from '#/hooks/use-crud-actions';
import ModalForm from '../modules/ModalForm.vue';
import {
deleteUserApi,
getUserListApi,
getUserDetailApi
} from '@zhouwei941017/system-management';
export function useConfig(hasAccessByCodes: any, $t: any) {
const [ModalComponent, modalApi] = useVbenModal({
connectedComponent: ModalForm,
destroyOnClose: true,
});
const listPageRef = ref<InstanceType<typeof DynamicListPage>>();
const { currentEditData, handleSuccess, createOperationConfig, onCreate } =
useCrudActions<UserEntity>({
modalApi,
getDetailApi: getUserDetailApi,
deleteApi: deleteUserApi,
listPageRef,
i18nKey: 'system.user',
operationTitle: $t('common.operation'),
operationOptions: [
{ code: 'edit', show: () => hasAccessByCodes(['sys:user:edit']) },
{ code: 'delete', show: () => hasAccessByCodes(['sys:user:delete']) },
],
customActions: {
changePassword: (row: UserEntity) => {
currentEditData.value = row;
},
},
});
const operationConfig = createOperationConfig();
return {
listPageRef,
currentEditData,
handleSuccess,
onCreate,
operationConfig,
ModalComponent,
getListApi: getUserListApi,
};
}第4步:主页面 (list.vue)
<!-- src/views/system/user/list.vue -->
<script lang="ts" setup>
import {
$t,
Button,
DynamicListPage,
useAccess,
} from '#/constants/common-imports';
import { useConfig } from './config';
const { hasAccessByCodes } = useAccess();
const { handleSuccess, onCreate, operationConfig, ModalComponent, getListApi } =
useConfig(hasAccessByCodes, $t);
</script>
<template>
<div>
<DynamicListPage
:fetch-data="getListApi"
:fixed-columns="operationConfig"
advanced-query-storage-key="system-user"
>
<template #table-title>
<Button
type="primary"
@click="onCreate"
v-if="hasAccessByCodes(['sys:user:create'])"
>
{{ $t('common.add') }}
</Button>
</template>
</DynamicListPage>
<ModalComponent @success="handleSuccess" />
</div>
</template>项目文件变化对比
| 原项目文件 | npm包部分 | 项目中保留部分 |
|-----------|----------|--------------|
| api.ts | API函数定义 | 无 (全部迁移) |
| config/data.ts | 表单schema | 无 (全部迁移) |
| config/index.ts | 无 | 完整保留 (稍作修改) |
| modules/ModalForm.vue | 无 | 完整保留 (稍作修改) |
| list.vue | 无 | 完整保留 (稍作修改) |
优势
- 类型安全: 全TypeScript类型支持
- 复用性: 其他项目直接安装即可使用
- 维护简单: 配置和类型定义集中管理
- 不影响现有UI: 保持原有的DynamicListPage等组件
注意事项
- 需要确保项目中已安装依赖的@vben系列包
- API函数可能需要根据实际后端地址进行包装
- 国际化key需要与项目匹配
- 表单schema可能需要根据业务需求调整
开发
# 本地开发
cd vue3-zw-package
npm run dev
# 构建
npm run build
# 发布
npm publish --access publicLicense
ISC
