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

@cimom/vben-stores

v5.6.10

Published

基于 Pinia 的状态管理工具包,提供了应用中常用的状态存储模块,包括用户状态、权限控制、标签页管理等。

Readme

@cimom/vben-stores

基于 Pinia 的状态管理工具包,提供了应用中常用的状态存储模块,包括用户状态、权限控制、标签页管理等。

安装

npm install @cimom/vben-stores

基本使用

初始化 Store

import { setupStore } from '@cimom/vben-stores';
import type { App } from 'vue';

// 在应用启动时初始化
export function setupApp(app: App) {
  // 初始化状态管理
  setupStore(app);

  // ... 其他初始化
}

使用状态存储

import {
  useUserStore,
  useAccessStore,
  useTabbarStore,
} from '@cimom/vben-stores';

// 用户状态
const userStore = useUserStore();
console.log(userStore.userInfo);

// 权限状态
const accessStore = useAccessStore();
console.log(accessStore.hasPermission('user:create'));

// 标签页状态
const tabbarStore = useTabbarStore();
console.log(tabbarStore.tabs);

可用的状态存储模块

用户状态 (UserStore)

管理用户信息和登录状态。

import { useUserStore } from '@cimom/vben-stores';

const userStore = useUserStore();

// 获取用户信息
const userInfo = userStore.userInfo;

// 设置用户信息
userStore.setUserInfo({
  id: '1',
  username: 'admin',
  realName: '管理员',
  avatar: '/avatar.jpg',
  // 其他用户信息...
});

// 清除用户信息
userStore.resetUserInfo();

状态

| 状态名 | 类型 | 说明 | | ---------- | ---------- | -------- | | userInfo | UserInfo | 用户信息 |

方法

| 方法名 | 参数 | 返回值 | 说明 | | --------------- | -------------------------- | ------ | ------------ | | setUserInfo | (info: UserInfo) => void | void | 设置用户信息 | | resetUserInfo | - | void | 重置用户信息 |

权限控制 (AccessStore)

管理用户权限和角色。

import { useAccessStore } from '@cimom/vben-stores';

const accessStore = useAccessStore();

// 检查是否有特定权限
if (accessStore.hasPermission('user:create')) {
  // 有创建用户的权限
}

// 检查是否有特定角色
if (accessStore.hasRole('admin')) {
  // 是管理员角色
}

// 设置权限列表
accessStore.setPermissions(['user:create', 'user:edit', 'user:delete']);

// 设置角色列表
accessStore.setRoles(['admin', 'editor']);

// 重置权限和角色
accessStore.resetPermissions();
accessStore.resetRoles();

状态

| 状态名 | 类型 | 说明 | | ------------- | ---------- | ---------------- | | permissions | string[] | 权限列表 | | roles | string[] | 角色列表 | | superAdmin | boolean | 是否为超级管理员 |

方法

| 方法名 | 参数 | 返回值 | 说明 | | --- | --- | --- | --- | | setPermissions | (permissions: string[]) => void | void | 设置权限列表 | | resetPermissions | - | void | 重置权限列表 | | setRoles | (roles: string[]) => void | void | 设置角色列表 | | resetRoles | - | void | 重置角色列表 | | setSuperAdmin | (value: boolean) => void | void | 设置超级管理员状态 | | hasPermission | (permission: string \| string[]) => boolean | boolean | 检查是否有特定权限 | | hasRole | (role: string \| string[]) => boolean | boolean | 检查是否有特定角色 |

标签页管理 (TabbarStore)

管理应用的标签页。

import { useTabbarStore } from '@cimom/vben-stores';

const tabbarStore = useTabbarStore();

// 获取所有标签页
const tabs = tabbarStore.tabs;

// 获取当前激活的标签页
const activeTab = tabbarStore.activeTab;

// 添加标签页
tabbarStore.addTab({
  path: '/dashboard',
  title: '仪表盘',
  name: 'Dashboard',
  closable: false,
});

// 关闭标签页
tabbarStore.closeTab('/dashboard');

// 关闭其他标签页
tabbarStore.closeOtherTabs('/dashboard');

// 关闭左侧标签页
tabbarStore.closeLeftTabs('/dashboard');

