haiwei-module-admin 1.2.2 → 1.2.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": 0,
3
3
  "name": "haiwei-module-admin",
4
4
  "code": "admin",
5
- "version": "1.2.2",
5
+ "version": "1.2.3",
6
6
  "description": "haiwei前端Admin模块组件",
7
7
  "author": "Eric",
8
8
  "license": "ISC",
@@ -68,7 +68,7 @@ export default name => {
68
68
  // 如果提供了账户ID参数,则添加到请求中(仅在授权模式下需要)
69
69
  if (accounts) {
70
70
  formData.append('accounts', accounts)
71
- }
71
+ }
72
72
  // 发送POST请求到文件上传接口
73
73
  // 使用multipart/form-data内容类型,适合文件上传
74
74
  return $http.post(urls.upload, formData, {
@@ -1,31 +1,27 @@
1
1
  <template>
2
2
  <div class="file-preview">
3
- <!-- 当fullPath有效时显示内容 -->
4
3
  <template v-if="hasValidFullPath">
5
- <!-- 图片预览链接 -->
6
4
  <a v-if="isImage" class="preview-link" @click="showPreviewDialog">
7
5
  查看
8
6
  </a>
9
-
10
- <!-- 非图片文件下载 -->
11
7
  <nm-file-download v-else :url="downloadUrl" :private="isPrivate" :fileName="fileName" :text="downloadText" :icon="downloadIcon" :size="downloadSize" :type="downloadType" @click="onDownload" />
12
8
  </template>
13
-
14
- <!-- 图片预览对话框 -->
15
9
  <nm-dialog
16
10
  v-if="isImage"
17
11
  ref="previewDialog"
18
12
  :visible.sync="previewVisible"
19
13
  :title="previewTitle"
20
- width="800px"
21
- height="800px"
22
- :fullscreen="false"
14
+ icon="photo"
15
+ width="1200px"
16
+ height="80%"
17
+ fullscreen
18
+ draggable
19
+ no-scrollbar
23
20
  :footer="false"
24
21
  custom-class="image-preview-dialog"
25
22
  @closed="resetState"
26
23
  >
27
24
  <div class="preview-wrapper">
28
- <!-- 使用CSS实现图片居中,而不是JS计算 -->
29
25
  <div class="preview-container" ref="previewContainer">
30
26
  <img
31
27
  :src="previewUrl"
@@ -40,8 +36,6 @@
40
36
  @dblclick="resetImage"
41
37
  />
42
38
  </div>
43
-
44
- <!-- 操作按钮栏 -->
45
39
  <div class="toolbar">
46
40
  <button class="toolbar-btn" @click="zoomIn">
47
41
  <span class="icon">+</span>
@@ -51,11 +45,18 @@
51
45
  <span class="icon">-</span>
52
46
  <span class="text">缩小</span>
53
47
  </button>
48
+ <button class="toolbar-btn" @click="rotateLeft">
49
+ <span class="icon">↺</span>
50
+ <span class="text">左转90°</span>
51
+ </button>
52
+ <button class="toolbar-btn" @click="rotateRight">
53
+ <span class="icon">↻</span>
54
+ <span class="text">右转90°</span>
55
+ </button>
54
56
  <button class="toolbar-btn" @click="resetImage">
55
57
  <span class="icon">⟳</span>
56
58
  <span class="text">重置</span>
57
59
  </button>
58
- <!-- 非图片文件下载 -->
59
60
  <nm-file-download
60
61
  v-if="hasValidFullPath"
61
62
  :url="downloadUrl"
@@ -89,147 +90,116 @@ export default {
89
90
  default: () => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico']
90
91
  }
91
92
  },
92
-
93
93
  data() {
94
94
  return {
95
95
  previewVisible: false,
96
96
  previewUrl: '',
97
97
  fileInfo: null,
98
-
99
- // 图片状态
100
98
  imageLoading: false,
101
99
  imageError: false,
102
100
  loadingTimeout: null,
103
101
 
104
- // 图片位置和缩放(使用CSS transform,但让CSS处理居中)
102
+ // 图片原始尺寸(transform 计算需要)
103
+ imgNaturalWidth: 0,
104
+ imgNaturalHeight: 0,
105
+
106
+ // 变换状态
105
107
  position: { x: 0, y: 0 },
106
108
  scale: 1,
107
109
  minScale: 0.1,
108
110
  maxScale: 5,
111
+ rotation: 0,
112
+
113
+ // 自适应比例
114
+ initScale: 1,
109
115
 
110
- // 拖拽状态
111
116
  isDragging: false,
112
- startPosition: { x: 0, y: 0 }
117
+ startPosition: { x: 0, y: 0 },
118
+ enableTransition: true
113
119
  }
114
120
  },
115
-
116
121
  computed: {
117
- // 缓存路径处理结果,避免重复计算
122
+ rotationRad() {
123
+ return (this.rotation * Math.PI) / 180
124
+ },
118
125
  normalizedPath() {
119
126
  if (!this.fullPath) return null
120
127
  return this.fullPath.replace(/\\/g, '/')
121
128
  },
122
-
123
- // 缓存文件名,避免重复提取
124
129
  fileName() {
125
130
  if (!this.normalizedPath) return ''
126
131
  const filename = this.normalizedPath.split('/').pop()
127
132
  return filename || ''
128
133
  },
129
-
130
- // 缓存文件扩展名
131
134
  fileExt() {
132
135
  const filename = this.fileName
133
136
  if (!filename) return ''
134
137
  const dotIndex = filename.lastIndexOf('.')
135
138
  return dotIndex > -1 ? filename.slice(dotIndex + 1).toLowerCase() : ''
136
139
  },
137
-
138
140
  hasValidFullPath() {
139
- // 检查fullPath是否有效:不为空且不是空字符串
140
- if (!this.fullPath || this.fullPath.trim() === '') {
141
- return false
142
- }
143
-
144
- // 检查是否是目录路径(以斜杠结尾)
145
- if (this.fullPath.endsWith('/') || this.fullPath.endsWith('\\')) {
146
- return false
147
- }
148
-
149
- // 使用已计算的文件名
141
+ if (!this.fullPath || this.fullPath.trim() === '') return false
142
+ if (this.fullPath.endsWith('/') || this.fullPath.endsWith('\\')) return false
150
143
  const filename = this.fileName
151
-
152
- // 文件名不能为空
153
- if (!filename || filename.trim() === '') {
154
- return false
155
- }
156
-
144
+ if (!filename || filename.trim() === '') return false
157
145
  return true
158
146
  },
159
-
160
147
  isImage() {
161
148
  return this.imageExtensions.includes(this.fileExt)
162
149
  },
163
-
164
150
  downloadUrl() {
165
- // console.log('this.fileInfo?.url ', this.fileInfo?.url)
166
151
  return this.fileInfo?.url || this.fullPath
167
152
  },
168
-
169
153
  imageStyle() {
170
154
  return {
171
- transform: `translate(${this.position.x}px, ${this.position.y}px) scale(${this.scale})`,
172
- cursor: this.isDragging ? 'grabbing' : 'grab'
155
+ transform: `translate(${this.position.x}px, ${this.position.y}px) scale(${this.scale}) rotate(${this.rotation}deg)`,
156
+ transformOrigin: 'center center',
157
+ cursor: this.isDragging ? 'grabbing' : 'grab',
158
+ transition: this.enableTransition ? 'transform 0.2s ease' : 'none'
173
159
  }
174
160
  }
175
161
  },
176
-
177
162
  watch: {
178
163
  fullPath(val) {
179
164
  if (val && this.isImage && !this.isPrivate) {
180
165
  this.previewUrl = val
181
166
  }
182
167
  },
183
-
184
168
  previewVisible(val) {
185
169
  if (!val) {
186
170
  this.resetState()
187
171
  }
188
172
  }
189
173
  },
190
-
191
174
  mounted() {
192
- // 监听全局鼠标事件用于拖拽
193
175
  document.addEventListener('mousemove', this.handleDrag)
194
176
  document.addEventListener('mouseup', this.stopDrag)
195
177
  },
196
-
197
178
  beforeDestroy() {
198
- // 清理事件监听
199
179
  document.removeEventListener('mousemove', this.handleDrag)
200
180
  document.removeEventListener('mouseup', this.stopDrag)
201
-
202
- // 清理超时
203
181
  if (this.loadingTimeout) {
204
182
  clearTimeout(this.loadingTimeout)
205
183
  this.loadingTimeout = null
206
184
  }
207
185
  },
208
-
209
186
  methods: {
210
187
  async getFileInfo() {
211
188
  if (!this.fullPath) return null
212
-
213
189
  try {
214
190
  const result = await $api.admin.file.getByFullPath(this.fullPath)
215
191
  this.fileInfo = result
216
-
217
- console.log('result', result)
218
-
219
192
  return result
220
193
  } catch (error) {
221
194
  console.error('获取文件信息失败:', error)
222
195
  return null
223
196
  }
224
197
  },
225
-
226
198
  async showPreviewDialog() {
227
199
  if (!this.isImage) return
228
-
229
200
  this.resetState()
230
201
  this.imageLoading = true
231
202
  this.previewVisible = true
232
-
233
203
  try {
234
204
  const fileInfo = await this.getFileInfo()
235
205
  if (!fileInfo) {
@@ -237,36 +207,29 @@ export default {
237
207
  this.imageError = true
238
208
  return
239
209
  }
240
-
241
210
  await this.setPreviewUrl(fileInfo)
242
-
243
- // 设置一个立即检查,防止缓存图片不触发load事件
244
211
  this.$nextTick(() => {
245
212
  setTimeout(() => {
246
213
  if (this.imageLoading && this.$refs.previewImage && this.$refs.previewImage.complete) {
247
214
  this.handleImageLoad()
248
215
  }
249
- }, 300) // 300ms后检查
216
+ }, 300)
250
217
  })
251
-
252
- // 设置超时,防止图片加载事件未触发
253
218
  this.loadingTimeout = setTimeout(() => {
254
219
  if (this.imageLoading) {
255
220
  console.warn('图片加载超时,强制结束加载状态')
256
221
  this.imageLoading = false
257
- // 检查图片是否已经加载完成
258
222
  if (this.$refs.previewImage && this.$refs.previewImage.complete) {
259
223
  this.handleImageLoad()
260
224
  }
261
225
  }
262
- }, 2000) // 2秒超时
226
+ }, 2000)
263
227
  } catch (error) {
264
228
  console.error('打开预览对话框失败:', error)
265
229
  this.imageLoading = false
266
230
  this.imageError = true
267
231
  }
