@ebiz/designer-components 0.0.18-kzy.1 → 0.0.18-kzy.3

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,117 @@
1
+ <script setup>
2
+ import { computed, inject, onMounted, getCurrentInstance } from 'vue';
3
+
4
+ const props = defineProps({
5
+ // 列唯一标识
6
+ colKey: {
7
+ type: String,
8
+ required: true
9
+ },
10
+ // 列标题
11
+ title: {
12
+ type: String,
13
+ default: ''
14
+ },
15
+ // 列宽度
16
+ width: {
17
+ type: [String, Number],
18
+ default: ''
19
+ },
20
+ // 最小列宽
21
+ minWidth: {
22
+ type: [String, Number],
23
+ default: ''
24
+ },
25
+ // 水平对齐方式
26
+ align: {
27
+ type: String,
28
+ default: 'left',
29
+ validator: (val) => ['left', 'center', 'right'].includes(val)
30
+ },
31
+ // 固定列位置
32
+ fixed: {
33
+ type: String,
34
+ default: '',
35
+ validator: (val) => ['', 'left', 'right'].includes(val)
36
+ },
37
+ // 列类型
38
+ type: {
39
+ type: String,
40
+ default: '',
41
+ validator: (val) => ['', 'multiple', 'single', 'index', 'expand'].includes(val)
42
+ },
43
+ // 超出省略
44
+ ellipsis: {
45
+ type: Boolean,
46
+ default: false
47
+ },
48
+ // 标题超出省略
49
+ ellipsisTitle: {
50
+ type: Boolean,
51
+ default: false
52
+ },
53
+ // 是否支持排序
54
+ sorter: {
55
+ type: Boolean,
56
+ default: false
57
+ },
58
+ // 过滤配置
59
+ filter: {
60
+ type: Object,
61
+ default: null
62
+ },
63
+ // 自定义类名
64
+ className: {
65
+ type: String,
66
+ default: ''
67
+ },
68
+ // 是否禁用
69
+ disabled: {
70
+ type: Boolean,
71
+ default: false
72
+ }
73
+ });
74
+
75
+ // 获取父级表格组件实例
76
+ const tableCtx = inject('tableCtx', null);
77
+ const instance = getCurrentInstance();
78
+
79
+ // 格式化列配置对象
80
+ const columnConfig = computed(() => {
81
+ return {
82
+ colKey: props.colKey,
83
+ title: props.title,
84
+ width: props.width,
85
+ minWidth: props.minWidth,
86
+ align: props.align,
87
+ fixed: props.fixed || '',
88
+ type: props.type || '',
89
+ ellipsis: props.ellipsis,
90
+ ellipsisTitle: props.ellipsisTitle,
91
+ sorter: props.sorter,
92
+ filter: props.filter,
93
+ className: props.className,
94
+ disabled: props.disabled,
95
+ cell: instance.slots.default ? props.colKey : undefined,
96
+ title: instance.slots.title ? `title-${props.colKey}` : undefined
97
+ };
98
+ });
99
+
100
+ // 在组件挂载时将列配置注册到表格组件
101
+ onMounted(() => {
102
+ if (tableCtx && typeof tableCtx.registerColumn === 'function') {
103
+ tableCtx.registerColumn(columnConfig.value);
104
+ } else {
105
+ console.warn('EbizTableColumn必须在EbizTable内部使用');
106
+ }
107
+ });
108
+ </script>
109
+
110
+ <template>
111
+ <template v-if="$slots.default">
112
+ <slot></slot>
113
+ </template>
114
+ <template v-if="$slots.title">
115
+ <slot name="title"></slot>
116
+ </template>
117
+ </template>
@@ -0,0 +1,181 @@
1
+ <template>
2
+ <div class="ebiz-table-sort">
3
+ <t-popup :visible="sortVisible" trigger="click" placement="bottom-right" :overlay-style="{ width: '450px' }"
4
+ @visible-change="handleVisibleChange" :destroy-on-close="false">
5
+ <template #content>
6
+ <t-card :title="popupTitle" size="small" :bordered="false">
7
+ <div class="sort-content">
8
+ <div class="sort-item" v-for="(item, index) in sortItems" :key="index">
9
+ <div class="sort-item-content" style="display: flex; margin-bottom: 12px;">
10
+ <t-select v-model="item.type" :placeholder="fieldPlaceholder" :options="fieldOptions" :clearable="false"
11
+ :style="{ width: '170px' }" @change="handleSortChange" />
12
+ <t-select v-model="item.sort" :placeholder="orderPlaceholder" :options="orderOptions" :clearable="false"
13
+ :style="{ width: '170px', marginLeft: '8px' }" @change="handleSortChange" />
14
+ <t-button theme="default" variant="text" shape="circle" @click="removeSortItem(index)"
15
+ v-if="sortItems.length > 1" :style="{ marginLeft: '8px', flexShrink: 0 }">
16
+ <template #icon>
17
+ <t-icon name="close" />
18
+ </template>
19
+ </t-button>
20
+ </div>
21
+ </div>
22
+ <div class="sort-footer">
23
+ <t-button theme="default" variant="outline" @click="addSortItem"
24
+ v-if="sortItems.length < maxSortItems">
25
+ <template #icon>
26
+ <t-icon name="add" />
27
+ </template>
28
+ {{ addConditionText }}
29
+ </t-button>
30
+ </div>
31
+ </div>
32
+ </t-card>
33
+ </template>
34
+ <t-button block variant="outline" :title="title">
35
+ <template #icon>
36
+ <t-icon :name="icon" />
37
+ </template>
38
+ <div v-if="buttonText">
39
+ {{ buttonText }}
40
+ </div>
41
+ </t-button>
42
+ </t-popup>
43
+ </div>
44
+ </template>
45
+
46
+ <script>
47
+ export default {
48
+ name: "EbizTableSort"
49
+ }
50
+ </script>
51
+
52
+ <script setup>
53
+ import { ref, computed, defineProps, defineEmits, watch } from 'vue';
54
+ import { Button as TButton, Popup as TPopup, Card as TCard, Select as TSelect, Icon as TIcon } from 'tdesign-vue-next';
55
+
56
+ const props = defineProps({
57
+ // v-model绑定值
58
+ modelValue: {
59
+ type: Array,
60
+ default: () => []
61
+ },
62
+ // 按钮图标
63
+ icon: {
64
+ type: String,
65
+ default: 'sort'
66
+ },
67
+ // 按钮文本
68
+ buttonText: {
69
+ type: String,
70
+ default: ''
71
+ },
72
+ // 按钮标题
73
+ title: {
74
+ type: String,
75
+ default: '排序'
76
+ },
77
+ // 弹出层标题
78
+ popupTitle: {
79
+ type: String,
80
+ default: '排序'
81
+ },
82
+ // 字段选项
83
+ fieldOptions: {
84
+ type: Array,
85
+ default: () => []
86
+ },
87
+ // 字段占位符
88
+ fieldPlaceholder: {
89
+ type: String,
90
+ default: '选择字段'
91
+ },
92
+ // 排序选项
93
+ orderOptions: {
94
+ type: Array,
95
+ default: () => [
96
+ { value: 'asc', label: '升序 ↑' },
97
+ { value: 'desc', label: '降序 ↓' }
98
+ ]
99
+ },
100
+ // 排序占位符
101
+ orderPlaceholder: {
102
+ type: String,
103
+ default: '选择排序'
104
+ },
105
+ // 最大排序条件数量
106
+ maxSortItems: {
107
+ type: Number,
108
+ default: 5
109
+ },
110
+ // 添加条件文本
111
+ addConditionText: {
112
+ type: String,
113
+ default: '添加排序条件'
114
+ }
115
+ });
116
+
117
+ const emit = defineEmits(['update:modelValue', 'sort', 'visible-change']);
118
+
119
+ // 排序弹出层显示状态
120
+ const sortVisible = ref(false);
121
+
122
+ // 排序条件列表
123
+ const sortItems = ref([]);
124
+
125
+ // 监听modelValue变化
126
+ watch(() => props.modelValue, (newVal) => {
127
+ if (newVal && newVal.length > 0) {
128
+ sortItems.value = JSON.parse(JSON.stringify(newVal));
129
+ } else {
130
+ // 默认添加一个空的排序条件
131
+ sortItems.value = [{ type: '', sort: 'desc' }];
132
+ }
133
+ }, { immediate: true });
134
+
135
+ // 添加排序条件
136
+ const addSortItem = () => {
137
+ if (sortItems.value.length < props.maxSortItems) {
138
+ sortItems.value.push({ type: '', sort: 'desc' });
139
+ }
140
+ };
141
+
142
+ // 移除排序条件
143
+ const removeSortItem = (index) => {
144
+ sortItems.value.splice(index, 1);
145
+ handleSortChange();
146
+ };
147
+
148
+ // 处理排序变更
149
+ const handleSortChange = () => {
150
+ // 过滤有效的排序条件(字段和排序方向都不为空)
151
+ const validSortItems = sortItems.value.filter(item => item.type && item.sort);
152
+ emit('update:modelValue', validSortItems);
153
+ emit('sort', validSortItems);
154
+ };
155
+
156
+ // 弹出层可见性变化
157
+ const handleVisibleChange = (visible) => {
158
+ sortVisible.value = visible;
159
+ emit('visible-change', visible);
160
+ };
161
+ </script>
162
+
163
+ <style lang="less" scoped>
164
+ .ebiz-table-sort {
165
+ display: inline-block;
166
+
167
+ .sort-content {
168
+ min-width: 400px;
169
+ width: 100%;
170
+ }
171
+
172
+ .sort-footer {
173
+ margin-top: 16px;
174
+ }
175
+
176
+ .sort-actions {
177
+ display: flex;
178
+ justify-content: flex-end;
179
+ }
180
+ }
181
+ </style>
package/src/index.js CHANGED
@@ -49,6 +49,9 @@ import EbizEmployeeInfo from "./components/EbizEmployeeInfo.vue";
49
49
  import EbizAlert from "./components/TdesignAlert.vue";
