5.6.10 • Published 6 months ago

@cimom/vben-stores v5.6.10

Weekly downloads
-
License
MIT
Repository
github
Last release
6 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

6 months ago

5.6.9

6 months ago

5.6.8

6 months ago

5.6.7

6 months ago

5.6.6

6 months ago

5.6.5

6 months ago

5.6.4

6 months ago

5.6.3

6 months ago

5.6.2

6 months ago

5.6.1

6 months ago

5.6.0

6 months ago

5.5.21

6 months ago

5.5.20

6 months ago

5.5.18

6 months ago

5.5.17

6 months ago

5.5.16

6 months ago

5.5.15

6 months ago

5.5.14

6 months ago

5.5.13

6 months ago

5.5.12

6 months ago

5.5.11

6 months ago

5.5.10

6 months ago

5.5.9

6 months ago