vue2-client 1.17.23 → 1.17.25

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.
@@ -3,7 +3,7 @@
3
3
  <!-- 图片 -->
4
4
  <span v-for="img in images" :key="img.id" class="picture-card" :style="{ width: cardSize, height: cardSize, padding: paddingSize }">
5
5
  <img :src="img.url" :alt="img.name" />
6
- <span class="picture-action" :style="{ width: actionSize, height: actionSize }">
6
+ <span class="picture-action" :style="{ width: actionSize, height: actionSize, top: paddingSize, left: paddingSize }">
7
7
  <a-icon type="eye" class="picture-preview-icon" @click="handlePreview(img.url)" />
8
8
  </span>
9
9
  </span>
@@ -11,24 +11,23 @@
11
11
  <a-modal
12
12
  v-model="previewVisible"
13
13
  :footer="null"
14
- :dialog-style="{ top: '20px' }"
15
- width="85%"
16
14
  :z-index="1001"
15
+ centered
17
16
  title="图片预览"
18
17
  @cancel="handlePreviewClose"
19
18
  >
20
- <file-preview :path="previewPath" />
19
+ <image-preview ref="imagePreview" :src="previewPath" />
21
20
  </a-modal>
22
21
  </div>
23
22
  </template>
24
23
 
25
24
  <script>
26
- import FilePreview from '@vue2-client/components/FilePreview'
25
+ import ImagePreview from '@/components/ImagePreview/ImagePreview.vue'
27
26
 