// 关闭右侧标签页
tabbarStore.closeRightTabs('/dashboard');

// 关闭所有标签页
tabbarStore.closeAllTabs();

// 设置激活的标签页
tabbarStore.setActiveTab('/dashboard');

// 刷新当前标签页
tabbarStore.refreshTab();

状态

| 状态名 | 类型 | 说明 | | ------------ | ------------- | -------------------- | | tabs | TabItem[] | 标签页列表 | | activeTab | string | 当前激活的标签页路径 | | reloadFlag | boolean | 刷新标志 | | cachedTabs | Set<string> | 缓存的标签页 |

方法

| 方法名 | 参数 | 返回值 | 说明 | | --- | --- | --- | --- | | setTabs | (tabs: TabItem[]) => void | void | 设置标签页列表 | | addTab | (tab: TabItem) => void | void | 添加标签页 | | updateTab | (path: string, tab: Partial<TabItem>) => void | void | 更新标签页 | | closeTab | (path: string) => void | void | 关闭标签页 | | closeOtherTabs | (path: string) => void | void | 关闭其他标签页 | | closeLeftTabs | (path: string) => void | void | 关闭左侧标签页 | | closeRightTabs | (path: string) => void | void | 关闭右侧标签页 | | closeAllTabs | - | void | 关闭所有标签页 | | setActiveTab | (path: string) => void | void | 设置激活的标签页 | | refreshTab | (path?: string) => void | void | 刷新标签页 | | addCachedTab | (name: string) => void | void | 添加缓存的标签页 | | removeCachedTab | (name: string) => void | void | 移除缓存的标签页 | | clearCachedTabs | - | void | 清除所有缓存的标签页 | | resetState | - | void | 重置状态 |

类型定义

用户信息 (UserInfo)

interface UserInfo {
  id: string;
  username: string;
  realName: string;
  avatar: string;
  desc?: string;
  homePath?: string;
  roles?: string[];
}

标签页项 (TabItem)

interface TabItem {
  path: string;
  name: string;
  title: string;
  icon?: string;
  closable?: boolean;
  affix?: boolean;
  query?: Record<string, any>;
  params?: Record<string, any>;
}

高级用法

自定义 Store

可以基于提供的 Store 创建自定义的状态存储。

import { defineStore } from '@cimom/vben-stores';

// 定义状态接口
interface CounterState {
  count: number;
  lastUpdated: number;
}

// 创建自定义 Store
export const useCounterStore = defineStore('counter', {
  state: (): CounterState => ({
    count: 0,
    lastUpdated: Date.now(),
  }),
  getters: {
    doubleCount(): number {
      return this.count * 2;
    },
  },
  actions: {
    increment() {
      this.count++;
      this.lastUpdated = Date.now();
    },
    decrement() {
      this.count--;
      this.lastUpdated = Date.now();
    },
    reset() {
      this.count = 0;
      this.lastUpdated = Date.now();
    },
  },
});

持久化状态

可以使用 pinia-plugin-persistedstate 插件来持久化状态。

import { defineStore } from '@cimom/vben-stores';

export const useSettingsStore = defineStore('settings', {
  state: () => ({
    theme: 'light',
    fontSize: 'medium',
    showSidebar: true,
  }),
  actions: {
    setTheme(theme: 'light' | 'dark') {
      this.theme = theme;
    },
    setFontSize(size: 'small' | 'medium' | 'large') {
      this.fontSize = size;
    },
    toggleSidebar() {
      this.showSidebar = !this.showSidebar;
    },
  },
  // 持久化配置
  persist: {
    key: 'app-settings',
    storage: localStorage,
    paths: ['theme', 'fontSize', 'showSidebar'],
  },
});

订阅状态变化

import { useUserStore } from '@cimom/vben-stores';
import { storeToRefs } from '@cimom/vben-stores';
import { watch } from 'vue';

const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);

// 监听用户信息变化
watch(
  userInfo,
  (newValue, oldValue) => {
    console.log('用户信息变化:', newValue, oldValue);
  },
  { deep: true },
);

// 使用 $subscribe 方法
userStore.$subscribe((mutation, state) => {
  console.log('状态变化:', mutation, state);
  // 可以在这里执行额外的操作,如保存到本地存储
});

