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

@bnfe/store-select

v1.0.4

Published

门店地址选择器组件,基于 Vue 3 + Element Plus 开发,支持自动数据加载、权限过滤和多种输出格式。

Readme

@bnfe/store-select

门店地址选择器组件,基于 Vue 3 + Element Plus 开发,支持自动数据加载、权限过滤和多种输出格式。

安装

pnpm add @bnfe/store-select

依赖

{
  "peerDependencies": {
    "element-plus": ">=2.5.0",
    "vue": ">=3.4.0"
  }
}

使用

方式一:自动模式(推荐)✅

StoreSelectWithApi 组件封装了 API 请求、数据转换和权限过滤,开箱即用:

<script setup lang="ts">
import { ref } from 'vue';
import { StoreSelectWithApi } from '@bnfe/store-select';
import '@bnfe/store-select/dist/store-select.css'

// 选中的门店ID
const selectedIds = ref<string[]>([]);

// 用户权限门店ID列表(从后端获取)
const permissionIds = ['12', '152', '108', '99'];

// 请求头配置(动态注入业务上下文)
const headers = {
  Authorization: 'Bearer xxx',
  'Employee-Id': 'xxx',
  appkey: 'xxx'
};
</script>

<template>
  <StoreSelectWithApi
    v-model="selectedIds"
    :api-url="'/api/stores/get-store-all-group'"
    :headers="headers"
    :permission-ids="permissionIds"
  />
</template>

方式二:手动模式

如果需要更灵活的控制,可以使用基础 StoreSelect 组件:

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { StoreSelect, filterStoreByPermission } from '@bnfe/store-select';
import '@bnfe/store-select/dist/store-select.css'

const selectedIds = ref([]);
const storeGroup = ref({  city: [], sub_region: [] });
const permissionIds = ['12', '152', '108'];

onMounted(async () => {
  // 1. 请求数据
  const res = await fetch('/api/stores/get-store-all-group');
  const data = await res.json();

  // 2. 权限过滤
  storeGroup.value = filterStoreByPermission(data.data, permissionIds);
});
</script>

<template>
  <StoreSelect v-model="selectedIds" :store-group="storeGroup" />
</template>

API

StoreSelectWithApi Props

| 属性 | 类型 | 默认值 | 必填 | 说明 | |------|------|--------|------|------| | v-model | string[] \| string | - | ✅ | 选中的门店ID,支持数组或逗号分隔字符串 | | api-url | string | /api/stores/get-store-all-group | - | 门店数据接口地址 | | headers | Record<string, string> | - | ✅ | 请求头对象,用于注入 Token、员工ID 等业务上下文 | | permission-ids | string[] | - | ✅ | 用户有权限访问的门店ID数组 | | value-type | 'array' \| 'string' | 'array' | - | 输出值类型:array 数组格式,string 逗号分隔字符串 | | auto-load | boolean | true | - | 组件挂载后自动请求数据 | | collapse-tags | boolean | true | - | 是否折叠Tags | | max-collapse-tags | number | 2 | - | 最多显示的Tag数量 |

StoreSelectWithApi Events

| 事件 | 参数 | 说明 | |------|------|------| | @load | (data: StoreGroupInfo) => void | 数据加载成功时触发 | | @error | (error: Error) => void | 数据加载失败时触发 | | @update:modelValue | (value: string[] \| string) => void | 选中值变化时触发 |

StoreSelect Props

| 属性 | 类型 | 默认值 | 必填 | 说明 | |------|------|--------|------|------| | v-model | string[] | - | ✅ | 选中的门店ID数组 | | store-group | StoreGroupInfo | - | ✅ | 门店数据(区域/城市分组) | | collapse-tags | boolean | true | - | 是否折叠Tags | | max-collapse-tags | number | 2 | - | 最多显示的Tag数量 |

工具函数

filterStoreByPermission

按权限过滤门店数据:

import { filterStoreByPermission } from '@bnfe/store-select';

const filteredData = filterStoreByPermission(originData, permissionIds);

参数:

  • data: 原始门店数据结构
  • userStoreIds: 用户有权限的门店ID数组

返回值: 过滤后的门店数据

数据结构

类型导入

import type { StoreGroupInfo, StoreGroupItem, StoreItem } from '@bnfe/store-select'

// StoreGroupInfo

interface StoreGroupInfo {
  region: StoreGroupItem[];      // 大区列表
  city: StoreGroupItem[];        // 城市列表
  sub_region: StoreGroupItem[];  // 子大区列表(含子小区嵌套)
}

interface StoreGroupItem {
  id: string;
  name: string;
  storeList?: StoreItem[];       // 直属门店列表
  sub?: StoreGroupItem[];        // 子分组(含嵌套门店)
}

interface StoreItem {
  jss_store_id: string;
  store_id: string;
  store_name: string;
}

示例

完整示例

<script setup lang="ts">
import { ref, computed } from 'vue';
import { StoreSelectWithApi } from '@bnfe/store-select';

// 用户权限门店ID(实际从后端获取)
const permissionIds = ['12', '152', '108', '99', '102', '94'];

// 选中值
const selectedIds = ref<string[]>([]);

// 字符串格式(用于提交表单)
const selectedIdsString = computed(() => selectedIds.value.join(','));

// 请求头
const headers = computed(() => ({
  Authorization: `Bearer ${token}`,
  'Employee-Id': userId,
  'User-Name': encodeURIComponent(userName),
  appkey: 'your-appkey'
}));

// 回调处理
const onLoad = (data) => {
  console.log('数据加载成功', data);
};

const onError = (error) => {
  console.error('数据加载失败', error);
};
</script>

<template>
  <div>
    <!-- 组件使用 -->
    <StoreSelectWithApi
      v-model="selectedIds"
      api-url="https://api.example.com/stores"
      :headers="headers"
      :permission-ids="permissionIds"
      @load="onLoad"
      @error="onError"
    />

    <!-- 显示选中结果 -->
    <p>数组格式: {{ selectedIds }}</p>
    <p>字符串格式: {{ selectedIdsString }}</p>
  </div>
</template>

使用字符串格式

如果接口需要逗号分隔的字符串格式:

<script setup lang="ts">
const selectedIds = ref(''); // 初始值为字符串
</script>

<template>
  <StoreSelectWithApi
    v-model="selectedIds"
    value-type="string"
    :headers="headers"
    :permission-ids="permissionIds"
  />
</template>

注意事项

  1. headers 配置:请求头中需要包含完整的业务上下文(Token、员工ID等),这些信息无法在组件内部获取,需要外部传入。

  2. permission-ids 参数:用于权限过滤,只返回用户有权限访问的门店。如果为空数组或未传,则返回所有门店。

  3. value-type 输出格式

    • array(默认):输出数组格式 ['74', '75', '77']
    • string:输出逗号分隔字符串 '74,75,77'
  4. 竞态处理:组件内部已处理快速切换时的请求竞态问题,确保最终显示的是最新请求的结果。

  5. 错误处理:建议监听 @error 事件以便在请求失败时进行适当处理。