50
50
  import EbizDialog from "./components/TdesignDialog.vue";
51
51
  import EbizTable from "./components/EbizTable.vue";
52
+ import EbizTableColumn from './components/EbizTableColumn.vue';
53
+ import EbizTableSort from './components/EbizTableSort.vue';
54
+ import EbizStatusBadge from "./components/EbizStatusBadge.vue";
52
55
  import { MessagePlugin as EbizMessage } from 'tdesign-vue-next';
53
56
 
54
57
  // 导入简洁数据服务
@@ -148,5 +151,10 @@ export {
148
151
  // 对话框组件
149
152
  EbizDialog,
150
153
  // 表格组件
151
- EbizTable
154
+ EbizTable,
155
+ EbizTableColumn,
156
+ // 表格排序组件
157
+ EbizTableSort,
158
+ // 状态标记组件
159
+ EbizStatusBadge
152
160
  };
@@ -1,10 +1,13 @@
1
1
  import { createRouter, createWebHistory } from 'vue-router'
2
+ import Home from '../views/Home.vue'
3
+ import ButtonView from '../views/Button.vue'
4
+ import TableView from '../views/TableView.vue'
2
5
 
3
6
  const routes = [
4
7
  {
5
8
  path: '/',
6
9
  name: 'Home',
7
- component: () => import('../views/Home.vue'),
10
+ component: Home,
8
11
  meta: { title: '首页' }
9
12
  },
10
13
  {
@@ -15,10 +18,16 @@ const routes = [
15
18
  },
16
19
  {
17
20
  path: '/table',
18
- name: 'Table',
19
- component: () => import('../views/Table.vue'),
21
+ name: 'table',
22
+ component: TableView,
20
23
  meta: { title: '表格组件示例' }
21
24
  },
25
+ {
26
+ path: '/table-column',
27
+ name: 'table-column',
28
+ component: TableView,
29
+ meta: { title: '表格列组件示例' }
30
+ },
22
31
  {
23
32
  path: '/form',
24
33
  name: 'Form',
@@ -27,8 +36,8 @@ const routes = [
27
36
  },
28
37
  {
29
38
  path: '/button',
30
- name: 'Button',
31
- component: () => import('../views/Button.vue'),
39
+ name: 'button',
40
+ component: ButtonView,
32
41
  meta: { title: '按钮组件示例' }
33
42
  },
34
43
  {
@@ -240,6 +249,18 @@ const routes = [
240
249
  name: 'TableDemo',
241
250
  component: () => import('../views/TableDemo.vue'),
242
251
  meta: { title: 'Ebiz表格组件示例' }
252
+ },
253
+ {
254
+ path: '/status-badge',
255
+ name: 'StatusBadge',
256
+ component: () => import('../views/StatusBadgeExample.vue'),
257
+ meta: { title: 'Ebiz状态标记组件示例' }
258
+ },
259
+ {
260
+ path: '/table-sort',
261
+ name: 'TableSort',
262
+ component: () => import('../views/TableSortDemo.vue'),
263
+ meta: { title: 'Ebiz表格排序组件示例' }
243
264
  }
244
265
  ]
245
266
 
@@ -54,7 +54,10 @@ export default {
54
54
  { path: '/ebiz-employee-info', title: 'Ebiz员工信息组件示例' },
55
55
  { path: '/tdesign-alert', title: 'TDesign提示组件示例' },
56
56
  { path: '/tdesign-dialog', title: 'TDesign对话框组件示例' },
57
- { path: '/table-demo', title: 'Ebiz表格组件示例' }
57
+ { path: '/table-demo', title: 'Ebiz表格组件示例' },
58
+ { path: '/status-badge', title: 'Ebiz状态标记组件示例' },
59
+ { path: '/table-column', title: 'Ebiz表格列组件示例' },
60
+ { path: '/table-sort', title: 'Ebiz表格排序组件示例' }
58
61
  ]
59
62
 
60
63
  return {
@@ -0,0 +1,146 @@
1
+ <template>
2
+ <div class="example-container">
3
+ <h2>状态标记组件示例</h2>
4
+
5
+ <div class="example-section">
6
+ <h3>不同状态类型</h3>
7
+ <div class="example-row">
8
+ <EbizStatusBadge status="default" text="默认状态" />
9
+ <EbizStatusBadge status="success" text="成功状态" />
10
+ <EbizStatusBadge status="warning" text="警告状态" />
11
+ <EbizStatusBadge status="error" text="错误状态" />
12
+ <EbizStatusBadge status="processing" text="处理中状态" />
13
+ </div>
14
+ </div>
15
+
16
+ <div class="example-section">
17
+ <h3>自定义颜色</h3>
18
+ <div class="example-row">
19
+ <EbizStatusBadge color="#8B5CF6" text="紫色状态" />
20
+ <EbizStatusBadge color="#EC4899" text="粉色状态" />
21
+ <EbizStatusBadge color="#14B8A6" text="青色状态" />
22
+ <EbizStatusBadge color="#F59E0B" text="橙色状态" />
23
+ </div>
24
+ </div>
25
+
26
+ <div class="example-section">
27
+ <h3>预设颜色映射</h3>
28
+ <div class="example-row">
29
+ <EbizStatusBadge
30
+ status="success"
31
+ text="自定义预设颜色"
32
+ :colorMap="customColorMap"
33
+ />
34
+ <EbizStatusBadge
35
+ status="error"
36
+ text="自定义预设颜色"
37
+ :colorMap="customColorMap"
38
+ />
39
+ <EbizStatusBadge
40
+ status="warning"
41
+ text="自定义预设颜色"
42
+ :colorMap="customColorMap"
43
+ />
44
+ <EbizStatusBadge
45
+ status="processing"
46
+ text="自定义预设颜色"
47
+ :colorMap="customColorMap"
48
+ />
49
+ </div>
50
+ </div>
51
+
52
+ <div class="example-section">
53
+ <h3>不同尺寸</h3>
54
+ <div class="example-row">
55
+ <EbizStatusBadge size="small" text="小尺寸" />
56
+ <EbizStatusBadge size="medium" text="中尺寸" />
57
+ <EbizStatusBadge size="large" text="大尺寸" />
58
+ <EbizStatusBadge :size="20" text="自定义尺寸(20px)" />
59
+ </div>
60
+ </div>
61
+
62
+ <div class="example-section">
63
+ <h3>不同位置</h3>
64
+ <div class="example-row">
65
+ <EbizStatusBadge position="left" text="左侧" />
66
+ <EbizStatusBadge position="right" text="右侧" />
67
+ <EbizStatusBadge position="top" text="顶部" />
68
+ <EbizStatusBadge position="bottom" text="底部" />
69
+ </div>
70
+ </div>
71
+
72
+ <div class="example-section">
73
+ <h3>脉冲动画</h3>
74
+ <div class="example-row">
75
+ <EbizStatusBadge status="processing" :pulse="true" text="处理中" />
76
+ <EbizStatusBadge status="success" :pulse="true" text="成功" />
77
+ <EbizStatusBadge status="error" :pulse="true" text="错误" />
78
+ </div>
79
+ </div>
80
+
81
+ <div class="example-section">
82
+ <h3>只显示状态点(无文本)</h3>
83
+ <div class="example-row">
84
+ <EbizStatusBadge status="default" :showText="false" />
85
+ <EbizStatusBadge status="success" :showText="false" />
86
+ <EbizStatusBadge status="warning" :showText="false" />
87
+ <EbizStatusBadge status="error" :showText="false" />
88
+ <EbizStatusBadge status="processing" :showText="false" />
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </template>
93
+
94
+ <script>
95
+ import { EbizStatusBadge } from '../index.js';
96
+ import { ref } from 'vue';
97
+
98
+ export default {
99
+ name: 'StatusBadgeExample',
100
+ components: {
101
+ EbizStatusBadge
102
+ },
103
+ setup() {
104
+ // 自定义预设颜色映射
105
+ const customColorMap = ref({
106
+ success: '#6EE7B7', // 浅绿色
107
+ error: '#F87171', // 浅红色
108
+ warning: '#FCD34D', // 浅黄色
109
+ processing: '#60A5FA', // 浅蓝色
110
+ default: '#A1A1AA' // 浅灰色
111
+ });
112
+
113
+ return {
114
+ customColorMap
115
+ };
116
+ }
117
+ }
118
+ </script>
119
+
120
+ <style scoped>
121
+ .example-container {
122
+ padding: 20px;
123
+ font-family: Arial, sans-serif;
124
+ }
125
+
126
+ .example-section {
127
+ margin-bottom: 30px;
128
+ border: 1px solid #eee;
129
+ border-radius: 6px;
130
+ padding: 16px;
131
+ }
132
+
133
+ .example-section h3 {
134
+ margin-top: 0;
135
+ margin-bottom: 16px;
136
+ font-size: 16px;
137
+ color: #333;
138
+ }
139
+
140
+ .example-row {
141
+ display: flex;
142
+ flex-wrap: wrap;
143
+ gap: 20px;
144
+ align-items: center;
145
+ }
146
+ </style>
@@ -0,0 +1,144 @@
1
+ <template>
2
+ <div class="container">
3
+ <h1>表格排序组件演示</h1>
4
+
5
+ <div class="demo-section">
6
+ <h2>基础用法</h2>
7
+ <div class="demo-item">
8
+ <EbizTableSort icon="filter-sort" :field-options="fieldOptions" @sort="handleSort"
9
+ @reset="handleReset" />
10
+ </div>
11
+ <div class="result" v-if="sortResult.length > 0">
12
+ <h3>排序结果:</h3>
13
+ <pre>{{ JSON.stringify(sortResult, null, 2) }}</pre>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="demo-section">
18
+ <h2>自定义按钮</h2>
19
+ <div class="demo-item">
20
+ <EbizTableSort icon="filter" button-text="自定义排序" :field-options="fieldOptions" @sort="handleSort2" />
21
+ </div>
22
+ <div class="result" v-if="sortResult2.length > 0">
23
+ <h3>排序结果:</h3>
24
+ <pre>{{ JSON.stringify(sortResult2, null, 2) }}</pre>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="demo-section">
29
+ <h2>预设排序条件</h2>
30
+ <div class="demo-item">
31
+ <EbizTableSort :field-options="fieldOptions" :default-sort="defaultSort" @sort="handleSort3" />
32
+ </div>
33
+ <div class="result" v-if="sortResult3.length > 0">
34
+ <h3>排序结果:</h3>
35
+ <pre>{{ JSON.stringify(sortResult3, null, 2) }}</pre>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="demo-section">
40
+ <h2>多条件排序</h2>
41
+ <div class="demo-item">
42
+ <EbizTableSort :field-options="fieldOptions" :max-sort-items="3" @sort="handleSort4" />
43
+ </div>
44
+ <div class="result" v-if="sortResult4.length > 0">
45
+ <h3>排序结果:</h3>
46
+ <pre>{{ JSON.stringify(sortResult4, null, 2) }}</pre>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </template>
51
+
52
+ <script setup>
53
+ import { ref } from 'vue';
54
+ import { EbizTableSort } from '../index.js';
55
+
56
+ // 字段选项
57
+ const fieldOptions = [
58
+ { value: 'name', label: '姓名' },
59
+ { value: 'age', label: '年龄' },
60
+ { value: 'address', label: '地址' },
61
+ { value: 'createTime', label: '创建时间' },
62
+ { value: 'status', label: '状态' }
63
+ ];
64
+
65
+ // 默认排序条件
66
+ const defaultSort = [
67
+ { field: 'age', order: 'desc' }
68
+ ];
69
+
70
+ // 排序结果
71
+ const sortResult = ref([]);
72
+ const sortResult2 = ref([]);
73
+ const sortResult3 = ref([]);
74
+ const sortResult4 = ref([]);
75
+
76
+ // 处理排序
77
+ const handleSort = (sort) => {
78
+ sortResult.value = sort;
79
+ console.log('排序条件:', sort);
80
+ };
81
+
82
+ const handleSort2 = (sort) => {
83
+ sortResult2.value = sort;
84
+ console.log('排序条件2:', sort);
85
+ };
86
+
87
+ const handleSort3 = (sort) => {
88
+ sortResult3.value = sort;
89
+ console.log('排序条件3:', sort);
90
+ };
91
+
92
+ const handleSort4 = (sort) => {
93
+ sortResult4.value = sort;
94
+ console.log('排序条件4:', sort);
95
+ };
96
+
97
+ // 处理重置
98
+ const handleReset = () => {
99
+ sortResult.value = [];
100
+ console.log('重置排序');
101
+ };
102
+ </script>
103
+
104
+ <style lang="less" scoped>
105
+ .container {
106
+ padding: 20px;
107
+
108
+ h1 {
109
+ margin-bottom: 20px;
110
+ }
111
+
112
+ .demo-section {
113
+ margin-bottom: 30px;
114
+ padding: 20px;
115
+ border: 1px solid #eee;
116
+ border-radius: 6px;
117
+
118
+ h2 {
119
+ margin-bottom: 16px;
120
+ font-size: 18px;
121
+ }
122
+
123
+ .demo-item {
124
+ margin-bottom: 16px;
125
+ }
126
+
127
+ .result {
128
+ margin-top: 20px;
129
+ padding: 16px;
130
+ background-color: #f9f9f9;
131
+ border-radius: 4px;
132
+
133
+ h3 {
134
+ margin-bottom: 8px;
135
+ font-size: 16px;
136
+ }
137
+
138
+ pre {
139
+ font-family: monospace;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ </style>