示例

权限控制组件

<template>
  <div>
    <!-- 根据权限显示按钮 -->
    <button v-if="hasPermission('user:create')">创建用户</button>

    <!-- 使用指令控制权限 -->
    <button v-permission="'user:edit'">编辑用户</button>

    <!-- 根据角色显示内容 -->
    <div v-if="hasRole('admin')">仅管理员可见内容</div>
  </div>
</template>

<script setup lang="ts">
import { useAccessStore } from '@cimom/vben-stores';

const accessStore = useAccessStore();
const { hasPermission, hasRole } = accessStore;
</script>

标签页组件

<template>
  <div class="tabs-container">
    <!-- 标签页列表 -->
    <div class="tabs">
      <div
        v-for="tab in tabs"
        :key="tab.path"
        :class="['tab', { active: activeTab === tab.path }]"
        @click="setActiveTab(tab.path)"
      >
        <span>{{ tab.title }}</span>
        <button
          v-if="tab.closable"
          class="close-btn"
          @click.stop="closeTab(tab.path)"
        >
          ×
        </button>
      </div>
    </div>

    <!-- 标签页操作 -->
    <div class="tab-actions">
      <button @click="refreshTab()">刷新</button>
      <button @click="closeOtherTabs(activeTab)">关闭其他</button>
      <button @click="closeAllTabs()">关闭所有</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { useTabbarStore } from '@cimom/vben-stores';
import { storeToRefs } from '@cimom/vben-stores';

const tabbarStore = useTabbarStore();
const { tabs, activeTab } = storeToRefs(tabbarStore);
const { setActiveTab, closeTab, closeOtherTabs, closeAllTabs, refreshTab } =
  tabbarStore;
</script>

<style scoped>
.tabs-container {
  display: flex;
  align-items: center;
  border-bottom: 1px solid #eee;
  padding: 0 16px;
  height: 40px;
}

.tabs {
  display: flex;
  flex: 1;
  overflow-x: auto;
}

.tab {
  display: flex;
  align-items: center;
  padding: 0 16px;
  height: 100%;
  cursor: pointer;
  border-right: 1px solid #eee;
  white-space: nowrap;
}

.tab.active {
  background-color: #f0f0f0;
}

.close-btn {
  margin-left: 8px;
  width: 16px;
  height: 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  border-radius: 50%;
}

.close-btn:hover {
  background-color: #ddd;
}

.tab-actions {
  display: flex;
  gap: 8px;
  margin-left: 16px;
}

.tab-actions button {
  padding: 4px 8px;
  border: 1px solid #ddd;
  background: white;
  border-radius: 4px;
  cursor: pointer;
}

.tab-actions button:hover {
  background-color: #f0f0f0;
}
</style>

用户信息组件

<template>
  <div v-if="userInfo.id" class="user-info">
    <div class="avatar">
      <img :src="userInfo.avatar" :alt="userInfo.realName" />
    </div>
    <div class="info">
      <div class="name">{{ userInfo.realName }}</div>
      <div class="username">@{{ userInfo.username }}</div>
    </div>
    <button @click="logout" class="logout-btn">退出登录</button>
  </div>
  <div v-else class="login-prompt">请先登录</div>
</template>

<script setup lang="ts">
import { useUserStore } from '@cimom/vben-stores';
import { storeToRefs } from '@cimom/vben-stores';

const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);

function logout() {
  userStore.resetUserInfo();
  // 其他登出逻辑...
}
</script>

<style scoped>
.user-info {
  display: flex;
  align-items: center;
  padding: 12px;
  border: 1px solid #eee;
  border-radius: 8px;
}

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  margin-right: 12px;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.info {
  flex: 1;
}

.name {
  font-weight: bold;
}

.username {
  font-size: 12px;
  color: #666;
}

.logout-btn {
  padding: 4px 8px;
  border: 1px solid #ddd;
  background: white;
  border-radius: 4px;
  cursor: pointer;
}

.login-prompt {
  padding: 12px;
  text-align: center;
  border: 1px solid #eee;
  border-radius: 8px;
  color: #999;
}
</style>