web-component-gallery 2.3.5 → 2.3.7

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.
@@ -1,5 +1,6 @@
1
1
  import PropTypes from 'ant-design-vue/es/_util/vue-types'
2
2
  import { Base64 } from '../../utils/Base64'
3
+ import { transferData } from '../../utils/Filter'
3
4
  import { IconFont } from '../index'
4
5
 
5
6
  const BrowseProps = {
@@ -21,41 +22,67 @@ const FILE_TYPES = {
21
22
 
22
23
  // 初始化数据
23
24
  const setInnerData = (data, https) => {
24
-
25
- let innerData = data ?? []
26
-
27
- if (typeof(data) === 'string') {
28
- try {
29
- innerData = JSON.parse(data)
30
- } catch(error) { innerData = [] }
25
+ // 处理Base64图片数据
26
+ if (typeof data === 'string' && data.startsWith('data:image')) {
27
+ return [{
28
+ url: data,
29
+ contentType: 'image',
30
+ name: 'base64_image'
31
+ }]
31
32
  }
32
33
 
33
- const { FILEURL, KKFILEURL, OVERVIEWFILEURL } = https
34
+ // 解析数据
35
+ let innerData = transferData(data, 'Array')
36
+
37
+ // 确保返回数组格式
38
+ const dataArray = Array.isArray(innerData) ? innerData : [innerData]
34
39
 
35
- innerData = Array.isArray(innerData) ? innerData : [innerData]
40
+ const { FILEURL, KKFILEURL, OVERVIEWFILEURL } = https
36
41
 
37
- innerData.forEach(dataItem => {
38
- if (!dataItem.url.startsWith('http')) {
39
- dataItem.url =
40
- getCustomTag(dataItem.url) === 'iframe'
41
- ? KKFILEURL + encodeURIComponent( Base64.encode( OVERVIEWFILEURL + dataItem.url ) )
42
- : FILEURL + dataItem.url
42
+ // URL前缀配置检查
43
+ if (!FILEURL || !KKFILEURL || !OVERVIEWFILEURL) {
44
+ console.warn('缺少必要的URL配置')
45
+ return dataArray
46
+ }
47
+
48
+ // 处理URL
49
+ return dataArray.map(dataItem => {
50
+ if (!dataItem || typeof dataItem !== 'object') {
51
+ return dataItem
43
52
  }
44
- })
45
53
 
46
- return innerData
54
+ // 如果已经是完整URL,直接返回
55
+ if (dataItem.url && (dataItem.url.startsWith('http') || dataItem.url.startsWith('data:image'))) {
56
+ return dataItem
57
+ }
58
+
59
+ // 构造完整URL
60
+ const baseUrl = getCustomTag(dataItem.url) === 'iframe' && KKFILEURL && OVERVIEWFILEURL
61
+ ? `${KKFILEURL}${encodeURIComponent(Base64.encode(`${OVERVIEWFILEURL}${dataItem.url}`))}`
62
+ : `${FILEURL}${dataItem.url || ''}`;
63
+
64
+ return {
65
+ ...dataItem,
66
+ url: baseUrl
67
+ }
68
+ })
47
69
  }
48
70
 
49
71
  // 不同类型不同容器承载
50
72
  const getCustomTag = (url) => {
73
+ // base64 图片处理
74
+ if (url.startsWith('data:image')) return 'img'
75
+
76
+ // 文件扩展名处理
51
77
  const ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
52
- if (FILE_TYPES.PICTURE.includes(ext)) return 'img'
53
- if (FILE_TYPES.AUDIO.includes(ext)) return 'audio'
54
- if (FILE_TYPES.VIDEO.includes(ext)) return 'video'
55
- return 'iframe'
78
+ return FILE_TYPES.PICTURE.includes(ext) ? 'img' :
79
+ FILE_TYPES.AUDIO.includes(ext) ? 'audio' :
80
+ FILE_TYPES.VIDEO.includes(ext) ? 'video' : 'iframe'
56
81
  }
57
82
 
58
83
  function renderContent(h, {url, name}, images) {
84
+ if (!url) return
85
+
59
86
  const { isThumb, astrictH, $viewerApi, $postM } = this
60
87
 
61
88
  const MEDIA_TYPES = {
@@ -5,24 +5,51 @@ import { transferData } from '../../utils/Filter.js'
5
5
 
6
6
  const { Item: DescriptionsItem } = Descriptions
7
7
 
8
- const descDefaultAttrs = {
8
+ // 默认属性配置
9
+ const DESC_DEFAULT_ATTRS = {
9
10
  size: 'middle',
10
11
  bordered: true
11
12
  }
12
13
 
14
+ // 属性定义
13
15
  const DescriptionsProps = {
14
16
  title: PropTypes.string,
15
17
  column: PropTypes.oneOfType([PropTypes.number, PropTypes.object]).def(4),
18
+ labelWidth: PropTypes.number.def(160),
16
19
  descDetails: PropTypes.object,
17
20
  descSettings: PropTypes.array,
18
21
  descAttrs: PropTypes.object,
19
22
  }
20
23
 
24
+ // 渲染内容组件
21
25
  const renderContent = (h, item, details) => {
22
26
  const CustomTag = item.type === 'file' ? Browse : 'span'
23
- const data = item.hasOwnProperty('multiProps') ?
24
- item.multiProps.map(propsItem => transferData(details[propsItem], 'Array')).flat() :
25
- transferData(details[item.props], 'Array')
27
+
28
+ // 统一处理内容值获取逻辑
29
+ const getContentValue = () => {
30
+ return item.customRender
31
+ ? item.customRender(details[item.props], details)
32
+ : details[item.props]
33
+ }
34
+
35
+ const contentValue = getContentValue()
36
+
37
+ // 处理文件类型的数据
38
+ const processData = () => {
39
+ if (item.type !== 'file') return contentValue
40
+
41
+ if (item.customRender) return contentValue
42
+
43
+ if (item.hasOwnProperty('multiProps')) {
44
+ return item.multiProps
45
+ .map(propsItem => transferData(details[propsItem], 'Array'))
46
+ .flat()
47
+ }
48
+
49
+ return contentValue
50
+ }
51
+
52
+ const data = processData()
26
53
 
27
54
  const props = {
28
55
  data,
@@ -30,16 +57,22 @@ const renderContent = (h, item, details) => {
30
57
  astrictH: 78
31
58
  }
32
59
 
33
- const contentValue = item.customRender ?
34
- item.customRender(details[item.props], details) :
35
- details[item.props]
36
-
37
60
  return (
38
61
  <CustomTag {...{ props }}>
39
62
  {contentValue ?? '暂无'}
40
63
  </CustomTag>
41
64
  )
42
65
  }
66
+ // ... existing code ...
67
+
68
+ // 响应式列数配置
69
+ const COLUMN_CONFIG = [
70
+ { minWidth: 1600, getColumn: (column) => column || 4 },
71
+ { minWidth: 1200, getColumn: (column) => Math.min(4, column) },
72
+ { minWidth: 992, getColumn: (column) => Math.min(3, column) },
73
+ { minWidth: 576, getColumn: (column) => Math.min(2, column) },
74
+ { minWidth: 0, getColumn: () => 1 }
75
+ ]
43
76
 
44
77
  const DescriptionsList = {
45
78
  name: 'DescriptionsList',
@@ -47,30 +80,38 @@ const DescriptionsList = {
47
80
  data() {
48
81
  return {
49
82
  responsiveColumn: 1,
50
- // 添加新属性:父级剩余高度
51
83
  parentRemainingHeight: 'auto'
52
84
  }
53
85
  },
86
+
54
87
  mounted() {
55
- this.setDescContentWidth()
56
- this.$bus.$onWindow(this, 'resize', this.setDescContentWidth)
57
- // 初始化父级剩余高度
58
- // this.setParentRemainingHeight()
88
+ this.initComponent()
59
89
  },
90
+
91
+ beforeDestroy() {
92
+ this.$bus.$offWindow(this, 'resize', this.setDescContentWidth)
93
+ },
94
+
60
95
  methods: {
96
+ // 初始化组件
97
+ initComponent() {
98
+ this.setDescContentWidth()
99
+ this.$bus.$onWindow(this, 'resize', this.setDescContentWidth)
100
+ },
101
+
102
+ // 获取响应式列数
61
103
  getCurrentColumn(width) {
62
- if (width >= 1600) return this.column || 4
63
- if (width >= 1200) return Math.min(4, this.column)
64
- if (width >= 992) return Math.min(3, this.column)
65
- if (width >= 576) return Math.min(2, this.column)
66
- return 1
104
+ const config = COLUMN_CONFIG.find(item => width >= item.minWidth)
105
+ return config ? config.getColumn(this.column) : 1
67
106
  },
68
107
 
108
+ // 计算项目宽度
69
109
  calculateItemWidth(totalWidth, itemSpan) {
70
110
  const effectiveSpan = itemSpan && this.responsiveColumn > itemSpan ? itemSpan : 1
71
111
  return totalWidth * (effectiveSpan / this.responsiveColumn)
72
112
  },
73
113
 
114
+ // 设置描述内容宽度
74
115
  setDescContentWidth() {
75
116
  const retry = () => {
76
117
  const container = this.$refs.Descriptions
@@ -86,74 +127,76 @@ const DescriptionsList = {
86
127
  }
87
128
 
88
129
  this.responsiveColumn = this.getCurrentColumn(width)
89
-
90
- setTimeout(() => {
91
- const rowElements = container.querySelectorAll('.ant-descriptions-row')
92
- // 记录数量
93
- let count = 0
94
-
95
- for (let i = 0; i < rowElements.length; i++) {
96
- const labelElements = rowElements[i].querySelectorAll('.ant-descriptions-item-label')
97
- const contentElements = rowElements[i].querySelectorAll('.ant-descriptions-item-content')
98
-
99
- for (let j = 0; j < labelElements.length; j++) {
100
- const itemSpan = this.descSettings[count]?.span || 1
101
- const eachWidth = width / this.responsiveColumn * itemSpan
102
-
103
- // 设置标签固定宽度
104
- labelElements[j].style = `
105
- width: 160px;
106
- min-width: 160px;
107
- max-width: 160px;
108
- `
109
-
110
- // 设置内容区域默认宽度
111
- contentElements[j].style = `
112
- width: ${eachWidth - 160}px;
113
- min-width: ${eachWidth - 160}px;
114
- max-width: ${eachWidth - 160}px;
115
- `
116
-
117
- count++
118
- }
119
- }
120
- }, 0)
121
-
130
+ this.updateItemStyles(container, width)
122
131
  }
132
+
123
133
  retry()
124
134
  },
125
-
135
+
136
+ // 更新项目样式
137
+ updateItemStyles(container, totalWidth) {
138
+ this.$nextTick(() => {
139
+ const rowElements = container.querySelectorAll('.ant-descriptions-row')
140
+ let itemCount = 0
141
+
142
+ rowElements.forEach(rowElement => {
143
+ const labelElements = rowElement.querySelectorAll('.ant-descriptions-item-label')
144
+ const contentElements = rowElement.querySelectorAll('.ant-descriptions-item-content')
145
+
146
+ labelElements.forEach((labelEl, index) => {
147
+ const itemConfig = this.descSettings[itemCount]
148
+ const itemSpan = itemConfig?.span || 1
149
+ const eachWidth = totalWidth / this.responsiveColumn * itemSpan
150
+
151
+ // 设置标签样式
152
+ this.setStyle(labelEl, {
153
+ width: `${this.labelWidth}px`,
154
+ minWidth: `${this.labelWidth}px`,
155
+ maxWidth: `${this.labelWidth}px`
156
+ })
157
+
158
+ // 设置内容样式
159
+ this.setStyle(contentElements[index], {
160
+ width: `${eachWidth - this.labelWidth}px`,
161
+ minWidth: `${eachWidth - this.labelWidth}px`,
162
+ maxWidth: `${eachWidth - this.labelWidth}px`
163
+ })
164
+
165
+ itemCount++
166
+ })
167
+ })
168
+ })
169
+ },
170
+
171
+ // 设置元素样式工具方法
172
+ setStyle(element, styles) {
173
+ if (element) {
174
+ Object.assign(element.style, styles)
175
+ }
176
+ },
177
+
126
178
  // 设置父级剩余高度
127
179
  setParentRemainingHeight() {
128
180
  const parent = this.$el.parentElement
129
181
  if (parent) {
130
- // 获取父级高度
131
182
  const parentHeight = parent.offsetHeight
132
- // 获取当前组件在父级中的位置
133
183
  const rect = this.$el.getBoundingClientRect()
134
184
  const parentRect = parent.getBoundingClientRect()
135
-
136
- // 计算父级剩余高度(从当前组件顶部到父级底部)
137
185
  const remainingHeight = parentHeight - (rect.top - parentRect.top)
138
-
139
- // 设置高度
140
186
  this.parentRemainingHeight = `${remainingHeight}px`
141
187
  }
142
188
  }
143
189
  },
190
+
144
191
  render(h) {
145
192
  const { title, descAttrs, descDetails, descSettings, $slots, $scopedSlots } = this
146
193
 
147
194
  return (
148
- // style={{
149
- // // 动态设置高度
150
- // height: this.parentRemainingHeight
151
- // }}
152
195
  <div class="Descriptions" ref="Descriptions">
153
196
  <Descriptions
154
197
  title={title}
155
198
  column={this.responsiveColumn}
156
- {...{ attrs: { ...descDefaultAttrs, ...descAttrs } }}
199
+ {...{ attrs: { ...DESC_DEFAULT_ATTRS, ...descAttrs } }}
157
200
  >
158
201
  {descSettings.map((descItem, key) => (
159
202
  <DescriptionsItem
@@ -163,9 +206,9 @@ const DescriptionsList = {
163
206
  <span slot="label">
164
207
  {$slots[`${descItem.props}Label`] ?? descItem.label}
165
208
  </span>
166
- {$scopedSlots[descItem.props] ?
167
- $scopedSlots[descItem.props](descDetails) :
168
- renderContent(h, descItem, descDetails)
209
+ {$scopedSlots[descItem.props]
210
+ ? $scopedSlots[descItem.props](descDetails)
211
+ : renderContent(h, descItem, descDetails)
169
212
  }
170
213
  </DescriptionsItem>
171
214
  ))}
@@ -6,6 +6,13 @@
6
6
  .scrollbarStyle();
7
7
  }
8
8
 
9
+ // 无边框
10
+ .ant-descriptions-item {
11
+ display: flex;
12
+ align-items: center;
13
+ }
14
+
15
+ // 携带边框
9
16
  .ant-descriptions-bordered {
10
17
 
11
18
  .ant-descriptions-view > table {
@@ -497,11 +497,9 @@ export default {
497
497
  })
498
498
 
499
499
  let newInnerOptions = []
500
- if (this.pagination.current === 1 && isReset) {
501
- newInnerOptions = [...records]
502
- } else {
503
- newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
504
- }
500
+ this.pagination.current === 1 && isReset
501
+ ? newInnerOptions = [...records]
502
+ : newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
505
503
 
506
504
  // 对合并后的数据进行去重
507
505
  this.innerOptions = this.deduplicateOptions(newInnerOptions)
@@ -1,10 +1,10 @@
1
-
2
1
  .ADatePicker {
3
2
  width: 100%;
4
3
  align-items: center;
5
- .flex-layout(@flexGap: 0 6px);
4
+ .flex-layout(@flexGap: 0 6px);
6
5
 
7
6
  .ant-calendar-picker {
8
7
  flex: 1;
8
+ min-width: 0 !important;
9
9
  }
10
10
  }
@@ -1,18 +1,42 @@
1
-
2
- // 添加flex属性解决css中div莫名高度
3
1
  .ASelectCustom {
4
- width: 100%;
2
+ align-items: center;
3
+ .flex-layout();
5
4
 
6
5
  .loading-more {
7
6
  font-size: @font-size-base;
8
7
  text-align: center;
9
8
  padding: @padding-xs 0;
10
9
  box-sizing: border-box;
11
- }
10
+ }
11
+
12
+ .ant-select {
13
+ &-selection {
14
+ .layout(100%, @input-height-base);
15
+
16
+ &--multiple {
17
+ padding-bottom: 0;
18
+ }
19
+
20
+ &__rendered {
21
+ overflow: hidden;
22
+ white-space: nowrap;
23
+ text-overflow: ellipsis;
24
+ // 2px为上下边框兼容
25
+ height: @input-height-base - 2px;
26
+
27
+ ul {
28
+ width: auto;
29
+ display: flex;
30
+
31
+ li { min-width: 70px; }
32
+ }
33
+ }
34
+ }
12
35
 
13
- .ant-select-dropdown-menu {
14
- max-height: 300px;
15
- overflow-y: auto;
16
- .scrollbarStyle();
36
+ &-dropdown-menu {
37
+ max-height: 300px;
38
+ overflow-y: auto;
39
+ .scrollbarStyle();
40
+ }
17
41
  }
18
42
  }
@@ -26,10 +26,7 @@ export default {
26
26
  /* 一行显示几个 PS:最多5个 */
27
27
  layoutSize: {
28
28
  type: Number,
29
- default: 4,
30
- validator: value => {
31
- return value <= 5
32
- }
29
+ default: 4
33
30
  },
34
31
  /* 表单项配置 */
35
32
  formSetting: Array
@@ -9,13 +9,6 @@
9
9
  width: 100%;
10
10
  }
11
11
 
12
- // 统一设置表单控件宽度
13
- .ant-select,
14
- .ant-input-number,
15
- .ant-calendar-picker {
16
- width: 100%;
17
- }
18
-
19
12
  .ant-radio-group {
20
13
  line-height: @input-height-lg;
21
14
  }
@@ -23,6 +16,10 @@
23
16
  .ant-form-item-children {
24
17
  display: flex;
25
18
  align-items: center;
19
+
20
+ & > * {
21
+ width: 100%;
22
+ }
26
23
  }
27
24
 
28
25
  .FormLine {
@@ -13,9 +13,9 @@ const FormModelItem = FormModel.Item
13
13
  export function getFormWidth(child, layoutSize, gap = 24) {
14
14
  const width = (100 / layoutSize) * (child.size ?? 1)
15
15
  if (this.layout === 'vertical') {
16
- return `flex: 0 1 calc(${width}% - ${gap}px); margin-right: ${gap}px;`
16
+ return `width: calc(${width}% - ${gap}px); margin-right: ${gap}px;`
17
17
  }
18
- return `flex: 0 1 ${width}%;`
18
+ return `width: ${width}%;`
19
19
  }
20
20
 
21
21
  /**
@@ -132,7 +132,7 @@ export default {
132
132
  middle: '16px',
133
133
  default: '24px'
134
134
  }
135
- return `flex: 0 1 calc((${(100 / this.matchMediaSize) * (e.size ?? 1)}% - ${
135
+ return `width: calc((${(100 / this.matchMediaSize) * (e.size ?? 1)}% - ${
136
136
  gap[this.searchStyle]
137
137
  })); margin-right: ${gap[this.searchStyle]};`
138
138
  },
@@ -1,33 +1,33 @@
1
1
  @import '../../form-comp/style/index.less';
2
2
 
3
3
  .WebComponentFormSearch {
4
- gap: 16px 0;
5
- .flex-mixins(@justify: flex-start);
6
-
7
- .ant-form-item {
8
- display: inline-flex;
9
- margin-right: unset;
10
-
11
- .ant-form-item-label {
12
- min-width: 70px;
13
- max-width: 100px;
14
- text-align: right;
15
- }
4
+ .flex-mixins(@justify: flex-start, @gap: 16px 0);
16
5
 
17
- .ant-form-item-control-wrapper {
18
- flex: 1;
19
- }
20
-
21
- .ant-select,
22
- .ant-input-number,
23
- .ant-calendar-picker {
24
- width: 100%;
25
- }
6
+ .ant-form-item {
7
+ display: inline-flex;
8
+ margin-right: 0;
9
+
10
+ .ant-form-item-label {
11
+ min-width: 70px;
12
+ max-width: 100px;
13
+ text-align: right;
26
14
  }
27
-
28
- &__Actions {
15
+
16
+ .ant-form-item-control-wrapper {
29
17
  flex: 1;
30
- text-align: right;
31
- // margin-right: 16px;
18
+ min-width: 0;
19
+ display: inline-flex;
20
+ align-items: center;
32
21
  }
22
+
23
+ &-control,
24
+ &-children > * {
25
+ width: 100%;
26
+ }
27
+ }
28
+
29
+ &__Actions {
30
+ flex: 1;
31
+ text-align: right;
32
+ }
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-component-gallery",
3
- "version": "2.3.5",
3
+ "version": "2.3.7",
4
4
  "description": "基础vue、antdvue、less实现的私有组件库",
5
5
  "main": "dist/index.umd.js",
6
6
  "files": [
package/utils/Filter.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  export function getDay(day) {
9
- return getNDaysBefore(day, "{y}-{m}-{d}")
9
+ return getNDaysBefore(day, null, "{y}-{m}-{d}")
10
10
  }
11
11
 
12
12
  // 获取n天前的时间
package/utils/Utils.js CHANGED
@@ -17,35 +17,65 @@ export function chunkArray(arr, size) {
17
17
  return result
18
18
  }
19
19
 
20
+
20
21
  /**
21
22
  * 下载文件
22
- * @param {Blob} response - 文档流
23
+ * @param {Blob|Object} response - 文档流或包含data和headers的对象
23
24
  * @param {string} name - 文件名称
24
25
  * @param {string} type - 文件类型
25
26
  * @returns {void}
26
27
  */
27
- export function downLoadFn( response, name, type = "application/vnd.ms-excel" ) {
28
-
28
+ export function downLoadFn(response, name, type = "application/vnd.ms-excel") {
29
+ // 兼容新写法:从response对象中解析data和headers
30
+ let fileData = response
31
+ let fileName = name
32
+ let fileType = type
33
+
34
+ // 如果response是对象且包含data属性,则使用新写法
35
+ if (response && typeof response === 'object' && response.data) {
36
+ fileData = response.data
37
+
38
+ // 从headers中解析文件名和类型
39
+ if (response.headers) {
40
+ const headers = response.headers
41
+
42
+ // 解析文件类型
43
+ if (headers['content-type']) {
44
+ fileType = headers['content-type']
45
+ }
46
+
47
+ // 解析文件名
48
+ if (headers['content-disposition']) {
49
+ const contentDisposition = headers['content-disposition']
50
+ const match = contentDisposition.match(/filename=([^;]+)/)
51
+ if (match && match[1]) {
52
+ fileName = decodeURIComponent(match[1].replace(/['"]/g, ''))
53
+ }
54
+ }
55
+ }
56
+ }
57
+
29
58
  let reader = new FileReader()
30
59
 
31
- reader.readAsText( response, "utf-8" )
60
+ reader.readAsText(fileData, "utf-8")
32
61
 
33
62
  reader.onload = function () {
34
63
  try {
35
- message.error( JSON.parse( reader.result ).msg )
64
+ message.error(JSON.parse(reader.result).msg)
36
65
  } catch (err) {
37
- message.success( "下载中..." )
38
- let blob = new Blob( [ response ], { type } )
39
- let url = window.URL.createObjectURL( blob )
40
- const link = document.createElement( "a" )
66
+ message.success("下载中...")
67
+ let blob = new Blob([fileData], { type: fileType })
68
+ let url = window.URL.createObjectURL(blob)
69
+ const link = document.createElement("a")
41
70
  link.href = url
42
- link.download = name
71
+ link.download = fileName
43
72
  link.click()
44
- window.URL.revokeObjectURL( url )
73
+ window.URL.revokeObjectURL(url)
45
74
  }
46
75
  }
47
76
  }
48
77
 
78
+
49
79
  /**
50
80
  * 获取图片宽高 (如超出限制高度,则根据高度比计算出对应的宽度比)
51
81
  * @param {string} url - 图片地址