fx-platform-ui 1.0.1 → 1.0.2

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,19 @@
1
+ import { computed } from 'vue'
2
+ import type { UseTableStateParams } from './useTableState'
3
+ import type { ComputedRef } from 'vue'
4
+
5
+ export function useTableForm({ props }: UseTableStateParams) {
6
+ const schemas = props.formProps?.schemas || []
7
+ const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
8
+ return schemas
9
+ .map((item) => {
10
+ const value = item['slot'] || null
11
+ return value ? value : null
12
+ })
13
+ .filter((item): item is string => !!item)
14
+ })
15
+ console.log('getFormSlotKeys', getFormSlotKeys)
16
+ return {
17
+ getFormSlotKeys
18
+ }
19
+ }
@@ -6,68 +6,79 @@
6
6
  ref="queryFormRef"
7
7
  v-bind="formProps"
8
8
  @submit="handleSubmit"
9
- />
9
+ >
10
+ <template v-for="item in getFormSlotKeys" #[item]="data">
11
+ <slot :name="item" v-bind="data || {}"></slot>
12
+ </template>
13
+ </PlForm>
14
+ <!-- 中间放置插槽以防需要 -->
15
+ <template v-if="$slots.middle">
16
+ <slot name="middle"></slot>
17
+ </template>
10
18
  <!-- 工具按钮 + table -->
11
19
  <div>
12
20
  <ToolBar v-if="showToolBar"> </ToolBar>
13
21
  <template v-if="$slots.toolbar">
14
22
  <slot name="toolbar"></slot>
15
23
  </template>
16
- <Table
17
- v-show="tableShow"
18
- ref="tableRef"
19
- v-bind="getBindValues"
20
- :data-source="tableData"
21
- @change="handleTableChange"
22
- >
23
- <template
24
- v-for="defaultItem in Object.keys($slots)"
25
- #[defaultItem]="slotData"
26
- :key="defaultItem"
27
- >
28
- <slot :name="defaultItem" v-bind="slotData"></slot>
29
- </template>
30
- <!-- bodyCell, headerCell -->
31
- <template
32
- v-for="item in ['bodyCell', 'headerCell']"
33
- #[item]="slotData"
34
- :key="item"
24
+ <div :style="showCard ? cardStyle : ''">
25
+ <Table
26
+ v-show="tableShow"
27
+ ref="tableRef"
28
+ v-bind="getBindValues"
29
+ :data-source="tableData"
30
+ @change="handleTableChange"
35
31
  >
36
- <slot :name="item" v-bind="slotData"></slot>
37
32
  <template
38
- v-if="
39
- item === 'bodyCell' && getColumnKey(slotData.column) === '$action'
40
- "
33
+ v-for="defaultItem in Object.keys($slots)"
34
+ #[defaultItem]="slotData"
35
+ :key="defaultItem"
41
36
  >
42
- <TableAction :actions="slotData.column.actions(slotData)" />
37
+ <slot :name="defaultItem" v-bind="slotData"></slot>
43
38
  </template>
44
- <!-- 自定义展示构造 -->
39
+ <!-- bodyCell, headerCell -->
45
40
  <template
46
- v-for="slotItem in getBindValues.columns?.filter(
47
- (value) => value[item]
48
- )"
49
- :key="getColumnKey(slotItem)"
41
+ v-for="item in ['bodyCell', 'headerCell']"
42
+ #[item]="slotData"
43
+ :key="item"
50
44
  >
51
- <component
52
- :is="getComponent(slotItem?.[item]?.(slotData))"
53
- v-if="getColumnKey(slotData.column) === getColumnKey(slotItem)"
54
- />
45
+ <slot :name="item" v-bind="slotData"></slot>
46
+ <template
47
+ v-if="
48
+ item === 'bodyCell' &&
49
+ getColumnKey(slotData.column) === '$action'
50
+ "
51
+ >
52
+ <TableAction :actions="slotData.column.actions(slotData)" />
53
+ </template>
54
+ <!-- 自定义展示构造 -->
55
+ <template
56
+ v-for="slotItem in getBindValues.columns?.filter(
57
+ (value) => value[item]
58
+ )"
59
+ :key="getColumnKey(slotItem)"
60
+ >
61
+ <component
62
+ :is="getComponent(slotItem?.[item]?.(slotData))"
63
+ v-if="getColumnKey(slotData.column) === getColumnKey(slotItem)"
64
+ />
65
+ </template>
55
66
  </template>
