@tmagic/table 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ import type { DefineComponent, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes, PropType } from 'vue';
2
+ declare const _default: DefineComponent<{
3
+ data: {
4
+ type: ArrayConstructor;
5
+ require: boolean;
6
+ };
7
+ columns: {
8
+ type: PropType<any[]>;
9
+ require: boolean;
10
+ default: () => never[];
11
+ };
12
+ /** 合并行或列的计算方法 */
13
+ spanMethod: {
14
+ type: PropType<(data: {
15
+ row: any;
16
+ column: any;
17
+ rowIndex: number;
18
+ columnIndex: number;
19
+ }) => [number, number]>;
20
+ };
21
+ fetch: {
22
+ type: BooleanConstructor;
23
+ default: boolean;
24
+ };
25
+ /** Table 的最大高度。合法的值为数字或者单位为 px 的高度 */
26
+ bodyHeight: {
27
+ type: (StringConstructor | NumberConstructor)[];
28
+ };
29
+ /** 是否显示表头 */
30
+ showHeader: {
31
+ type: BooleanConstructor;
32
+ };
33
+ /** 空数据时显示的文本内容 */
34
+ emptyText: {
35
+ type: StringConstructor;
36
+ };
37
+ /** 是否默认展开所有行,当 Table 包含展开行存在或者为树形表格时有效 */
38
+ defaultExpandAll: {
39
+ type: BooleanConstructor;
40
+ default: boolean;
41
+ };
42
+ rowkeyName: {
43
+ type: StringConstructor;
44
+ };
45
+ /** 是否带有纵向边框 */
46
+ border: {
47
+ type: BooleanConstructor;
48
+ default: boolean;
49
+ };
50
+ }, unknown, {
51
+ editState: any[];
52
+ }, {
53
+ tableData(): unknown[];
54
+ selectionColumn(): any;
55
+ hasBorder(): boolean;
56
+ }, {
57
+ sortChange(data: any): void;
58
+ selectHandler(selection: any, row: any): void;
59
+ selectAllHandler(selection: any): void;
60
+ selectionChangeHandler(selection: any): void;
61
+ toggleRowSelection(row: any, selected: boolean): void;
62
+ toggleRowExpansion(row: any, expanded: boolean): void;
63
+ clearSelection(): void;
64
+ objectSpanMethod(data: any): [number, number] | (() => {
65
+ rowspan: number;
66
+ colspan: number;
67
+ });
68
+ }, ComponentOptionsMixin, ComponentOptionsMixin, ("afterAction" | "sort-change" | "select" | "select-all" | "selection-change")[], "afterAction" | "sort-change" | "select" | "select-all" | "selection-change", VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
69
+ data: {
70
+ type: ArrayConstructor;
71
+ require: boolean;
72
+ };
73
+ columns: {
74
+ type: PropType<any[]>;
75
+ require: boolean;
76
+ default: () => never[];
77
+ };
78
+ /** 合并行或列的计算方法 */
79
+ spanMethod: {
80
+ type: PropType<(data: {
81
+ row: any;
82
+ column: any;
83
+ rowIndex: number;
84
+ columnIndex: number;
85
+ }) => [number, number]>;
86
+ };
87
+ fetch: {
88
+ type: BooleanConstructor;
89
+ default: boolean;
90
+ };
91
+ /** Table 的最大高度。合法的值为数字或者单位为 px 的高度 */
92
+ bodyHeight: {
93
+ type: (StringConstructor | NumberConstructor)[];
94
+ };
95
+ /** 是否显示表头 */
96
+ showHeader: {
97
+ type: BooleanConstructor;
98
+ };
99
+ /** 空数据时显示的文本内容 */
100
+ emptyText: {
101
+ type: StringConstructor;
102
+ };
103
+ /** 是否默认展开所有行,当 Table 包含展开行存在或者为树形表格时有效 */
104
+ defaultExpandAll: {
105
+ type: BooleanConstructor;
106
+ default: boolean;
107
+ };
108
+ rowkeyName: {
109
+ type: StringConstructor;
110
+ };
111
+ /** 是否带有纵向边框 */
112
+ border: {
113
+ type: BooleanConstructor;
114
+ default: boolean;
115
+ };
116
+ }>> & {
117
+ onAfterAction?: ((...args: any[]) => any) | undefined;
118
+ "onSort-change"?: ((...args: any[]) => any) | undefined;
119
+ onSelect?: ((...args: any[]) => any) | undefined;
120
+ "onSelect-all"?: ((...args: any[]) => any) | undefined;
121
+ "onSelection-change"?: ((...args: any[]) => any) | undefined;
122
+ }, {
123
+ columns: any[];
124
+ fetch: boolean;
125
+ showHeader: boolean;
126
+ defaultExpandAll: boolean;
127
+ border: boolean;
128
+ }>;
129
+ export default _default;
@@ -0,0 +1,29 @@
1
+ import type { DefineComponent, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes, PropType } from 'vue';
2
+ import { ColumnConfig } from './schema';
3
+ declare const _default: DefineComponent<{
4
+ config: {
5
+ type: PropType<ColumnConfig>;
6
+ default: () => {};
7
+ required: true;
8
+ };
9
+ editState: {
10
+ type: ObjectConstructor;
11
+ default: () => void;
12
+ };
13
+ }, {
14
+ formatter: (item: ColumnConfig, row: any) => any;
15
+ }, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, Record<string, any>, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
16
+ config: {
17
+ type: PropType<ColumnConfig>;
18
+ default: () => {};
19
+ required: true;
20
+ };
21
+ editState: {
22
+ type: ObjectConstructor;
23
+ default: () => void;
24
+ };
25
+ }>>, {
26
+ config: ColumnConfig;
27
+ editState: Record<string, any>;
28
+ }>;
29
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { App } from 'vue';
2
+ export { default as MagicTable } from './Table.vue';
3
+ declare const _default: {
4
+ install(app: App): void;
5
+ };
6
+ export default _default;
@@ -0,0 +1,38 @@
1
+ import { FormConfig, FormValue } from '@tmagic/form';
2
+ export interface ColumnActionConfig {
3
+ type?: 'delete' | 'copy' | 'edit';
4
+ display?: (vm: any, row: any) => boolean;
5
+ text: string;
6
+ name: string;
7
+ handler?: (row: any) => Promise<any> | any;
8
+ after?: () => void;
9
+ action?: (data: {
10
+ data: any;
11
+ }) => void;
12
+ }
13
+ export declare type ColumnConfig = {
14
+ form?: FormConfig;
15
+ rules?: any;
16
+ values?: FormValue;
17
+ selection?: boolean | 'single';
18
+ selectable?: (row: any, index: number) => boolean;
19
+ label: string;
20
+ fixed?: 'left' | 'right' | boolean;
21
+ width?: number | string;
22
+ actions?: ColumnActionConfig[];
23
+ type: 'popover' | 'expand' | string | ((value: any, row: any) => string);
24
+ text: string;
25
+ prop: string;
26
+ showHeader: boolean;
27
+ table?: ColumnConfig[];
28
+ formatter?: 'datetime' | ((item: any, row: Record<string, any>) => any);
29
+ popover: {
30
+ placement: '';
31
+ width: '';
32
+ trigger: '';
33
+ tableEmbed: '';
34
+ };
35
+ sortable?: boolean | 'custom';
36
+ action?: 'tip' | 'actionLink' | 'img' | 'link' | 'tag';
37
+ handler: (row: any) => void;
38
+ };
@@ -0,0 +1,6 @@
1
+ declare module '*.vue' {
2
+ import { DefineComponent } from 'vue';
3
+
4
+ const component: DefineComponent<{}, {}, any>;
5
+ export default component;
6
+ }
@@ -0,0 +1,2 @@
1
+ import { ColumnConfig } from './schema';
2
+ export declare const formatter: (item: ColumnConfig, row: any) => any;
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "version": "1.0.0-beta.1",
3
+ "name": "@tmagic/table",
4
+ "main": "dist/magic-table.umd.js",
5
+ "module": "dist/magic-table.es.js",
6
+ "types": "dist/types/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/magic-table.es.js",
10
+ "require": "./dist/magic-table.umd.js"
11
+ },
12
+ "./dist/style.css": {
13
+ "import": "./dist/style.css",
14
+ "require": "./dist/style.css"
15
+ }
16
+ },
17
+ "scripts": {
18
+ "build": "vite build"
19
+ },
20
+ "engines": {
21
+ "node": ">=14"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/Tencent/tmagic-editor.git"
26
+ },
27
+ "dependencies": {
28
+ "@tmagic/form": "^1.0.0-beta.1",
29
+ "element-plus": "^2.0.2",
30
+ "lodash-es": "^4.17.21",
31
+ "vue": "^3.2.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/color": "^3.0.1",
35
+ "@types/lodash-es": "^4.17.4",
36
+ "@types/node": "^15.12.4",
37
+ "@vitejs/plugin-vue": "^1.2.3",
38
+ "@vue/compiler-sfc": "^3.2.0",
39
+ "@vue/test-utils": "^2.0.0-rc.12",
40
+ "sass": "^1.35.1",
41
+ "typescript": "^4.3.4",
42
+ "vite": "^2.3.7",
43
+ "vite-plugin-dts": "^0.9.6",
44
+ "vue-tsc": "^0.0.24"
45
+ }
46
+ }
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <el-table-column :label="config.label" :width="config.width" :fixed="config.fixed">
3
+ <template v-slot="scope">
4
+ <el-button
5
+ v-for="(action, actionIndex) in config.actions"
6
+ v-show="display(action.display, scope.row) && !editState[scope.$index]"
7
+ v-html="action.text"
8
+ class="action-btn"
9
+ type="text"
10
+ size="small"
11
+ :key="actionIndex"
12
+ @click="actionHandler(action, scope.row, scope.$index)"
13
+ ></el-button>
14
+ <el-button
15
+ class="action-btn"
16
+ v-show="editState[scope.$index]"
17
+ type="text"
18
+ size="small"
19
+ @click="save(scope.$index, config)"
20
+ >保存</el-button
21
+ >
22
+ <el-button
23
+ class="action-btn"
24
+ v-show="editState[scope.$index]"
25
+ type="text"
26
+ size="small"
27
+ @click="editState[scope.$index] = undefined"
28
+ >取消</el-button
29
+ >
30
+ </template>
31
+ </el-table-column>
32
+ </template>
33
+
34
+ <script lang="ts">
35
+ import { PropType } from 'vue';
36
+ import { ElMessage, ElMessageBox } from 'element-plus';
37
+
38
+ import { ColumnActionConfig, ColumnConfig } from './schema';
39
+ </script>
40
+
41
+ <script lang="ts" setup>
42
+ const props = defineProps({
43
+ columns: {
44
+ type: Array as PropType<any[]>,
45
+ require: true,
46
+ default: () => [],
47
+ },
48
+
49
+ config: {
50
+ type: Object as PropType<ColumnConfig>,
51
+ require: true,
52
+ default: () => {},
53
+ },
54
+
55
+ rowkeyName: {
56
+ type: String,
57
+ default: 'c_id',
58
+ },
59
+
60
+ editState: {
61
+ type: Object,
62
+ default: () => {},
63
+ },
64
+ });
65
+
66
+ const emit = defineEmits(['afterAction']);
67
+
68
+ const display = (fuc: boolean | Function | undefined, row: any) => {
69
+ if (typeof fuc === 'function') {
70
+ return fuc.call(this, this, row);
71
+ }
72
+ return true;
73
+ };
74
+
75
+ const success = (msg: string, action: ColumnActionConfig) => {
76
+ ElMessage.success(msg);
77
+ action.after?.();
78
+ };
79
+
80
+ const error = (msg: string) => ElMessage.error(msg);
81
+
82
+ const deleteAction = async (action: ColumnActionConfig, row: any) => {
83
+ await ElMessageBox.confirm(`确认删除${row[action.name || 'c_name']}(${row[props.rowkeyName]})?`, '提示', {
84
+ confirmButtonText: '确定',
85
+ cancelButtonText: '取消',
86
+ type: 'warning',
87
+ });
88
+
89
+ const res = await action.handler?.(row);
90
+
91
+ if (res.ret === 0) {
92
+ success('删除成功!', action);
93
+ } else {
94
+ error(res.msg || '删除失败');
95
+ }
96
+ };
97
+
98
+ const copyHandler = async (action: ColumnActionConfig, row: any) => {
99
+ await ElMessageBox.confirm(`确定复制${row[action.name || 'c_name']}(${row.c_id})?`, '提示', {
100
+ confirmButtonText: '确定',
101
+ cancelButtonText: '取消',
102
+ type: 'warning',
103
+ });
104
+
105
+ try {
106
+ const res = await action.handler?.(row);
107
+
108
+ if (res.ret === 0) {
109
+ success('复制成功!', action);
110
+ } else {
111
+ error(`复制失败!${res.msg}`);
112
+ }
113
+ } catch (e) {
114
+ error('复制失败!');
115
+ }
116
+ };
117
+
118
+ const actionHandler = async (action: ColumnActionConfig, row: any, index: number) => {
119
+ if (action.type === 'delete') {
120
+ await deleteAction(action, row);
121
+ } else if (action.type === 'copy') {
122
+ await copyHandler(action, row);
123
+ } else if (action.type === 'edit') {
124
+ props.editState[index] = row;
125
+ } else {
126
+ await action.handler?.(row);
127
+ action.after?.();
128
+ }
129
+ };
130
+
131
+ const save = async (index: number, config: ColumnConfig) => {
132
+ const action = config.actions?.find((item) => item.type === 'edit')?.action;
133
+ if (!action) return;
134
+
135
+ const data: any = {};
136
+ const row = props.editState[index];
137
+ props.columns
138
+ .filter((item) => item.type)
139
+ .forEach((column) => {
140
+ data[column.prop] = row[column.prop];
141
+ });
142
+
143
+ const res: any = await action({
144
+ data,
145
+ });
146
+
147
+ if (res) {
148
+ if (res.ret === 0) {
149
+ ElMessage.success('保存成功');
150
+ props.editState[index] = undefined;
151
+ emit('afterAction');
152
+ } else {
153
+ ElMessage.error({
154
+ duration: 10000,
155
+ showClose: true,
156
+ dangerouslyUseHTMLString: true,
157
+ message: res.msg || '保存失败',
158
+ });
159
+ }
160
+ } else {
161
+ props.editState[index] = undefined;
162
+ emit('afterAction');
163
+ }
164
+ };
165
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <el-table-column type="expand">
3
+ <template #default="scope">
4
+ <m-table
5
+ v-if="config.table"
6
+ :show-header="false"
7
+ :columns="config.table"
8
+ :data="scope.row[config.prop]"
9
+ ></m-table>
10
+ <m-form
11
+ v-if="config.form"
12
+ :config="config.form"
13
+ :init-values="config.values || scope.row[config.prop] || {}"
14
+ ></m-form>
15
+ </template>
16
+ </el-table-column>
17
+ </template>
18
+
19
+ <script lang="ts">
20
+ import { defineComponent, PropType } from 'vue';
21
+
22
+ import { MForm } from '@tmagic/form';
23
+
24
+ import { ColumnConfig } from './schema';
25
+
26
+ export default defineComponent({
27
+ components: { MForm },
28
+
29
+ props: {
30
+ config: {
31
+ type: Object as PropType<ColumnConfig>,
32
+ default: () => ({}),
33
+ required: true,
34
+ },
35
+ },
36
+ });
37
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <el-table-column :label="config.label" :width="config.width" :fixed="config.fixed">
3
+ <template v-slot="scope">
4
+ <el-popover :placement="config.popover.placement" :width="config.popover.width" :trigger="config.popover.trigger">
5
+ <m-table
6
+ v-if="config.popover.tableEmbed"
7
+ :show-header="config.showHeader"
8
+ :columns="config.table"
9
+ :data="scope.row[config.prop]"
10
+ ></m-table>
11
+ <template #reference>
12
+ <el-button type="text"> {{ config.text || formatter(config, scope.row) }}</el-button>
13
+ </template>
14
+ </el-popover>
15
+ </template>
16
+ </el-table-column>
17
+ </template>
18
+
19
+ <script lang="ts">
20
+ import { defineComponent, PropType } from 'vue';
21
+
22
+ import { ColumnConfig } from './schema';
23
+ import { formatter } from './utils';
24
+
25
+ export default defineComponent({
26
+ props: {
27
+ config: {
28
+ type: Object as PropType<ColumnConfig>,
29
+ default: () => ({}),
30
+ required: true,
31
+ },
32
+ },
33
+
34
+ setup() {
35
+ return {
36
+ formatter,
37
+ };
38
+ },
39
+ });
40
+ </script>