cd-share
v1.1.3
Published
分享组件 - 支持人员选择、权限设置、链接分享、多渠道分享
Maintainers
Readme
cd-share
分享组件 - 支持人员选择、权限设置、链接分享、多渠道分享、协作者管理
✨ 特性
- 🎯 完整的分享功能 - 支持人员选择、链接分享、权限设置
- 👥 集成人员选择器 - 基于 cd-personselector,支持树形结构、搜索
- 🔐 三级权限控制 - 可阅读/可编辑/可管理,细粒度权限管理
- 👨💼 协作者管理 - 查看、添加、移除协作者,修改协作者权限
- 🔗 链接分享 - 支持组织范围控制、权限级别设置
- 🔒 加密连接 - 支持密码保护,组织外用户需密码访问
- 📱 多渠道分享 - 二维码、邮件、加密链接等
- ⚙️ 权限设置 - 管理员可配置分享、协作者管理、内容操作等权限
- 🎨 基于 TDesign - 遵循 TDesign 设计规范
📦 安装
npm install cd-share
# 或
pnpm add cd-share
# 或
yarn add cd-share🚀 三种使用方法
方法一:基础使用 - 只读权限场景
适用于普通用户查看分享信息,可申请更高权限。
<template>
<div>
<t-button @click="visible = true">查看分享</t-button>
<ShareDialog
v-model:visible="visible"
title="文档分享"
:shareUrl="shareUrl"
currentPermission="read"
:owner="owner"
:collaborators="collaborators"
:organizations="organizations"
@request-permission="handleRequestPermission"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ShareDialog } from 'cd-share'
import 'cd-share/style.css'
const visible = ref(false)
const shareUrl = ref('https://example.com/doc/123')
const owner = ref({
id: 'owner-1',
name: '张三',
avatar: 'https://example.com/avatar/zhangsan.jpg'
})
const collaborators = ref([
{ id: 'c-1', name: '李四', avatar: '', permission: 'edit' },
{ id: 'c-2', name: '王五', avatar: '', permission: 'read' }
])
const organizations = ref([
{ id: 1, name: '总公司' },
{ id: 2, name: '研发中心' },
{ id: 'internet', name: '互联网获得链接的人' }
])
const handleRequestPermission = (permission) => {
console.log('申请权限:', permission)
// 发送权限申请到后端
}
</script>方法二:编辑权限场景
适用于可以添加协作者、修改部分权限的用户。
<template>
<div>
<t-button theme="primary" @click="visible = true">分享文档</t-button>
<ShareDialog
v-model:visible="visible"
title="文档分享"
:shareUrl="shareUrl"
currentPermission="edit"
:owner="owner"
:collaborators="collaborators"
:tabs="tabs"
:organizations="organizations"
@confirm="handleShareConfirm"
@search="handleSearch"
@load-users="handleLoadUsers"
@collaborator-permission-change="handleCollaboratorPermissionChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ShareDialog } from 'cd-share'
import { MessagePlugin } from 'tdesign-vue-next'
import 'cd-share/style.css'
const visible = ref(false)
const shareUrl = ref('https://example.com/doc/123')
const owner = ref({
id: 'owner-1',
name: '张三',
avatar: ''
})
const collaborators = ref([
{ id: 'c-1', name: '李四', avatar: '', permission: 'edit' },
{ id: 'c-2', name: '王五', avatar: '', permission: 'read' },
{ id: 'c-3', name: '赵六', avatar: '', permission: 'manage' }
])
const tabs = ref([
{
key: 'department',
name: '按部门',
icon: 'folder',
tree: [
{ id: 'dept-1', name: '研发部', userCount: 15 },
{ id: 'dept-2', name: '产品部', userCount: 8 }
]
}
])
const organizations = ref([
{ id: 1, name: '总公司' },
{ id: 2, name: '研发中心' },
{ id: 'internet', name: '互联网获得链接的人' }
])
const handleShareConfirm = (payload) => {
console.log('分享结果:', payload)
MessagePlugin.success(`已分享给 ${payload.sharerIds.length} 位用户`)
// 提交到后端
}
const handleSearch = ({ keyword, callback }) => {
// 调用后端搜索接口
const users = [
{ id: 'u-1', name: '用户A', department: '研发部' }
]
callback(users)
}
const handleLoadUsers = ({ tabKey, nodeId, callback }) => {
// 加载节点下的用户
callback([])
}
const handleCollaboratorPermissionChange = ({ id, permission }) => {
const collaborator = collaborators.value.find(c => c.id === id)
if (collaborator) {
collaborator.permission = permission
MessagePlugin.success('权限已更新')
}
}
</script>方法三:管理权限场景(完整功能)
适用于管理员,拥有所有权限,可以管理协作者、设置权限策略。
<template>
<div>
<t-button theme="primary" @click="visible = true">管理分享</t-button>
<ShareDialog
v-model:visible="visible"
title="报表分享管理"
:shareUrl="shareUrl"
helpUrl="https://help.example.com/share"
currentPermission="manage"
:owner="owner"
:collaborators="collaborators"
:tabs="tabs"
:organizations="organizations"
:defaultPermissionSettings="permissionSettings"
@confirm="handleShareConfirm"
@search="handleSearch"
@load-users="handleLoadUsers"
@permission-settings-change="handlePermissionSettingsChange"
@manage-collaborators="handleManageCollaborators"
@remove-collaborator="handleRemoveCollaborator"
@collaborator-permission-change="handleCollaboratorPermissionChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ShareDialog } from 'cd-share'
import { MessagePlugin } from 'tdesign-vue-next'
import 'cd-share/style.css'
const visible = ref(false)
const shareUrl = ref('https://example.com/report/123')
const owner = ref({
id: 'owner-1',
name: '张三',
displayName: '张三(产品经理)',
avatar: 'https://example.com/avatar.jpg'
})
const collaborators = ref([
{ id: 'c-1', name: '李四', displayName: '李四', avatar: '', permission: 'edit' },
{ id: 'c-2', name: '王五', displayName: '王五', avatar: '', permission: 'read' },
{ id: 'c-3', name: '赵六', displayName: '赵六', avatar: '', permission: 'manage' }
])
const tabs = ref([
{
key: 'department',
name: '按部门',
icon: 'folder',
tree: [
{ id: 'dept-1', name: '研发部', userCount: 15 },
{ id: 'dept-2', name: '产品部', userCount: 8 }
]
}
])
const organizations = ref([
{ id: 1, name: '总公司' },
{ id: 2, name: '研发中心' },
{ id: 'internet', name: '互联网获得链接的人' }
])
const permissionSettings = ref({
allowExternalShare: true,
allowViewCollaborators: true,
allowAddCollaborators: true
})
const handleShareConfirm = (payload) => {
console.log('分享数据:', payload)
// payload 包含:sharerIds, orgId, permission, sendNotification, password, remark
MessagePlugin.success(`已分享给 ${payload.sharerIds.length} 位用户`)
}
const handleSearch = ({ keyword, callback }) => {
// 搜索用户
setTimeout(() => {
const users = [
{ id: 'u-1', name: '张三', department: '研发部', position: '前端工程师' },
{ id: 'u-2', name: '李四', department: '产品部', position: '产品经理' }
]
callback(users.filter(u => u.name.includes(keyword)))
}, 300)
}
const handleLoadUsers = ({ tabKey, nodeId, callback }) => {
// 加载树节点下的用户
setTimeout(() => {
callback([
{ id: 'u-3', name: '王五', department: '研发部' }
])
}, 300)
}
const handlePermissionSettingsChange = (settings) => {
console.log('权限设置变更:', settings)
MessagePlugin.success('权限设置已保存')
// 提交到后端
}
const handleManageCollaborators = (persons) => {
console.log('添加协作者:', persons)
MessagePlugin.info('添加协作者')
}
const handleRemoveCollaborator = (id) => {
collaborators.value = collaborators.value.filter(c => c.id !== id)
MessagePlugin.success('已移除协作者')
}
const handleCollaboratorPermissionChange = ({ id, permission }) => {
const collaborator = collaborators.value.find(c => c.id === id)
if (collaborator) {
collaborator.permission = permission
MessagePlugin.success(`已修改权限为: ${permission}`)
}
}
</script>📚 API 文档
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| visible | Boolean | false | 对话框显示状态(支持 v-model) |
| title | String | '分享' | 对话框标题 |
| shareUrl | String | '' | 分享链接 URL |
| helpUrl | String | '' | 帮助文档链接 |
| width | String | '500px' | 对话框宽度 |
| currentPermission | 'read' \| 'edit' \| 'manage' | 'edit' | 当前用户对资源的权限 |
| owner | User | - | 资源所有者信息 |
| collaborators | Collaborator[] | [] | 协作者列表(包含权限) |
| tabs | Array | [] | 人员选择器的 Tab 配置 |
| organizations | Organization[] | [] | 组织列表(含"互联网获得链接的人") |
| defaultPermissionSettings | PermissionSettings | - | 默认权限设置 |
Events
| 事件名 | 参数 | 说明 |
|--------|------|------|
| update:visible | (visible: boolean) | 对话框显示状态变化 |
| confirm | (payload: SharePayload) | 确认分享 |
| search | ({ keyword, callback }) | 搜索用户 |
| load-users | ({ tabKey, nodeId, callback }) | 加载树节点用户 |
| request-permission | (permission: Permission) | 申请权限(只读用户) |
| permission-settings-change | (settings: PermissionSettings) | 权限设置变更 |
| manage-collaborators | (persons?: any[]) | 管理协作者(添加) |
| remove-collaborator | (id: string \| number) | 移除协作者 |
| collaborator-permission-change | ({ id, permission }) | 协作者权限变更 |
类型定义
// 用户类型
interface User {
id: string | number
name?: string
displayName?: string
avatar?: string
}
// 协作者类型
interface Collaborator extends User {
permission: 'read' | 'edit' | 'manage'
}
// 组织类型
interface Organization {
id: number | string
name: string
displayName?: string
}
// 分享数据类型
interface SharePayload {
sharerIds: string[] // 格式:user:id, depot:id, group:id, post:id
orgId: string | number // 组织ID
permission: 'read' | 'edit' | 'manage' // 权限级别
sendNotification: boolean // 是否发送通知
password?: string // 密码(如果设置)
remark: string // 备注信息
}
// 权限设置类型
interface PermissionSettings {
allowExternalShare?: boolean // 允许分享到组织外
allowViewCollaborators?: boolean // 允许查看协作者
allowAddCollaborators?: boolean // 允许添加协作者
allowCopy?: boolean // 允许复制
allowDownload?: boolean // 允许下载/打印
allowComment?: boolean // 允许评论
showVisitorAvatars?: boolean // 显示访问者头像
}🔐 权限说明
三级权限控制
| 权限级别 | 功能说明 | |---------|---------| | 只读 (read) | • 只能查看协作者列表和分享信息• 不能添加协作者• 不能修改任何权限• 可以复制链接、查看二维码• 可以申请编辑权限 | | 编辑 (edit) | • 可以添加协作者• 可以修改"可阅读"和"可编辑"权限的协作者• 不能修改"可管理"权限的协作者• 不能删除协作者• 可以设置加密连接 | | 管理 (manage) | • 拥有所有权限• 可以设置任何级别的权限• 可以删除协作者• 可以配置权限策略• 完全控制权 |
权限设计原则
- ✅ 最小权限原则 - 用户只拥有完成任务所需的最小权限
- ✅ 分级管理 - 编辑用户不能越权设置管理员
- ✅ UI + 函数双层防护 - 即使绕过 UI 禁用,函数层仍会验证
- ✅ 清晰的视觉反馈 - 所有权限限制都有明确提示
🎨 样式定制
组件基于 TDesign,支持通过 CSS 变量自定义样式:
/* 自定义对话框样式 */
.cd-share-dialog {
/* 你的自定义样式 */
}🔧 依赖
vue^3.0.0tdesign-vue-next^1.0.0cd-personselector^1.2.3cd-usercard^2.3.1
📄 License
MIT
🤝 贡献
欢迎提交 Issue 和 Pull Request!