56
- </template>
57
- </Table>
67
+ </Table>
68
+ </div>
58
69
  </div>
59
70
  </div>
60
71
  </template>
61
72
 
62
73
  <script lang="ts" setup>
63
- import { onUpdated, unref } from "vue"
74
+ import { onUpdated, unref } from 'vue'
64
75
  import { Table } from 'ant-design-vue'
65
76
  import PlForm from '../../form'
66
77
  import { isFunction } from '../../../utils/is'
67
78
  import { ToolBar, TableAction } from './components'
68
79
  import { platTableProps } from './plat-table-props'
69
80
  import { platTableEmits } from './plat-table-emits'
70
- import { useTableState, useTableMethods } from './hook'
81
+ import { useTableState, useTableMethods, useTableForm } from './hook'
71
82
  defineOptions({
72
83
  name: 'PlTable'
73
84
  })
@@ -77,6 +88,11 @@ const emit = defineEmits(platTableEmits)
77
88
 
78
89
  // table所有状态(可以理解成将props 和 slot 进行处理 并将结果输出)
79
90
  const tableState = useTableState({ props })
91
+
92
+ const { getFormSlotKeys } = useTableForm({
93
+ props
94
+ })
95
+
80
96
  const { tableData, queryFormRef, getBindValues } = tableState
81
97
 
82
98
  // 表格内部方法
