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

bmfe-cms-template

v1.0.1

Published

本木后台系统模板

Readme

使用安装

权限不足请使用 sudo

BM init -f cms-template 创建名称 版本 cnpm install

功能介绍

后台系统模板是基于iview组件的,支持所有iview组件以及全局组件。 如果项目规模够大,请直接 use(iview)。 如果项目很小,请务必在业务中 import 对应组件,这样会减少打包体积。

目录结构

·
|-- .gitignore          (需要忽略的文件:/node_modules、/bower_components、/dist)
|-- .babelrc            (babel 编译的文件)
|-- .eslintrc           (js 语法检测文件)
|-- config.js           (BM 配置文件)
|-- node_modules        (node 依赖)
|-- html                (对外输出的页面文件)
|-- dist                (对外输出的 js/css 资源文件)
|-- src                 (工程目录)
    |-- css                 (css 文件目录)
    |-- html                (html 文件目录)
    |-- mock                (mock)
    |-- js                  (js 文件目录)
        |-baseLibs          (此文件一般是外部一些大型的资源文件,且这个文件不会走编译)
        |-common            (公共模块具有完整的页面周期的行为,如:登录)
        |-components        (全局公共组件)
        |-config            (公共配置文件)
        |-directive         (全局指令)
        |-routers           (路由配置)
        |-pages             (页面的业务)
        |-service           (发送请求的服务方法,字段映射配置)
        |-store             (全局的 store 如登录信息)
        |-utils             (工具类函数)
        |-app.vue           (根节点)
        |-main.js           (业务的根节点 js)
        |-vendor.js         (公共的资源文件引入)

修改配置文件

修改文件目录中的src\js\config\index.js

// 独立开发时,mock 服务的路径
export const TESTPATH = '//fe.benmu-health.com'
// 接口拦截到需要跳转登录页面的 code
export const LOGIN_CODE = 1000
// 需要微信认证
export const WXCONFIG = true
// 请求超时时间
export const AJAXTIMEOUT = 20000
// 请求是否会发送本地的请求
export const LOCAL_AJAX = false

export const DEBUG = {
    // 请求打印
    req: false,
    // 响应打印
    res: false,
    //开启vconsole
    vconsole: false,
    // 开启vue debug
    v_debug: true,
    // 开启vue devtools
    v_devtools: true
}

将上面的配置文件,配置成适用于当前项目的参数

启动

BM server // 启动该项目,该项目会自动打开浏览器

ajax 和 常量使用规范 ( Service 层)

底层使用axios,需要了解API自行了解axios库,需要在service中配置好自己的请求发送参数如

// order.js
{
    // 接口名称,调用时会用到,注意重复
    name: 'detail',
    // 发送请求类型
    method: 'GET',
    // 接口描述
    desc: '医生个人信息接口',
    // 本地地址
    localPath: '/test/sectionDoctor/detail',
    // 线上地址
    path: '/mobile/wx/individualDoc/queryById',
    // 发送出去的参数,自动会截取相应的参数,即使你传了很多用不到的参数也没关系。
    // 如果不传定义好的参数,则会把下面的默认值带上发出去
    params: {
        key: value
    }
}

Service 层大概结构如下:

|-service                  (服务层)
    |-apis                 (请求集合)
        |-index.js         (主页配置)
        |-order.js         (订单模块)
    |-consts               (常量集合)
        |-index.js         (主页配置)
        |-order.js         (订单模块)

Service 层文件命名尽量保持对应,抽象我们的业务,这样我们可以减少很多变量和请求方法的冗余代码,order 模块在 index 中进行配置如下:

import { Apior } from 'Utils/apior'
// 报告查询
import order from './order'

export default new Apior({
    order
})['_apiMap']

这样 Apior 会自动用 order 来作为前缀,做一层命名空间,放到$service中。

业务中调用方式

this.$apis['order/detail']({
    key: value
}, {
    // 额外的参数 如:header
    noShowDefaultError: true // 不弹出默认的报错提示
}).then((data) => {
    // 已经过滤了 resData.data,可直接使用,无需判断
    // 具体的过滤器在 config/ajax 中
}, () => {
    // 失败的回调,错误已经自动报了,一般无需关心
});

如果你想单独发请求也没关系

GLOBAL.$ajax.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
 
// Optionally the request above could also be done as 
GLOBAL.$ajax.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })

GLOBAL.$ajax.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

对于常量,建议都使用大写。

//service/consts/other 目录结构
export default [{
    name: 'MENU', 
    value: [{
        id: 1,
        parentId: 0,
        label: '指标管理',
        route: '/tomato/target',
        show: true,
        order: 1,
        icon: 'arrow-graph-up-right',
    }, {
        id: 2,
        parentId: 0,
        order: 1,
        label: 'IDEA管理',
        route: '/tomato/idea',
        show: true,
        icon: 'ios-flower'
    }, {
        id: 3,
        parentId: 0,
        order: 1,
        label: '项目管理',
        route: '/tomato/project',
        show: true,
        icon: 'ios-briefcase'
    }, {
        id: 4,
        parentId: 0,
        order: 1,
        label: '项目报告',
        route: '/tomato/report',
        show: true,
        icon: 'ios-paper'
    }]
}]

这样我们在业务中使用的时候 this.$consts['other/MENU'] 便可以拿到,如果不在业务中:

import CONSTS from 'Service/consts'

console.log(CONSTS['other/MENU'])

也是完全可以拿到的,apis 也是。

router 命名规范

命名尽量遵循父级路由.当前路由的规则,一般路由路径不能超过三层,需要考虑效率问题

路由配置文件在 config/router 中,路由配置规则尽量遵循父子路由的关系,子路由都配置在父路由的 children 属性中,配置自路由的好处是在打开子路由返回的时候,父级路由的转台都还保存着

订单模块,有搜索条件的页面,搜索结果列表页面,搜索详情页面,构造出来的路由如下:

{
    path: '/order',
    component: Order,
    children: [{
        path: '/search',
        component: Search
    },{
        path: '/list',
        component: List,
        children: [{
            path: '/detail',
            component: Detail
        }]
    }]
}

父路由中模板文件也需要增加对应的自路由组件

<transition name="child">
    <router-view></router-view>
</transition>

store 使用( vuex

在通常的业务中,通常会把所有 store 都放到一个目录下,通过 modules 来拆分,现实很美好,科室后台系统这种业务,其实模块与模块之间的交互并不高,可以说是基本没有,所以随着业务的增长,store 下的对应的module越来越多,在 storepages 中来回切换就非常耗时。

好在 [email protected] 之后添加了 registerModuleunregisterModule 2个方法,让我们能把 store 中的 module 分散到对应的业务当中。

使用都是跟着路由的生命周期完成的,这里并不是真正的把store移除,实质上只是在当前的store树上解除了引用关系,下来再次加回来的时候状态都还在。如果想要每次都是新的状态,应该在state的声明的时候返回一个纯函数,每次使用的时候都是新的状态。

beforeRouteEnter(to, from, next) {
    store.install()
    next()
},
beforeRouteLeave(to, from, next) {
    store.uninstall()
    next()
}

actions 命名规范

由于项目中的 store 是合并到一个 store 上,获取 actions 的方式又是通过 mapActions,所以需要做好命名的区分。

一般我们是用,由于有命名空间,在多个模块间共用的actions不能重复:

DO_something	GET_HOSLIST

getter 命名规范

由于项目中的 store 是合并到一个 store 上,获取 getter 的方式又是通过 mapGetters,所以需要做好命名的区分

有了命名空间,一般是不会重复,一般我们是用:

...mapGetters('tab', ['activeTab', 'showMask'])

pages 文件夹下命名规范

原子命名和尽量全部都小写

比如有一个目录结构是:

医院管理
    医院列表

对应的 page 下的文件目录结构就应该类似如下:

hosmanage
	list

//或者

hosmanage
    hoslist

这样看起来会使整个目录整洁,尽量少的文件夹名,也会跟容易让人记得住。

模块的构成

当划分出一个子模块之后,我们不能简单粗暴的用一个 .vue 文件把所有业务逻辑完成,除非你的模块功能非常单一,其他的情况,我们希望把模块进行划分,由多个子 component 组成,划分的粒度也需要自己掌握,粒度越细越灵活,但也意味着 component 间的交互会变得复杂。

比如我们划分出了三个模块 headerlistfooter,我们的目录结构按照上面的继续写就会是

	hosManager
		hosList
			index.vue
            store
                index.js
                actions.js
                modules
                    header.js
                    list.js
                    footer.js
            components
                header.vue
                list                // 如果业务非常复杂可做一下拆分
                    index.vue		// 参照 vue2 官网说明,这个文件是作为引入其他文件存在
                    index.js	    // js 逻辑文件
                    index.scss		// 样式文件
                    index.html		// html 文件
                footer.vue

hosList/index.vue 仅仅是作为组织文件,将三个子模块引入,并且做好架子的角色,如 html 中的布局,如果 component 间需要事件交互,这个文件也可以充当中介者的角色。

beacon 的使用

发送beacon记录打点,发送到hive中,各业务再去找对应的后端做查询,具体文件在utils/beacon.js

$Beacon(key, page(可缺省), {
    // 保留参数,没有特殊需求这些参数不能覆盖 openId  userId  时间戳
    extra_[a-e]: '额外参数'
    // 额外需要记录的数据
    extra_[d-g]: '额外参数'
});

$Beacon('WX_DLZC0000005');
$Beacon('WX_DLZC0000005', '登录页', {
    extra_d: '注册业务'
});
$Beacon('WX_DLZC0000005', {
    extra_d: '注册业务'
});

vue 使用规范

组件交互

兄弟组件

父组件向子组件传递数据:
props

子组件向父组件抛出事件:
vm.$emit('xxx')

父组件用v-on:xxx="func"来接子组件触发的事件和暴露的数据

虽然vue还提供了$ref$parent来让我们访问其他组件的数据和方法,但为了工程的可维护性,让我们的数据变化的追踪变得有规律可循,我们应尽量避免他们的使用

非兄弟组件 有时候非父子关系的组件也需要通信。在简单的场景下,使用一个空的 Vue 实例作为中央事件总线

业务简单:

var bus = new Vue()

// 触发组件 A 中的事件
bus.$emit('id-selected', 1)

// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})

业务复杂:

请直接使用Vuex
actions中只做异步和分发
commit应该按state结构来细分 尽量避免一个commit修改多个state

格式

如果不给代码做格式化就是等于代码没有写。请原谅我是 tab = 4空格档,就必须是这样的