268
232
  },
269
-
270
233
  async setPreviewUrl(fileInfo) {
271
234
  let newUrl
272
235
  if (this.isPrivate && fileInfo.url) {
@@ -278,22 +241,13 @@ export default {
278
241
  } else {
279
242
  newUrl = fileInfo.url || this.fullPath
280
243
  }
281
-
282
- // 先清空URL,强制重新加载(即使URL相同)
283
244
  if (this.previewUrl) {
284
245
  this.previewUrl = ''
285
- // 等待一个tick确保DOM更新
286
246
  await this.$nextTick()
287
247
  }
288
-
289
- // 设置新的URL
290
248
  this.previewUrl = newUrl
291
-
292
- // 等待DOM更新后检查图片是否已经加载完成
293
249
  this.$nextTick(() => {
294
- // 如果图片元素存在且已经加载完成,直接触发加载完成事件
295
250
  if (this.$refs.previewImage && this.$refs.previewImage.complete) {
296
- // 小延迟确保图片完全渲染
297
251
  setTimeout(() => {
298
252
  if (this.imageLoading) {
299
253
  this.handleImageLoad()
@@ -302,26 +256,51 @@ export default {
302
256
  }
303
257
  })
304
258
  },
305
-
306
259
  async onDownload() {
307
260
  const fileInfo = await this.getFileInfo()
308
261
  const url = fileInfo?.url || this.fullPath
309
262
  this.$emit('download', url, this.fileName)
310
263
  },
311
264
 
265
+ // ✅ 图片加载完成:自适应铺满 + 居中
312
266
  handleImageLoad() {
313
- // 清理超时
314
267
  if (this.loadingTimeout) {
315
268
  clearTimeout(this.loadingTimeout)
316
269
  this.loadingTimeout = null
317
270
  }
318
271
  this.imageLoading = false
319
- // 图片加载完成后自动居中
320
- this.resetImage()
272
+ this.$nextTick(() => {
273
+ const img = this.$refs.previewImage
274
+ const container = this.$refs.previewContainer
275
+ if (!img || !container) return
276
+
277
+ const cw = container.clientWidth
278
+ const ch = container.clientHeight
279
+ const iw = img.naturalWidth
280
+ const ih = img.naturalHeight
281
+ if (!iw || !ih || !cw || !ch) return
282
+
283
+ // 记录原始尺寸(后续 zoom/rotate 需要)
284
+ this.imgNaturalWidth = iw
285
+ this.imgNaturalHeight = ih
286
+
287
+ // ✅ 自适应比例:contain 铺满容器
288
+ this.initScale = Math.min(cw / iw, ch / ih)
289
+ this.scale = this.initScale
290
+ this.rotation = 0
291
+
292
+ // ✅ 动态缩放边界:自适应比例 × [0.1, 10],至少允许 5 倍放大
293
+ this.minScale = this.initScale * 0.1
294
+ this.maxScale = Math.max(this.initScale * 10, 5)
295
+
296
+ // ✅ 居中:transform-origin 是 center center,
297
+ // 图片布局盒子的中心在 (iw/2, ih/2),需要平移到 (cw/2, ch/2)
298
+ this.position.x = (cw - iw) / 2
299
+ this.position.y = (ch - ih) / 2
300
+ })
321
301
  },
322
302
 
323
303
  handleImageError() {
324
- // 清理超时
325
304
  if (this.loadingTimeout) {
326
305
  clearTimeout(this.loadingTimeout)
327
306
  this.loadingTimeout = null
@@ -330,36 +309,42 @@ export default {
330
309
  this.imageError = true
331
310
  },
332
311
 
333
- // 鼠标滚轮缩放 - 以鼠标为中心点缩放
312
+ /**
313
+ * 以 (anchorX, anchorY) 为锚点缩放。
314
+ * 在 transform-origin: center center 的变换模型下:
315
+ * p' = O + t + s·R·(p − O)
316
+ * 缩放前后锚点 p 在容器坐标不变,可解得:
317
+ * t_new = q − O − (s_new / s_old)·(q − O − t_old)
318
+ * 其中 O = (iw/2, ih/2) 为图片布局盒子中心。
319
+ */
320
+ zoomTo(newScale, anchorX, anchorY) {
321
+ newScale = Math.max(this.minScale, Math.min(this.maxScale, newScale))
322
+ if (Math.abs(this.scale - newScale) < 0.0001) return
323
+
324
+ const Ox = this.imgNaturalWidth / 2
325
+ const Oy = this.imgNaturalHeight / 2
326
+ const k = newScale / this.scale
327
+
328
+ this.position.x = anchorX - Ox - k * (anchorX - Ox - this.position.x)
329
+ this.position.y = anchorY - Oy - k * (anchorY - Oy - this.position.y)
330
+ this.scale = newScale
331
+ },
332
+
334
333
  handleWheel(event) {
335
334
  event.preventDefault()
336
-
337
- const delta = event.deltaY < 0 ? 0.1 : -0.1
338
- const newScale = Math.max(this.minScale, Math.min(this.maxScale, this.scale + delta))
339
-
340
- // 计算缩放中心(相对于图片)
335
+ // ✅ 乘法缩放:手感顺滑,且不受当前 scale 大小影响
336
+ const factor = event.deltaY < 0 ? 1.15 : 1 / 1.15
337
+ const newScale = this.scale * factor
341
338
  if (this.$refs.previewContainer) {
342
- const containerRect = this.$refs.previewContainer.getBoundingClientRect()
343
- const mouseX = event.clientX - containerRect.left
344
- const mouseY = event.clientY - containerRect.top
345
-
346
- // 计算鼠标相对于图片原始坐标系的位置
347
- // 注意:position.x 和 position.y 是图片相对于容器的平移
348
- const relativeX = (mouseX - this.position.x) / this.scale
349
- const relativeY = (mouseY - this.position.y) / this.scale
350
-
351
- // 更新位置以保持鼠标点不变
352
- this.position.x = mouseX - relativeX * newScale
353
- this.position.y = mouseY - relativeY * newScale
354
- this.scale = newScale
355
- } else {
356
- this.scale = newScale
339
+ const rect = this.$refs.previewContainer.getBoundingClientRect()
340
+ const mouseX = event.clientX - rect.left
341
+ const mouseY = event.clientY - rect.top
342
+ this.zoomTo(newScale, mouseX, mouseY)
357
343
  }
358
344
  },
359
345
 
360
- // 开始拖拽
361
346
  startDrag(event) {
362
- if (event.button !== 0) return // 只响应左键
347
+ if (event.button !== 0) return
363
348
  this.isDragging = true
364
349
  this.startPosition = {
365
350
  x: event.clientX - this.position.x,
@@ -367,73 +352,87 @@ export default {
367
352
  }
368
353
  event.preventDefault()
369
354
  },
370
-
371
- // 处理拖拽
372
355
  handleDrag(event) {
373
356
  if (!this.isDragging) return
374
-
375
357
  this.position.x = event.clientX - this.startPosition.x
376
358
  this.position.y = event.clientY - this.startPosition.y
377
359
  },
378
-
379
- // 停止拖拽
380
360
  stopDrag() {
381
361
  this.isDragging = false
382
362
  },
383
363
 
384
- // 放大
385
364
  zoomIn() {
386
- const newScale = Math.min(this.maxScale, this.scale + 0.2)
387
- if (newScale !== this.scale) {
388
- this.centerZoom(newScale)
389
- }
365
+ const container = this.$refs.previewContainer
366
+ if (!container) return
367
+ const cx = container.clientWidth / 2
368
+ const cy = container.clientHeight / 2
369
+ // ✅ 乘法缩放:每次放大 20%
370
+ this.zoomTo(this.scale * 1.2, cx, cy)
390
371
  },
391
-
392
- // 缩小
393
372
  zoomOut() {
394
- const newScale = Math.max(this.minScale, this.scale - 0.2)
395
- if (newScale !== this.scale) {
396
- this.centerZoom(newScale)
397
- }
373
+ const container = this.$refs.previewContainer
374
+ if (!container) return
375
+ const cx = container.clientWidth / 2
376
+ const cy = container.clientHeight / 2
377
+ this.zoomTo(this.scale / 1.2, cx, cy)
398
378
  },
399
379
 
400
- // 以当前视图中心点缩放(用于工具栏按钮)
401
- centerZoom(newScale) {
402
- if (this.$refs.previewContainer) {
403
- const containerRect = this.$refs.previewContainer.getBoundingClientRect()
404
- // 使用容器中心作为缩放中心点
405
- const centerX = containerRect.width / 2
406
- const centerY = containerRect.height / 2
407
-
408
- // 计算中心点相对于图片原始坐标系的位置
409
- const relativeX = (centerX - this.position.x) / this.scale
410
- const relativeY = (centerY - this.position.y) / this.scale
411
-
412
- // 更新位置以保持中心点不变
413
- this.position.x = centerX - relativeX * newScale
414
- this.position.y = centerY - relativeY * newScale
415
- }
416
- this.scale = newScale
380
+ rotateLeft() {
381
+ this.enableTransition = false
382
+ this.rotation = (this.rotation - 90 + 360) % 360
383
+ this.$nextTick(() => {
384
+ setTimeout(() => {
385
+ this.enableTransition = true
386
+ }, 0)
387
+ })
388
+ },
389
+ rotateRight() {
390
+ this.enableTransition = false
391
+ this.rotation = (this.rotation + 90) % 360
392
+ this.$nextTick(() => {
393
+ setTimeout(() => {
394
+ this.enableTransition = true
395
+ }, 0)
396
+ })
417
397
  },
418
398
 
419
- // 重置图片位置和大小
399
+ // ✅ 重置:角度归零,scale 回到自适应比例,重新居中
420
400
  resetImage() {
421
- this.position = { x: 0, y: 0 }
422
- this.scale = 1
401
+ const img = this.$refs.previewImage
402
+ const container = this.$refs.previewContainer
403
+ if (!img || !container) return
404
+
405
+ const cw = container.clientWidth
406
+ const ch = container.clientHeight
407
+ const iw = img.naturalWidth || this.imgNaturalWidth
408
+ const ih = img.naturalHeight || this.imgNaturalHeight
409
+ if (!iw || !ih || !cw || !ch) return
410
+
411
+ this.rotation = 0
412
+ this.scale = this.initScale
413
+
414
+ // transform-origin: center center,居中平移量 = (cw - iw)/2, (ch - ih)/2
415
+ this.position.x = (cw - iw) / 2
416
+ this.position.y = (ch - ih) / 2
423
417
  },
424
418
 
425
- // 重置所有状态
426
419
  resetState() {
427
- // 清理超时
428
420
  if (this.loadingTimeout) {
429
421
  clearTimeout(this.loadingTimeout)
430
422
  this.loadingTimeout = null
431
423
  }
432
424
  this.position = { x: 0, y: 0 }
433
425
  this.scale = 1
426
+ this.minScale = 0.1
427
+ this.maxScale = 5
428
+ this.rotation = 0
429
+ this.initScale = 1
430
+ this.imgNaturalWidth = 0
431
+ this.imgNaturalHeight = 0
434
432
  this.imageLoading = false
435
433
  this.imageError = false
436
434
  this.isDragging = false
435
+ this.enableTransition = true
437
436
  }
438
437
  }
439
438
  }
@@ -442,59 +441,42 @@ export default {
442
441
  <style lang="scss" scoped>
443
442
  .file-preview {
444
443
  display: inline-block;
445
-
446
444
  .preview-link {
447
445
  color: #409eff;
448
446
  cursor: pointer;
449
447
  text-decoration: none;
450
448
  transition: color 0.2s;
451
-
452
449
  &:hover {
453
450
  color: #66b1ff;
454
451
  text-decoration: underline;
455
452
  }
456
453
  }
457
454
  }
458
-
459
455
  .preview-wrapper {
460
456
  width: 100%;
461
- height: 750px;
457
+ /* 撑满对话框内容区(高度由 nm-dialog 的 height 决定),
458
+ 不写固定高度,避免弹窗缩放/全屏后图片区与内容区高度不一致 */
459
+ height: 100%;
462
460
  background: #000;
463
461
  position: relative;
464
462
  overflow: hidden;
465
- display: flex;
466
- align-items: center;
467
- justify-content: center;
468
463
  }
469
-
470
464
  .preview-container {
471
465
  width: 100%;
472
466
  height: 100%;
473
- display: flex;
474
- align-items: center;
475
- justify-content: center;
476
467
  position: relative;
477
468
  overflow: hidden;
478
469
  touch-action: none;
479
- /* 防止移动端默认行为 */
480
470
  }
481
-
482
471
  .preview-image {
483
- max-width: 100%;
484
- max-height: 100%;
485
- object-fit: contain;
486
- /* 关键:保持比例并适应容器 */
487
- transform-origin: 0 0;
488
- /* 设置为左上角以匹配我们的数学计算 */
489
- transition: transform 0.2s ease;
490
472
  user-select: none;
491
473
  -webkit-user-drag: none;
492
-
493
- /* 平滑的拖拽和缩放效果 */
494
474
  will-change: transform;
475
+ /* ✅ 绝对定位在左上角,保证 transform 计算以容器 (0,0) 为基准 */
476
+ position: absolute;
477
+ top: 0;
478
+ left: 0;
495
479
  }
496
-
497
- /* 操作工具栏 */
498
480
  .toolbar {
499
481
  position: absolute;
500
482
  bottom: 20px;
@@ -507,7 +489,6 @@ export default {
507
489
  border-radius: 4px;
508
490
  z-index: 10;
509
491
  }
510
-
511
492
  .toolbar-btn {
512
493
  display: flex;
513
494
  align-items: center;
@@ -521,21 +502,17 @@ export default {
521
502
  cursor: pointer;
522
503
  font-size: 12px;
523
504
  transition: all 0.2s;
524
-
525
505
  &:hover {
526
506
  background: rgba(255, 255, 255, 0.2);
527
507
  border-color: rgba(255, 255, 255, 0.3);
528
508
  }
529
-
530
509
  &:active {
531
510
  transform: scale(0.95);
532
511
  }
533
-
534
512
  .icon {
535
513
  font-size: 14px;
536
514
  font-weight: bold;
537
515
  }
538
-
539
516
  .text {
540
517
  white-space: nowrap;
541
518
  }
@@ -543,23 +520,38 @@ export default {
543
520
  </style>
544
521
 
545
522
  <style lang="scss">
546
- /* 对话框全局样式 */
547
523
  .image-preview-dialog {
548
524
  .el-dialog {
549
525
  background: #000;
550
526
  border: 1px solid #333;
551
527
  }
552
-
553
528
  .el-dialog__header {
554
529
  background: #000;
555
530
  border-bottom: 1px solid #333;
556
531
  padding: 10px 20px;
557
532
 
558
- .el-dialog__title {
533
+ /* nm-dialog 的标题结构:图标 + 标题 + 工具栏(全屏/关闭按钮) */
534
+ .nm-dialog-title {
559
535
  color: #fff;
560
536
  font-size: 14px;
537
+ cursor: move; /* 与 draggable 配合,提示可拖动 */
561
538
  }
562
539
 
540
+ .nm-dialog-icon {
541
+ color: #fff;
542
+ }
543
+
544
+ /* 工具栏里的全屏/关闭按钮:深色底上要显示为白色,
545
+ 否则继承框架默认深色图标导致看不见 */
546
+ .nm-dialog-toolbar .nm-button {
547
+ color: #fff;
548
+
549
+ &:hover {
550
+ color: #409eff;
551
+ }
552
+ }
553
+
554
+ /* 兼容 element-ui 原生关闭按钮 */
563
555
  .el-dialog__close {
564
556
  color: #fff;
565
557
 
@@ -568,11 +560,10 @@ export default {
568
560
  }
569
561
  }
570
562
  }
571
-
572
563
  .el-dialog__body {
573
564
  padding: 0 !important;
574
565
  background: #000 !important;
575
566
  overflow: hidden !important;
576
567
  }
577
568
  }
578
- </style>
569
+ </style>