@@ -9,6 +9,21 @@ import type {
9
9
 
10
10
  export const platTableProps = {
11
11
  ...tableProps(),
12
+ // 表格是否展示卡片属性
13
+ showCard: {
14
+ type: Boolean as PropType<boolean>,
15
+ default: false
16
+ },
17
+ // 表格外层卡片属性
18
+ cardStyle: {
19
+ type: Object as PropType<Recordable>,
20
+ default: () => ({
21
+ padding: '16px',
22
+ opacity: '1',
23
+ background: '#ffffff',
24
+ borderRadius: '4pt'
25
+ })
26
+ },
12
27
  // 是否显示搜索菜单
13
28
  searchShow: {
14
29
  type: Boolean as PropType<boolean>,
@@ -0,0 +1,10 @@
1
+ import { App } from 'vue'
2
+
3
+ import PlTagInput from './src/index.vue'
4
+ PlTagInput.install = function (app: App) {
5
+ // 组件注册,按需引入
6
+ app.component(PlTagInput.name, PlTagInput)
7
+ return app
8
+ }
9
+
10
+ export default PlTagInput
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <div
3
+ class="fx-tag-input"
4
+ tabindex="0"
5
+ :style="contentStyle"
6
+ v-on="{ click: focusActive }"
7
+ >
8
+ <div v-if="inputVisible" class="fx-tag-input-body">
9
+ <template v-for="tag in value" :key="tag">
10
+ <a-tag v-bind="tagProps" closable @close="() => handleClose(tag)">
11
+ {{ tag }}
12
+ </a-tag>
13
+ </template>
14
+ <div class="fx-tag-input-wrap">
15
+ <div class="fx-tag-input-enter">
16
+ <a-input
17
+ ref="inputRef"
18
+ v-model:value="inputValue"
19
+ type="text"
20
+ size="small"
21
+ :bordered="false"
22
+ @compositionupdate="titleCompositionUpdate"
23
+ @compositionend="titleCompositionEnd"
24
+ @blur="handleInputBlur"
25
+ @keydown.enter="handleInputConfirm"
26
+ />
27
+ </div>
28
+ <div class="fx-tag-input-hidden"
29
+ >{{ inputValue }}{{ inputUpdateValue }}</div
30
+ >
31
+ </div>
32
+ </div>
33
+ <div class="no-select">{{ prompt }}</div>
34
+ </div>
35
+ </template>
36
+
37
+ <script lang="ts" setup>
38
+ import { nextTick, PropType, ref } from 'vue'
39
+ import { message } from 'ant-design-vue'
40
+ import type { TagProps } from 'ant-design-vue/es/tag'
41
+ defineOptions({
42
+ name: 'PlTagInput'
43
+ })
44
+ const emit = defineEmits(['update:value', 'change'])
45
+ const props = defineProps({
46
+ tagProps: {
47
+ type: Object as PropType<TagProps>,
48
+ default: () => ({})
49
+ },
50
+ contentStyle: {
51
+ type: Object as PropType<Recordable>,
52
+ default: () => {
53
+ return {}
54
+ }
55
+ },
56
+ value: {
57
+ type: Array as PropType<string[] | number[]>,
58
+ default: () => {
59
+ return []
60
+ }
61
+ },
62
+ prompt: {
63
+ type: String,
64
+ default: '请输入内容,按回车确认'
65
+ }
66
+ })
67
+ const inputRef = ref()
68
+ // 输入已确认的值
69
+ const inputValue = ref('')
70
+ // 输入的字符还没有被确认
71
+ const inputUpdateValue = ref('')
72
+ // 是否显示输入框
73
+ const inputVisible = ref(false)
74
+
75
+ // compositionupdate 事件触发于字符被输入到一段文字的时候,但是输入的字符还没有被确认,因此不能用于替代 input 事件。
76
+ const titleCompositionUpdate = (e: any) => {
77
+ inputUpdateValue.value = e.target.value
78
+ }
79
+
80
+ const titleCompositionEnd = () => {
81
+ inputUpdateValue.value = ''
82
+ }
83
+ // 失焦事件
84
+ const handleInputBlur = () => {
85
+ inputValue.value = ''
86
+ inputVisible.value = props.value.length > 0
87
+ }
88
+ // 删除标签事件
89
+ const handleClose = (removedTag) => {
90
+ const tagsArray: (string | number)[] = props.value
91
+ const tags = tagsArray.filter((tag) => tag !== removedTag)
92
+ focusActive()
93
+ emit('update:value', tags)
94
+ }
95
+ // 确认输入事件
96
+ const handleInputConfirm = () => {
97
+ let tagsArray: (string | number)[] = props.value
98
+ if (inputValue.value && tagsArray.indexOf(inputValue.value) === -1) {
99
+ tagsArray = [...tagsArray, inputValue.value]
100
+ emit('update:value', tagsArray)
101
+ emit('change', tagsArray)
102
+ } else if (inputValue.value && tagsArray.indexOf(inputValue.value) !== -1) {
103
+ message.warning('内容已存在')
104
+ }
105
+ inputValue.value = ''
106
+ inputUpdateValue.value = ''
107
+ }
108
+ // 聚焦事件
109
+ const focusActive = () => {
110
+ inputVisible.value = true
111
+ nextTick(() => {
112
+ inputRef.value.focus()
113
+ })
114
+ }
115
+ </script>
116
+
117
+ <style lang="less" scoped>
118
+ .fx-tag-input {
119
+ border: 1px solid #d9d9d9;
120
+ border-radius: 2px;
121
+ padding: 5px;
122
+ min-height: 100px;
123
+
124
+ .fx-tag-input-wrap {
125
+ display: inline-block;
126
+ width: auto;
127
+ min-width: 60px;
128
+ position: relative;
129
+ height: 22px;
130
+ vertical-align: middle;
131
+
132
+ .fx-tag-input-enter {
133
+ position: absolute;
134
+ top: 0;
135
+ left: 0;
136
+ width: 100%;
137
+ height: 100%;
138
+ z-index: 1;
139
+ }
140
+
141
+ .fx-tag-input-hidden {
142
+ height: 0;
143
+ overflow: hidden;
144
+ white-space: nowrap;
145
+ // 对齐input所有会影响宽度的样式
146
+ padding: 0 15px;
147
+ font-size: 14px;
148
+ }
149
+ }
150
+
151
+ .no-select {
152
+ margin-top: 10px;
153
+ color: #bfbfbf;
154
+ -webkit-touch-callout: none;
155
+ -webkit-user-select: none;
156
+ -khtml-user-select: none;
157
+ -moz-user-select: none;
158
+ -ms-user-select: none;
159
+ user-select: none;
160
+ }
161
+ }
162
+ </style>
@@ -0,0 +1,13 @@
1
+ @primary-color: #1890ff; // 全局主色
2
+ @link-color: #1890ff; // 链接色
3
+ @success-color: #52c41a; // 成功色
4
+ @warning-color: #faad14; // 警告色
5
+ @error-color: #f5222d; // 错误色
6
+ @font-size-base: 14px; // 主字号
7
+ @heading-color: rgba(0, 0, 0, 0.85); // 标题色
8
+ @text-color: rgba(0, 0, 0, 0.65); // 主文本色
9
+ @text-color-secondary: rgba(0, 0, 0, 0.45); // 次文本色
10
+ @disabled-color: rgba(0, 0, 0, 0.25); // 失效色
11
+ @border-radius-base: 2px; // 组件/浮层圆角
12
+ @border-color-base: #d9d9d9; // 边框色
13
+ @box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // 浮层阴影
Binary file
File without changes