28
27
  export default {
29
28
  name: 'ImageItem',
30
29
  components: {
31
- FilePreview
30
+ ImagePreview
32
31
  },
33
32
  props: {
34
33
  images: {
@@ -55,7 +54,7 @@ export default {
55
54
  return this.width + 'px'
56
55
  },
57
56
  actionSize: function () {
58
- return this.width - 22 + 'px'
57
+ return this.width - 2 * this.padding + 'px'
59
58
  },
60
59
  paddingSize: function () {
61
60
  if (Number(this.padding) === 0) {
@@ -71,6 +70,7 @@ export default {
71
70
  this.previewVisible = true
72
71
  },
73
72
  handlePreviewClose () {
73
+ this.$refs.imagePreview.handleReset()
74
74
  this.previewVisible = false
75
75
  this.previewPath = ''
76
76
  }
@@ -85,20 +85,20 @@ export default {
85
85
  border: 1px solid #d9d9d9;
86
86
  border-radius: 6px;
87
87
  //padding: 10px;
88
- margin: 0 10px 10px 0;
89
- overflow: hidden;
88
+ margin: 5px 5px 5px 5px;
89
+ //overflow: hidden;
90
90
  img {
91
91
  width: 100%;
92
92
  height: 100%;
93
93
  object-fit: cover;
94
+ border-radius: 6px;
94
95
  }
95
96
  .picture-action {
96
97
  position: absolute;
97
- top: 10px;
98
- left: 10px;
99
98
  display: flex;
100
99
  justify-content: center;
101
100
  align-items: center;
101
+ border-radius: 6px;
102
102
  background: #000;
103
103
  opacity: 0;
104
104
  transition: opacity 0.3s;
@@ -0,0 +1,323 @@
1
+ <template>
2
+ <div class="image-preview-container">
3
+ <!-- 工具栏 -->
4
+ <div class="preview-toolbar">
5
+ <!-- 放大按钮 -->
6
+ <a-button
7
+ type="link"
8
+ icon="zoom-in"
9
+ @click="handleZoomIn"
10
+ :disabled="scale >= maxScale"
11
+ />
12
+ <!-- 缩小按钮 -->
13
+ <a-button
14
+ type="link"
15
+ icon="zoom-out"
16
+ @click="handleZoomOut"
17
+ :disabled="scale <= minScale"
18
+ />
19
+ <!-- 重置按钮 -->
20
+ <a-button
21
+ type="link"
22
+ icon="sync"
23
+ @click="handleReset"
24
+ />
25
+ <a-divider type="vertical"/>
26
+ <!-- 左转按钮 -->
27
+ <a-button
28
+ type="link"
29
+ icon="undo"
30
+ @click="handleRotateLeft"
31
+ />
32
+ <!-- 右转按钮 -->
33
+ <a-button
34
+ type="link"
35
+ icon="redo"
36
+ @click="handleRotateRight"
37
+ />
38
+ <a-divider type="vertical"/>
39
+ <!-- 当前缩放比例显示 -->
40
+ <span class="scale-info">{{ Math.round(scale * 100) }}%</span>
41
+ </div>
42
+
43
+ <!-- 图片内容区域 -->
44
+ <div class="preview-content" @wheel.prevent="handleWheel">
45
+ <div class="preview-image-wrapper">
46
+ <!-- 图片显示 -->
47
+ <img
48
+ v-if="src && !fullImageError"
49
+ :src="src"
50
+ :alt="alt"
51
+ class="preview-image"
52
+ :style="imageStyle"
53
+ @mousedown="handleDragStart"
54
+ @mousemove="handleDragMove"
55
+ @mouseup="handleDragEnd"
56
+ @mouseleave="handleDragEnd"
57
+ />
58
+
59
+ <!-- 图片加载错误提示 -->
60
+ <div v-if="fullImageError" class="preview-error">
61
+ <a-icon type="picture" style="font-size: 48px; color: #d9d9d9;"/>
62
+ <p>图片加载失败</p>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </template>
68
+
69
+ <script>
70
+ export default {
71
+ name: 'ImagePreview',
72
+ props: {
73
+ src: { // 图片地址
74
+ type: String,
75
+ required: true
76
+ },
77
+ alt: { // 图片 alt 属性
78
+ type: String,
79
+ default: '图片'
80
+ }
81
+ },
82
+ data () {
83
+ return {
84
+ // 缩放相关
85
+ scale: 1, // 当前缩放比例
86
+ rotate: 0, // 当前旋转角度
87
+ minScale: 0.1, // 最小缩放
88
+ maxScale: 5, // 最大缩放
89
+ scaleStep: 0.1, // 每次缩放步长
90
+
91
+ // 拖拽相关
92
+ translateX: 0, // X轴偏移
93
+ translateY: 0, // Y轴偏移
94
+ isDragging: false, // 是否正在拖拽
95
+ dragStartX: 0, // 拖拽起点 X
96
+ dragStartY: 0, // 拖拽起点 Y
97
+ startTranslateX: 0, // 拖拽起始偏移 X
98
+ startTranslateY: 0, // 拖拽起始偏移 Y
99
+
100
+ // 图片加载错误状态
101
+ fullImageError: false
102
+ }
103
+ },
104
+ computed: {
105
+ // 图片样式
106
+ imageStyle () {
107
+ return {
108
+ // transform 包含平移、缩放和旋转
109
+ transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale}) rotate(${this.rotate}deg)`,
110
+ // 拖拽时取消动画,防止滞后
111
+ transition: this.isDragging ? 'none' : 'transform 0.3s ease',
112
+ // 拖拽光标样式
113
+ cursor: this.isDragging ? 'grabbing' : (this.scale > 1 ? 'grab' : 'default')
114
+ }
115
+ }
116
+ },
117
+ methods: {
118
+ /**
119
+ * 放大图片
120
+ */
121
+ handleZoomIn () {
122
+ if (this.scale < this.maxScale) {
123
+ this.scale = Math.min(this.scale + this.scaleStep, this.maxScale) // 避免超过最大值
124
+ }
125
+ },
126
+
127
+ /**
128
+ * 缩小图片
129
+ */
130
+ handleZoomOut () {
131
+ if (this.scale > this.minScale) {
132
+ this.scale = Math.max(this.scale - this.scaleStep, this.minScale) // 避免低于最小值
133
+ // 缩小到 1 或以下重置偏移
134
+ if (this.scale <= 1) {
135
+ this.translateX = 0
136
+ this.translateY = 0
137
+ }
138
+ }
139
+ },
140
+
141
+ /**
142
+ * 向左旋转图片 90 度
143
+ */
144
+ handleRotateLeft () {
145
+ this.rotate -= 90
146
+ },
147
+
148
+ /**
149
+ * 向右旋转图片 90 度
150
+ */
151
+ handleRotateRight () {
152
+ this.rotate += 90
153
+ },
154
+
155
+ /**
156
+ * 重置图片状态
157
+ */
158
+ handleReset () {
159
+ this.scale = 1
160
+ this.rotate = 0
161
+ this.translateX = 0
162
+ this.translateY = 0
163
+ },
164
+
165
+ /**
166
+ * 开始拖拽
167
+ * @param {MouseEvent} event
168
+ */
169
+ handleDragStart (event) {
170
+ if (this.scale <= 1) return // 缩放 <=1 时不可拖拽
171
+ event.preventDefault()
172
+ this.isDragging = true
173
+ this.dragStartX = event.clientX
174
+ this.dragStartY = event.clientY
175
+ this.startTranslateX = this.translateX
176
+ this.startTranslateY = this.translateY
177
+ },
178
+
179
+ /**
180
+ * 拖拽移动
181
+ * @param {MouseEvent} event
182
+ */
183
+ handleDragMove (event) {
184
+ if (!this.isDragging) return
185
+ event.preventDefault()
186
+ const deltaX = event.clientX - this.dragStartX // 当前偏移 X
187
+ const deltaY = event.clientY - this.dragStartY // 当前偏移 Y
188
+ this.translateX = this.startTranslateX + deltaX
189
+ this.translateY = this.startTranslateY + deltaY
190
+ },
191
+
192
+ /**
193
+ * 结束拖拽
194
+ */
195
+ handleDragEnd (event) {
196
+ if (!this.isDragging) return
197
+ event.preventDefault()
198
+ this.isDragging = false
199
+ },
200
+
201
+ /**
202
+ * 鼠标滚轮缩放
203
+ * @param {WheelEvent} event
204
+ */
205
+ handleWheel (event) {
206
+ const delta = event.deltaY || event.wheelDelta
207
+ if (delta > 0) this.handleZoomOut() // 向下滚动缩小
208
+ else this.handleZoomIn() // 向上滚动放大
209
+ }
210
+ }
211
+ }
212
+ </script>
213
+
214
+ <style lang="less" scoped>
215
+ /* 整个预览容器 */
216
+ .image-preview-container {
217
+ width: 100%;
218
+ height: 100%;
219
+ position: relative; /* 方便工具栏绝对定位 */
220
+ }
221
+
222
+ /* 工具栏样式 */
223
+ .preview-toolbar {
224
+ position: absolute; /* 悬浮在图片上方 */
225
+ top: 16px; /* 距离顶部 16px */
226
+ left: 50%; /* 居中 */
227
+ transform: translateX(-50%);
228
+ z-index: 10; /* 确保在图片上层 */
229
+ background: rgba(255, 255, 255, 0.95); /* 半透明白色背景 */
230
+ border-radius: 8px; /* 圆角 */
231
+ padding: 8px 16px; /* 内边距 */
232
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); /* 阴影 */
233
+ display: flex;
234
+ align-items: center;
235
+ gap: 8px; /* 按钮间距 */
236
+
237
+ /* 工具栏按钮样式 */
238
+ .ant-btn-link {
239
+ color: #333;
240
+ padding: 4px 8px;
241
+ height: 32px;
242
+ width: 32px;
243
+ display: inline-flex;
244
+ align-items: center;
245
+ justify-content: center;
246
+
247
+ &:hover:not(:disabled) { /* 悬停状态 */
248
+ color: #1890ff;
249
+ background: rgba(24, 144, 255, 0.1);
250
+ border-radius: 4px;
251
+ }
252
+
253
+ &:disabled { /* 禁用状态 */
254
+ color: #d9d9d9;
255
+ cursor: not-allowed;
256
+ }
257
+ }
258
+
259
+ /* 分割线样式 */
260
+ .ant-divider-vertical {
261
+ height: 20px;
262
+ margin: 0 4px;
263
+ background: #e8e8e8;
264
+ }
265
+
266
+ /* 显示缩放比例 */
267
+ .scale-info {
268
+ color: #666;
269
+ font-size: 12px;
270
+ min-width: 40px;
271
+ text-align: center;
272
+ user-select: none; /* 禁止选中文本 */
273
+ }
274
+ }
275
+
276
+ /* 图片内容区域 */
277
+ .preview-content {
278
+ position: relative;
279
+ width: 100%;
280
+ height: 100%;
281
+ display: flex;
282
+ align-items: center; /* 垂直居中 */
283
+ justify-content: center; /* 水平居中 */
284
+ background: #fafafa; /* 灰色背景 */
285
+ overflow: hidden; /* 超出隐藏 */
286
+ }
287
+
288
+ /* 图片包裹容器 */
289
+ .preview-image-wrapper {
290
+ display: flex;
291
+ align-items: center; /* 垂直居中 */
292
+ justify-content: center; /* 水平居中 */
293
+ width: 100%;
294
+ height: 100%;
295
+ //overflow: auto; /* 超出可滚动 */
296
+ position: relative;
297
+ }
298
+
299
+ /* 图片样式 */
300
+ .preview-image {
301
+ max-width: 100%; /* 最大宽度不超过容器 */
302
+ max-height: 100%; /* 最大高度不超过容器 */
303
+ object-fit: contain; /* 保持比例显示 */
304
+ user-select: none; /* 禁止选中图片 */
305
+ transform-origin: center center; /* 旋转、缩放中心 */
306
+ -webkit-user-drag: none; /* 禁止图片拖拽 */
307
+ }
308
+
309
+ /* 图片加载错误提示 */
310
+ .preview-error {
311
+ display: flex;
312
+ flex-direction: column; /* 图标和文字垂直排列 */
313
+ align-items: center; /* 水平居中 */
314
+ justify-content: center; /* 垂直居中 */
315
+ gap: 16px; /* 图标和文字间距 */
316
+ color: #999;
317
+
318
+ p {
319
+ margin: 0;
320
+ font-size: 14px;
321
+ }
322
+ }
323
+ </style>
@@ -6,7 +6,7 @@ export default {
6
6
  components: { WorkflowDetail },
7
7
  mounted () {
8
8
  this.$refs.workFlow.init({
9
- workflowId: '4476'
9
+ workflowId: 4454
10
10
  })
11
11
  },
12
12
  methods: {