
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@~crazy/tablex
Advanced tools
tablex 是一个基于 Vue 、ELement UI 、 Axios 实现的一个 table 组件,可根据配置快速实现增删改查业务
npm i @~crazy/tablex -S
// 引入
import tablex from '@~crazy/tablex'
// 安装
Vue.use(tablex, {
// 全局配置
});
// 全局访问 tablex 对象
Vue.$tablex;
| 属性名 | 说明 |
|---|---|
| version | 版本号 |
| api | 接口对象,根据 request.map 配置生成的接口函数 |
| responseFormat | 全局请求响应数据格式化回调 |
| options | 配置 |
| type | 类型对象 |
| 配置名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| i18n | Object | - | Vue I18n 实例,实现组件国际化 |
| locales | Object | - | 国际化语言列表 |
| store | Obejct | - | Vue Store 实例 |
| request | Object | - | 请求配置 |
| request.map | Object | - | 接口地图 |
| request.axios | Object | - | Axios 配置 |
| request.axios.authorizationKey | String | Authorization | 在请求头携带的 Token 认证名称 |
| request.axios.defaults | Object | - | 同 Axios 配置 |
| request.axios.defaults.timeout | Number | 1000 * 5 | 请求超时毫秒数 |
| request.axios.defaults.withCredentials | Boolean | true | 跨域请求是否需要使用凭证 |
| request.axios.defaults.headers | Object | { 'Content-Type': 'application/json;charset=UTF-8' } | 请求头配置 |
| request.axios.interceptors | Object | - | 自定义拦截处理回调 |
| request.axios.interceptors.request | Array[Function] | [] | 请求处理回调列表 |
| request.axios.interceptors.response | Array[Function] | [] | 响应处理回调列表 |
| table | Object | - | Table 组件配置 |
| table.requestFormat | Function | - | 全局请求参数格式化回调 |
| table.responseFormat | Function | - | 全局响应数据格式化回调 |
| table.deleteRequestFormat | Function | - | 全局删除请求参数格式化回调 |
| table.delete | Obejct | - | 删除行动配置 |
| table.delete.key | String | id | 发送请求时参数的名称 |
| table.delete.paramKey | String | id | 获取参数时数据列的名称 |
| table.paging | Obejct | - | 分页配置 |
| table.paging.paramsFormat | Function | - | 分页参数格式化回调 |
Vue.use(tablex, {
// Vue I18n
i18n: null,
// 国际化语言列表
locales: {},
// Vue Store
store: null,
// 请求配置
request: {
// 接口地图
map: {},
// axios 配置
axios: {
authorizationKey: 'Authorization',
// 全局配置
defaults: {
// 请求超时毫秒数
timeout: 1000 * 5,
// 跨域请求是否需要使用凭证
withCredentials: true,
// 请求头配置
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
},
// 自定义拦截处理回调
interceptors: {
request: [],
response: [],
},
},
},
table: {
// 全局请求参数格式化回调
requestFormat: null,
// 全局响应数据格式化回调
responseFormat: null,
// 全局删除请求参数格式化回调
deleteRequestFormat: null,
// 删除
delete: {
// 参数键
key: 'id',
// 获取参数值的键
paramKey: 'id',
},
// 分页
paging: {
// 分页参数格式化回调
paramsFormat: null,
},
},
})
格式为 JSON,接口集合可多层嵌套
{
接口名称:'请求方式,GET / POST',
// 如 POST : http://XXXX/login
login: 'post',
自定义接口函数名称: ['请求方式,GET / POST', '接口名称'],
// 如 POST :http://XXXX/login
// 自定义接口函数名为 Login
Login: ['post', 'login'],
接口集合名(以开头的名称命名):{},
// 如有以下以 system 开头的接口:
// POST:http://XXXX/system/setUser
// GET:http://XXXX/system/getUserData
system: {
setUser: 'post',
getUserData: 'get',
},
接口集合名(不以开头的名称命名):{},
// 如有以下以 system 开头的接口:
// POST:http://XXXX/system/setUser
// GET:http://XXXX/system/getUserData
SystemData: {
// 设置默认接口前缀
default: 'system',
setUser: 'post',
getUserData: 'get',
},
}
import tablex from '@~crazy/tablex';
// 配置
Vue.use(tablex, {
request: {
map: {
// 设置用户数据
setUserData: ['post', 'set_user_data'],
},
},
});
// 通过 api 属性访问
// 获取请求实例
const req = this.$tablex.api.setUserData({
// 传递参数
nickname: 'admin',
address: 'xxxxxx',
});
// 发送请求
req.send({
// 此处可覆盖参数
}).then(res => {
// 请求成功
});
// 取消请求
req.cancel();
为了实现各种数据类型在界面上的展示(Visible)、编辑(Edit),在此定义了几种数据类型(文档中为了不与原生属性混淆,使用 tablex 作为前缀):
基类,所有类型均继承此类。目前有以下类:
| 类型 | 继承于 | 说明 |
|---|---|---|
| tablex.String | tablex.Type | 字符串 |
| tablex.JSON | tablex.Type | json 对象,尚未实现 |
| tablex.Double | tablex.Type | 浮点数 |
| tablex.Password | tablex.String | 密码 |
| tablex.Date | tablex.Type | 日期,YYYY-MM-DD HH:mm:ss |
| tablex.Time | tablex.Date | 时间点,HH:mm:ss |
| tablex.DateRange | tablex.Type | 时间区间,YYYY-MM-DD HH:mm:ss - YYYY-MM-DD HH:mm:ss |
| tablex.Select | tablex.Type | 下拉选择器 |
| tablex.Radio | tablex.Select | 单选 |
| tablex.Checkbox | tablex.Radio | 多选 |
不同类型函数传参有所不同
| 参数 | 类型 | 默认值 | 适用类型 | 参数顺序 | 说明 |
|---|---|---|---|---|---|
| value | Any | - | 所有 | - | 原始数据值,不同类型会根据 value 作出不同的显示方式 |
| formatString | String | YYYY-MM-DD HH:mm:ss | tablex.Date | (value, formatString) | 格式化显示方式,不包含 Edit 状态 |
| HH:mm:ss | tablex.Time | ||||
| YYYY-MM-DD HH:mm:ss | DateRange | (start, end, formatString) | |||
| start | String/Number/Date | - | tablex.DateRange | (start, end, formatString) | 开始时间 |
| end | String/Number/Date | - | tablex.DateRange | (start, end, formatString) | 结束时间 |
| options | Array[Object({ lable: String, value: String, })] | [] | tablex.Select | (value, options) | 数据列表 |
| tablex.Radio | |||||
| tablex.Checkbox |
获取类型编辑器,编辑器可修改数据值返回到数据源中。多用于表单提交新增、修改功能
| 参数 | 类型 | 默认值 | 适用类型 | 参数顺序 | 说明 |
|---|---|---|---|---|---|
| vue | Vue | - | 所有 | - | Vue 实例对象 |
| props | Object | - | tablex.String | (vue, props) | 同 el-input 组件参数 |
| tablex.Password | |||||
| tablex.Double | 同 el-input-number 组件参数 | ||||
| tablex.Date | 同 el-date-picker 组件参数 | ||||
| tablex.DateRange | |||||
| tablex.Time | 同 el-time-picker 组件参数 | ||||
| tablex.Select | 同 el-select 组件参数 | ||||
| tablex.Radio | 同 el-radio 组件参数 | ||||
| tablex.Checkbox | 同 el-checkbox 组件参数 |
将原始数据转换为显示状态
| 参数 | 类型 | 默认值 | 适用类型 | 参数顺序 | 说明 |
|---|---|---|---|---|---|
| vue | Vue | - | 所有 | - | Vue 实例对象 |
| placeholder | String | - | tablex.String | (vue, placeholder) | 占位文本 |
| tablex.Password | |||||
| precision | Number | 0 | tablex.Double | - | 精度 |
| formatString | String | - | tablex.Date | (vue, formatString) | 格式化显示方式,为空时使用实例的 formatString 值 |
| tablex.Time | |||||
| tablex.DateRange |
将原始数据转换为 JSON 对象
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| key | String | - | 原始值的键 |
| keyAlias | String/Array[String] | - | 需要将原始值转化的别名键 |
| value | Any | - | 原始值 |
| 配置名 | 类型 | 说明 |
|---|---|---|
| options | Object | tablex 组件配置,tablex 依靠此配置工作 |
| tablex | tablex 实例 | 父级 tablex 实例,在多个 tablex 嵌套使用插槽时传入 |
<template>
<!-- 引用 -->
<el-tablex :options="options"></el-tablex>
</template>
<script>
export default {
computed: {
options: {
// tablex 组件配置
},
},
};
</script>
<template>
<!-- 引用 -->
<el-tablex :options="options">
<!-- 嵌套的 tablex 使用插槽,options 与 tablex 属性需要使用作用域变量传入 -->
<el-tablex slot="table-details" slot-scope="scope" :options="scope.options" :tablex="scope.tablex"></el-tablex>
</el-tablex>
</template>
<script>
export default {
computed: {
options: {
// 省略部分代码...
actions: {
// 查看详情列表
details: {
table: {
// 此处为嵌套 tablex
},
},
},
},
},
};
</script>
| 配置名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| multiple | Boolean | false | 开启列表多选功能 |
| model | Object(tablex.Model) | - | 数据模型 |
| data | Array | null | 列表数据 |
| actions | Object(tablex.Action) | - | 行为列表 |
| actionParams | Object | - | 全局行为请求时附带参数 |
| requestFormat | Function | null | 全局请求参数格式化回调 |
| responseFormat | Function | null | 全局响应数据格式化回调 |
| deleteRequestFormat | Function | null | 全局删除请求参数格式化回调 |
| condition | Object | - | 查询条件 |
| condition.showButton | Boolean | true | 显示查询按钮 |
| condition.updateOnChange | Boolean | false | 查询条件改变立即更新 |
| condition.toUrl | Boolean | true | 将条件参数附加到浏览器 url |
| condition.list | Array[tablex.Model] | [] | 查询列表 |
| operation | Object | - | 列表操作 |
| operation.title | String | null | 操作栏显示的标题文本 |
| operation.width | String | null | 操作栏的宽度,需要带 px 或 % |
| operation.toExpand | Boolean | true | 当存在展开行时将操作加入到行内 |
| operation.list | Array[tablex.Operation] | [] | 操作列表 |
| paging | Object | - | 分页 |
| paging.visible | Boolean | true | 显示分页 |
| paging.describe | Boolean | true | 显示描述 |
| paging.toUrl | Boolean | true | 将分页参数附加到浏览器 url |
| paging.paramsFormat | Function | null | 分页参数格式化回调 |
| props | Object | - | 额外参数 |
| props.table | Object | - | 同 el-table 组件参数 |
| props.table.stripe | Boolean | true | 是否为斑马纹 table |
| props.pagination | Object | - | 同 el-pagination 组件参数 |
| props.pagination.background | Boolean | true | 是否为分页按钮添加背景色 |
| props.pagination.small | Boolean | true | 是否使用小型分页样式 |
| props.pagination.pageSize | Number | 10 | 每页显示条目个数 |
| props.pagination.currentPage | Number | 1 | 当前页数 |
| props.pagination.pageSizes | Array[Number] | [5, 10, 20, 30, 40, 50, 100] | 每页显示个数选择器的选项设置 |
目前 model 、 condition.list 这两个组件配置项使用此模型配置,其中 model又分为 Visible(展示) 模式 与 Edit(编辑) 模式,但不是所有配置都适用。为方便阅读理解,在下面列表的适用配置项会用 model 、 condition 表示:
| 配置名 | 类型 | 默认值 | 适用配置项 | 适用 model 模式 | 说明 |
|---|---|---|---|---|---|
| type | String | tablex.String | 所有 | 所有 | 对应 tablex 数据类型 此处额外多两个类型: $index:返回行号 expand:展开行,同 el-table 展开行功能,只适用于 Visible 模式。注意:一个数据模型里最多只能存在一个 expand |
| key | String | - | condition | - | 数据键 |
| keyAlias | String/Array[String] | null | 所有 | 所有 | 数据键别名 |
| data | Array[Any] | - | 所有 | 所有 | 数据来源,等同于 tablex.type 构造函数的传参, 从第二位开始 |
| label | String | - | 所有 | 所有 | 组件显示的标签 |
| slots | Function | null | 所有 | 所有 | 插槽自定义函数 |
| format | Function | null | 所有 | 所有 | 格式化数据回调 |
| props | Object | - | 所有 | 所有 | 同对应的数据类型所对应的 element-ui 组件 |
| visible | Boolean | true | 所有 | Visible | 是否显示 |
| model | Object(tablex.Model) | null | model | Visible | 在 type 为 expand 时适用,格式同 tablex 组件配置的 model |
| editOpts | Object | - | 所有 | Edit | 编辑/输入时的选项 |
| editOpts.vibible | Boolean | true | 所有 | Edit | 是否显示 |
| editOpts.readonly | Boolean | false | 所有 | Edit | 是否只读 |
| editOpts.watch | Function | null | 所有 | Edit | 值监听回调函数 |
| updateOnChange | Boolean | false | condition | - | 此查询条件值改变后立即请求更新 |
<template>
<el-tablex :options="options"></el-tablex>
</template>
<script>
export default {
computed: {
options(){
return {
// model 示例
model: {
// 使用 type 为 $index 显示行号
$index: {
type: '$index',
},
// 此处 name 对应 配置里的 key
name: {
// type 默认为 tablex.String,
type: 'String',
label: '姓名',
},
sex: {
type: 'Radio',
label: '性别',
// 由于性别需要单选,这里传入数据来源
data: [
// 第一个参数,性别列表,对应 tablex.Raido 构造函数的 options 参数
[{
label: '男',
// 注意此处 value 值必须为 String 类型
value: '0',
}, {
label: '女',
value: '1',
}],
],
},
// 使用展开行,因为 expand 在一个数据模型里最多只能存在一个,所以可以直接使用 key 作为 type 类型
expand: {
model: {
age: {
label: '年龄',
},
address: {
label: '地址',
props: {
// 使用多行文本框
type: 'textarea',
},
},
},
},
},
// condition 查询条件示例
condition: {
list: [{
key: 'name',
label: '姓名',
}],
},
};
},
},
};
</script>
| 配置名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| key | String | - | 操作唯一的键,可以通过 operation-${key} 使用插槽 |
| label | String | - | 操作显示的文本内容,使用插槽时无效 |
| trigger | Function | - | 点击时触发的回调。使用插槽时无效,需自定义交互 |
| visible | Boolean/Function | true | 是否显示此操作,回调中可获取到当前数据用于逻辑判断 |
<template>
<el-tablex :options="options">
<!-- 使用插槽 -->
<el-button slot="operation-delete" slot-scope="scope" @click="deleteRow(scope)" type="danger" icon="el-icon-delete-solid" circle></el-button>
</el-tablex>
</template>
<script>
export default {
computed: {
options() {
return {
operation: {
list: [{
key: 'edit',
label: '修改',
trigger: scope => {
// 通过 scope.row 可以获取当前操作的数据
},
}, {
// 使用插槽
key: 'delete',
}],
},
};
},
},
methods: {
deleteRow(scope) {
// 通过 scope.row 可以获取当前操作的数据
},
},
};
</script>
tablex 所有的交互都是围绕 action 开展的,通过 action 驱动增删改查及各种操作
tablex 内置了四种常用的 action :
| 配置名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| method | String/Function | - | 此行为调用的服务端接口或自定义回调函数 |
| params | Object | null | 调用时附带的参数 |
| before | Function | - | 调用前请求参数格式化回调 |
| after | Function | - | 调用后响应数据格式化回调 |
| editor | Object | - | 表单弹窗配置 |
| editor.customClass | String | - | 自定义弹窗类名 |
| editor.title | String | - | 弹窗标题 |
| editor.width | String | - | 弹窗宽度,px 或 % |
| editor.props | Object | - | 弹窗组件配置,同 el-dialog |
| editor.labelWidth | String | - | 表单标签宽度,px 或 % |
| editor.model | Object(tablex.Model) | - | 表单数据模型 |
| editor.sendParams | Array[String] | - | 定义发送参数列表 |
| table | Object | - | 表格弹窗配置 |
| table.customClass | String | - | 自定义弹窗类名 |
| table.title | String | - | 弹窗标题 |
| table.width | String | - | 弹窗宽度,px 或 % |
| table.props | Object | - | 弹窗组件配置,同 el-dialog |
| table.options | Object(tablex.Options) | - | tablex 配置选项 |
| table.on | Object | - | 事件绑定 |
<template>
<el-tablex :options="options"></el-tablex>
</template>
<script>
import axios from 'axios';
export default {
computed: {
options() {
return {
operation: {
list: [{
// 更新状态操作按钮
key: 'status',
trigger: scope => scope.action('updateStatus', scope, {
id: scope.row.id,
}),
}, {
// 查看详情列表操作按钮
key: 'details',
trigger: scope => scope.action('getDetails', scope, {
id: scope.row.id,
}),
}],
},
actions: {
// 查询数据
select: {
// 此接口为注册 tablex 时由全局配置 request.map 传入
method: 'getData',
},
// 自定义 action
// 更新状态
updateStatus: {
// 使用自定义回调
method: async (params, scope) => {
// 自定义请求
const res = await axios.post('http://XXXX/updateStatus', {
params,
});
// 响应数据必须返回
return res;
},
},
// 查看详情列表
getDetails: {
// 使用表格展示
table: {
options: {
actions: {
select: {
method: 'getDetails',
},
},
},
},
},
},
};
},
},
};
</script>
| 事件名 | 说明 | 参数 | 参数说明 |
|---|---|---|---|
| action | 当 tablex 有 action 执行时触发 | name | 行为名称 |
| close | 当前组件窗口被销毁 | tablex | 当前 tablex |
| name | 行为名称 | ||
| params | 多个参数,根据实际情况获取 | ||
| condition-close | 条件查询被关闭时触发 | - | - |
| selection-change | 当前表格选择的数据发生变化 | value | 当前选择数据集合 |
| 插槽名 | 说明 |
| default | 拓展操作栏内容 |
| insert | 自定义新增操作按钮内容 |
| delete | 自定义多选删除操作按钮内容 |
| column-${key} | 自定义表格列的内容 |
| operation-${key} | 自定义表格操作列的内容 |
| form-${key} | 自定义弹窗表单项内容,多个弹窗时存在相同 key 的项可以使用 actionName 区分 |
| ${actionName}-from-${key} | |
| ${actionName}-dialog-footer | 拓展弹窗底部内容 |
| ${actionName}-dialog-footer-cancel | 自定义弹窗底部取消按钮内容 |
| ${actionName}-dialog-footer-confirm | 自定义弹窗底部确认按钮内容 |
| table-${actionName} | 自定义弹窗的嵌套 tablex 内容 |
import 'babel-polyfill';
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import VueI18n from 'vue-i18n';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import tablex from '@~crazy/tablex';
Vue.use(VueI18n);
Vue.use(ElementUI, {
size: 'mini',
});
const i18n = new VueI18n({
locale: 'zh-cn',
silentTranslationWarn: true,
messages: {
'zh-cn': {},
en: {},
},
});
Vue.use(tablex, {
i18n,
request: {
map: {
getApiList: 'get',
getApiData: 'get',
},
axios: {
defaults: {
baseURL: 'https://crazy-gt.com/crazy-api/',
},
},
},
table: {
responseFormat: res => {
return {
...res,
total: res.total || res.data.length,
};
},
},
});
Vue.config.productionTip = false
new Vue({
router,
store,
i18n,
render: h => h(App)
}).$mount('#app')
<template>
<el-tablex :options="options">
<!-- 自定义数据源内容 -->
<el-tag v-if="scope.row.data_source" slot="column-data_source" slot-scope="scope">{{scope.row.data_source}}</el-tag>
<!-- 自定义是否为列表内容 -->
<el-tag slot="column-is_list" slot-scope="scope" :type="scope.row.is_list ? 'success' : 'danger'">{{scope.row.is_list}}</el-tag>
<!-- 自定义嵌套 tablex 内容 -->
<el-tablex slot="table-details" slot-scope="scope" :options="scope.options" :tablex="scope.tablex">
<div slot="column-content" slot-scope="scope" class="column-content">{{scope.row.content}}</div>
</el-tablex>
<el-tablex slot="table-list" slot-scope="scope" :options="scope.options" :tablex="scope.tablex">
<!-- 自定义数据源内容 -->
<el-tag v-if="scope.row.data_source" slot="column-data_source" slot-scope="scope">{{scope.row.data_source}}</el-tag>
<!-- 自定义是否为列表内容 -->
<el-tag slot="column-is_list" slot-scope="scope" :type="scope.row.is_list ? 'success' : 'danger'">{{scope.row.is_list}}</el-tag>
</el-tablex>
</el-tablex>
</template>
<script>
export default {
computed: {
model() {
return {
id: {},
no: {
label: '编号',
},
name: {
label: '名称',
},
data_source: {
label: '数据源',
},
is_list: {
type: 'Radio',
label: '是否为列表',
data: [
[{
label: '否',
value: false,
}, {
label: '是',
value: true,
}],
],
},
};
},
options() {
return {
multiple: true,
model: this.model,
operation: {
list: [{
key: 'details',
label: '查看详情',
trigger: scope => scope._self.action('details', scope, scope.row),
visible: scope => !scope.row.is_list,
}, {
key: 'list',
label: '列表详情',
trigger: scope => scope._self.action('list', scope, scope.row),
visible: scope => scope.row.is_list,
}],
},
actions: {
select: {
// 使用回调函数自定义数据
method: async ({
page,
size,
}) => {
const {
data,
} = await this.$tablex.api.getApiList().send();
return {
data: [...data].splice((page - 1) * size, size),
total: data.length,
};
},
},
list: {
table: {
title: '列表详情',
options: {
model: this.model,
actions: {
select: {
method: params => ({
data: params.list,
}),
},
},
paging: {
visible: false,
},
},
},
},
details: {
// 嵌套的 tablex
table: {
title: '查看详情',
options: {
model: {
no: {
label: '编号',
},
type: {
label: '类型',
},
content: {
label: '数据内容',
},
},
actions: {
select: {
method: 'getApiData',
sendParams: ['id'],
},
},
paging: {
visible: false,
},
},
},
},
},
};
},
},
}
</script>
<style lang="scss">
.column-content {
background: #333;
color: #FFF;
padding: 10px;
border-radius: 4px;
}
</style>



FAQs
tablex
We found that @~crazy/tablex demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.