npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cd-share

v1.1.3

Published

分享组件 - 支持人员选择、权限设置、链接分享、多渠道分享

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.0
  • tdesign-vue-next ^1.0.0
  • cd-personselector ^1.2.3
  • cd-usercard ^2.3.1

📄 License

MIT

🤝 贡献

欢迎提交 Issue 和 Pull Request!