5.6.10 • Published 10 months ago

@cimom/vben-stores v5.6.10

Weekly downloads
-
License
MIT
Repository
github
Last release
10 months ago

@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();

状态

状态名类型说明
userInfoUserInfo用户信息

方法

方法名参数返回值说明
setUserInfo(info: UserInfo) => voidvoid设置用户信息
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();

状态

状态名类型说明
permissionsstring[]权限列表
rolesstring[]角色列表
superAdminboolean是否为超级管理员

方法

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

标签页管理 (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();

状态

状态名类型说明
tabsTabItem[]标签页列表
activeTabstring当前激活的标签页路径
reloadFlagboolean刷新标志
cachedTabsSet<string>缓存的标签页

方法

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

10 months ago

5.6.9

10 months ago

5.6.8

10 months ago

5.6.7

10 months ago

5.6.6

10 months ago

5.6.5

10 months ago

5.6.4

10 months ago

5.6.3

10 months ago

5.6.2

10 months ago

5.6.1

10 months ago

5.6.0

10 months ago

5.5.21

10 months ago

5.5.20

10 months ago

5.5.18

10 months ago

5.5.17

10 months ago

5.5.16

10 months ago

5.5.15

10 months ago

5.5.14

10 months ago

5.5.13

10 months ago

5.5.12

10 months ago

5.5.11

10 months ago

5.5.10

10 months ago

5.5.9

10 months ago