djm-ui 0.72.0 → 0.73.0

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,8 +1,8 @@
1
1
  {
2
2
  "name": "djm-ui",
3
3
  "displayName": "DJM UI",
4
- "version": "0.72.0",
5
- "generatedAt": "2026-10-26T09:23:17.100Z",
4
+ "version": "0.73.0",
5
+ "generatedAt": "2026-10-26T09:46:53.848Z",
6
6
  "docs": "https://ui.duojumi.com/docs/",
7
7
  "homepage": "https://ui.duojumi.com",
8
8
  "repository": "https://yohan.cloud:8081/DJM/dimui.git",
@@ -12,7 +12,7 @@
12
12
  "stats": {
13
13
  "components": 105,
14
14
  "categories": 11,
15
- "props": 623
15
+ "props": 632
16
16
  },
17
17
  "categories": [
18
18
  {
@@ -50,7 +50,8 @@
50
50
  "affix",
51
51
  "splitter",
52
52
  "grid",
53
- "layout"
53
+ "layout",
54
+ "glass"
54
55
  ]
55
56
  },
56
57
  {
@@ -189,7 +190,7 @@
189
190
  "title": "2. 浏览器直接引入",
190
191
  "text": "UMD 版本复用全局 Vue,不会重复打包 Vue。Vue 必须先加载,再加载组件库和样式。",
191
192
  "file": "index.html",
192
- "code": "<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/djm-ui@0.72.0/dist/djm-ui.min.css\" />\n<script src=\"https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/djm-ui@0.72.0/dist/djm-ui.umd.min.js\"></script>\n\n<script>\n Vue.createApp({\n template: '<DjmButton variant=\"primary\">按钮</DjmButton>'\n }).use(DjmUI).mount('#app')\n</script>"
193
+ "code": "<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/djm-ui@0.73.0/dist/djm-ui.min.css\" />\n<script src=\"https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/djm-ui@0.73.0/dist/djm-ui.umd.min.js\"></script>\n\n<script>\n Vue.createApp({\n template: '<DjmButton variant=\"primary\">按钮</DjmButton>'\n }).use(DjmUI).mount('#app')\n</script>"
193
194
  },
194
195
  {
195
196
  "title": "3. 全量注册",
@@ -2141,7 +2142,7 @@
2141
2142
  "slug": "progress",
2142
2143
  "title": "Progress 进度条",
2143
2144
  "category": "展示",
2144
- "description": "横向进度,支持成功 / 警告 / 失败配色与自定义高度。",
2145
+ "description": "横向与环形两种形态,支持成功 / 警告 / 失败配色与自定义高度。",
2145
2146
  "docUrl": "https://ui.duojumi.com/docs/index.html#/progress",
2146
2147
  "aliases": [
2147
2148
  "progress",
@@ -2155,6 +2156,12 @@
2155
2156
  "default": "0",
2156
2157
  "description": "进度百分比,超出自动收敛到 0–100"
2157
2158
  },
2159
+ {
2160
+ "name": "type",
2161
+ "type": "string",
2162
+ "default": "'line'",
2163
+ "description": "line 横向 / circle 环形"
2164
+ },
2158
2165
  {
2159
2166
  "name": "status",
2160
2167
  "type": "string",
@@ -2165,24 +2172,36 @@
2165
2172
  "name": "show-text",
2166
2173
  "type": "boolean",
2167
2174
  "default": "true",
2168
- "description": "是否显示右侧百分比"
2175
+ "description": "是否显示百分比"
2169
2176
  },
2170
2177
  {
2171
2178
  "name": "stroke-width",
2172
2179
  "type": "number",
2173
2180
  "default": "6",
2174
- "description": "进度条高度"
2181
+ "description": "进度条粗细"
2175
2182
  },
2176
2183
  {
2177
2184
  "name": "color",
2178
2185
  "type": "string",
2179
2186
  "default": "''",
2180
2187
  "description": "自定义进度色,优先于状态色"
2188
+ },
2189
+ {
2190
+ "name": "size",
2191
+ "type": "number",
2192
+ "default": "96",
2193
+ "description": "环形直径(px)"
2194
+ },
2195
+ {
2196
+ "name": "label",
2197
+ "type": "string",
2198
+ "default": "''",
2199
+ "description": "无障碍名称,默认「进度」"
2181
2200
  }
2182
2201
  ],
2183
2202
  "events": [],
2184
2203
  "slots": [],
2185
- "example": "<div class=\"djm-docs-stack\">\n <DjmProgress :percent=\"32\" />\n <DjmProgress :percent=\"64\" status=\"success\" />\n <DjmProgress :percent=\"86\" status=\"warning\" />\n <DjmProgress :percent=\"100\" status=\"error\" />\n </div>",
2204
+ "example": "<div class=\"djm-docs-stack\">\n <div class=\"djm-docs-inline\" style=\"gap: 24px; align-items: center\">\n <DjmProgress type=\"circle\" :percent=\"32\" />\n <DjmProgress type=\"circle\" :percent=\"64\" status=\"success\" :size=\"80\" />\n <DjmProgress type=\"circle\" :percent=\"86\" status=\"warning\" :size=\"80\" />\n <DjmProgress type=\"circle\" :percent=\"100\" status=\"error\" :size=\"80\" />\n </div>\n <DjmProgress :percent=\"32\" />\n <DjmProgress :percent=\"64\" status=\"success\" />\n <DjmProgress :percent=\"86\" status=\"warning\" />\n <DjmProgress :percent=\"100\" status=\"error\" />\n </div>",
2186
2205
  "blocks": [],
2187
2206
  "dsl": {
2188
2207
  "component": "DjmProgress",
@@ -2192,6 +2211,11 @@
2192
2211
  "default": "0",
2193
2212
  "description": "进度百分比,超出自动收敛到 0–100"
2194
2213
  },
2214
+ "type": {
2215
+ "type": "string",
2216
+ "default": "'line'",
2217
+ "description": "line 横向 / circle 环形"
2218
+ },
2195
2219
  "status": {
2196
2220
  "type": "string",
2197
2221
  "default": "''",
@@ -2200,17 +2224,27 @@
2200
2224
  "show-text": {
2201
2225
  "type": "boolean",
2202
2226
  "default": "true",
2203
- "description": "是否显示右侧百分比"
2227
+ "description": "是否显示百分比"
2204
2228
  },
2205
2229
  "stroke-width": {
2206
2230
  "type": "number",
2207
2231
  "default": "6",
2208
- "description": "进度条高度"
2232
+ "description": "进度条粗细"
2209
2233
  },
2210
2234
  "color": {
2211
2235
  "type": "string",
2212
2236
  "default": "''",
2213
2237
  "description": "自定义进度色,优先于状态色"
2238
+ },
2239
+ "size": {
2240
+ "type": "number",
2241
+ "default": "96",
2242
+ "description": "环形直径(px)"
2243
+ },
2244
+ "label": {
2245
+ "type": "string",
2246
+ "default": "''",
2247
+ "description": "无障碍名称,默认「进度」"
2214
2248
  }
2215
2249
  },
2216
2250
  "events": [],
@@ -10188,7 +10222,7 @@
10188
10222
  "slug": "spin",
10189
10223
  "title": "Spin 加载中",
10190
10224
  "category": "反馈",
10191
- "description": "单独使用时是转圈提示,包裹内容时在内容上盖一层遮罩。",
10225
+ "description": "四种形态:环形、点状、柱状、脉冲;支持延迟显示、全屏遮罩与自定义指示器。",
10192
10226
  "docUrl": "https://ui.duojumi.com/docs/index.html#/spin",
10193
10227
  "aliases": [
10194
10228
  "spin",
@@ -10202,6 +10236,12 @@
10202
10236
  "default": "true",
10203
10237
  "description": "包裹模式下是否显示遮罩"
10204
10238
  },
10239
+ {
10240
+ "name": "type",
10241
+ "type": "string",
10242
+ "default": "'ring'",
10243
+ "description": "ring 环形 / dots 点状 / bars 柱状 / pulse 脉冲"
10244
+ },
10205
10245
  {
10206
10246
  "name": "size",
10207
10247
  "type": "string",
@@ -10217,7 +10257,25 @@
10217
10257
  "name": "tip",
10218
10258
  "type": "string",
10219
10259
  "default": "''",
10220
- "description": "转圈旁的文字"
10260
+ "description": "指示器旁的文字"
10261
+ },
10262
+ {
10263
+ "name": "delay",
10264
+ "type": "number",
10265
+ "default": "0",
10266
+ "description": "延迟多少毫秒后显示,避免快速请求闪一下"
10267
+ },
10268
+ {
10269
+ "name": "fullscreen",
10270
+ "type": "boolean",
10271
+ "default": "false",
10272
+ "description": "遮罩铺满视口"
10273
+ },
10274
+ {
10275
+ "name": "color",
10276
+ "type": "string",
10277
+ "default": "''",
10278
+ "description": "自定义指示器颜色,默认跟随品牌色"
10221
10279
  }
10222
10280
  ],
10223
10281
  "events": [],
@@ -10225,9 +10283,13 @@
10225
10283
  {
10226
10284
  "name": "default",
10227
10285
  "description": "被包裹的内容,传入即为包裹模式"
10286
+ },
10287
+ {
10288
+ "name": "indicator",
10289
+ "description": "自定义加载指示器"
10228
10290
  }
10229
10291
  ],
10230
- "example": "<div class=\"djm-demo-stack\">\n <div class=\"djm-docs-inline\">\n <DjmSpin />\n <DjmSpin size=\"sm\" />\n <DjmSpin size=\"lg\" />\n <DjmSpin tip=\"正在加载\" />\n </div>\n <div class=\"djm-docs-inline\">\n <DjmSpin :spinning=\"loading\" tip=\"加载中\">\n <div class=\"djm-spin-demo\">\n <div class=\"djm-demo-note\">\n <strong>组织架构同步</strong>\n <p>最近一次同步:2026-10-24 09:30,共 128 条记录。</p>\n </div>\n </div>\n </DjmSpin>\n <DjmButton size=\"sm\" @click=\"loading = !loading\">{{ loading ? '结束加载' : '开始加载' }}</DjmButton>\n </div>\n </div>",
10292
+ "example": "<div class=\"djm-demo-stack\">\n <div class=\"djm-docs-inline\">\n <DjmSpin />\n <DjmSpin type=\"dots\" />\n <DjmSpin type=\"bars\" />\n <DjmSpin type=\"pulse\" />\n <DjmSpin tip=\"正在加载\" />\n <DjmSpin type=\"dots\" color=\"#12855a\" tip=\"同步中\" />\n </div>\n <div class=\"djm-docs-inline\">\n <DjmSpin size=\"sm\" />\n <DjmSpin size=\"sm\" type=\"dots\" />\n <DjmSpin size=\"lg\" type=\"bars\" />\n <DjmSpin size=\"lg\" type=\"pulse\" />\n </div>\n <div class=\"djm-docs-inline\">\n <DjmSpin :spinning=\"loading\" tip=\"加载中\" type=\"dots\">\n <div class=\"djm-spin-demo\">\n <div class=\"djm-demo-note\">\n <strong>组织架构同步</strong>\n <p>最近一次同步:2026-10-24 09:30,共 128 条记录。</p>\n </div>\n </div>\n </DjmSpin>\n <DjmButton size=\"sm\" @click=\"loading = !loading\">{{ loading ? '结束加载' : '开始加载' }}</DjmButton>\n <DjmButton size=\"sm\" @click=\"showFullscreen\">全屏加载</DjmButton>\n <DjmSpin :spinning=\"fullscreen\" fullscreen tip=\"正在准备数据\" type=\"bars\" />\n </div>\n </div>",
10231
10293
  "blocks": [],
10232
10294
  "dsl": {
10233
10295
  "component": "DjmSpin",
@@ -10237,6 +10299,11 @@
10237
10299
  "default": "true",
10238
10300
  "description": "包裹模式下是否显示遮罩"
10239
10301
  },
10302
+ "type": {
10303
+ "type": "string",
10304
+ "default": "'ring'",
10305
+ "description": "ring 环形 / dots 点状 / bars 柱状 / pulse 脉冲"
10306
+ },
10240
10307
  "size": {
10241
10308
  "type": "string",
10242
10309
  "default": "'md'",
@@ -10250,12 +10317,28 @@
10250
10317
  "tip": {
10251
10318
  "type": "string",
10252
10319
  "default": "''",
10253
- "description": "转圈旁的文字"
10320
+ "description": "指示器旁的文字"
10321
+ },
10322
+ "delay": {
10323
+ "type": "number",
10324
+ "default": "0",
10325
+ "description": "延迟多少毫秒后显示,避免快速请求闪一下"
10326
+ },
10327
+ "fullscreen": {
10328
+ "type": "boolean",
10329
+ "default": "false",
10330
+ "description": "遮罩铺满视口"
10331
+ },
10332
+ "color": {
10333
+ "type": "string",
10334
+ "default": "''",
10335
+ "description": "自定义指示器颜色,默认跟随品牌色"
10254
10336
  }
10255
10337
  },
10256
10338
  "events": [],
10257
10339
  "slots": [
10258
- "default"
10340
+ "default",
10341
+ "indicator"
10259
10342
  ]
10260
10343
  }
10261
10344
  },
@@ -10603,6 +10686,12 @@
10603
10686
  "type": "boolean",
10604
10687
  "default": "false",
10605
10688
  "description": "全屏铺满,内容区撑满剩余高度"
10689
+ },
10690
+ {
10691
+ "name": "glass",
10692
+ "type": "boolean",
10693
+ "default": "false",
10694
+ "description": "毛玻璃底,需要透出背后页面时使用"
10606
10695
  }
10607
10696
  ],
10608
10697
  "events": [
@@ -10675,6 +10764,11 @@
10675
10764
  "type": "boolean",
10676
10765
  "default": "false",
10677
10766
  "description": "全屏铺满,内容区撑满剩余高度"
10767
+ },
10768
+ "glass": {
10769
+ "type": "boolean",
10770
+ "default": "false",
10771
+ "description": "毛玻璃底,需要透出背后页面时使用"
10678
10772
  }
10679
10773
  },
10680
10774
  "events": [
@@ -10855,6 +10949,12 @@
10855
10949
  "type": "boolean",
10856
10950
  "default": "true",
10857
10951
  "description": "允许 Esc 关闭"
10952
+ },
10953
+ {
10954
+ "name": "glass",
10955
+ "type": "boolean",
10956
+ "default": "false",
10957
+ "description": "毛玻璃底"
10858
10958
  }
10859
10959
  ],
10860
10960
  "events": [
@@ -10931,6 +11031,11 @@
10931
11031
  "type": "boolean",
10932
11032
  "default": "true",
10933
11033
  "description": "允许 Esc 关闭"
11034
+ },
11035
+ "glass": {
11036
+ "type": "boolean",
11037
+ "default": "false",
11038
+ "description": "毛玻璃底"
10934
11039
  }
10935
11040
  },
10936
11041
  "events": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "djm-ui",
3
- "version": "0.72.0",
3
+ "version": "0.73.0",
4
4
  "description": "DJM UI — 企业级中后台 Vue 3 组件库",
5
5
  "homepage": "https://ui.duojumi.com",
6
6
  "repository": {
@@ -23,7 +23,9 @@ export default {
23
23
  // 点击遮罩关闭
24
24
  maskClosable: { type: Boolean, default: true },
25
25
  showClose: { type: Boolean, default: true },
26
- closeOnEsc: { type: Boolean, default: true }
26
+ closeOnEsc: { type: Boolean, default: true },
27
+ // 毛玻璃底
28
+ glass: { type: Boolean, default: false }
27
29
  },
28
30
  emits: ['update:modelValue', 'open', 'close'],
29
31
  setup (props, { emit }) {
@@ -96,7 +98,7 @@ export default {
96
98
  <aside
97
99
  ref="panelRef"
98
100
  class="djm-drawer"
99
- :class="'djm-drawer-' + placement"
101
+ :class="['djm-drawer-' + placement, { 'djm-is-glass': glass }]"
100
102
  :style="panelStyle"
101
103
  role="dialog"
102
104
  aria-modal="true"
@@ -19,7 +19,9 @@ export default {
19
19
  // 是否允许 Esc 关闭
20
20
  closeOnEsc: { type: Boolean, default: true },
21
21
  // 全屏铺满,适合配置类大表单
22
- fullscreen: { type: Boolean, default: false }
22
+ fullscreen: { type: Boolean, default: false },
23
+ // 毛玻璃底:需要显示背后页面时使用
24
+ glass: { type: Boolean, default: false }
23
25
  },
24
26
  emits: ['update:modelValue', 'open', 'close'],
25
27
  setup (props, { emit }) {
@@ -97,7 +99,7 @@ export default {
97
99
  <div
98
100
  ref="dialogRef"
99
101
  class="djm-modal"
100
- :class="{ 'djm-is-fullscreen': fullscreen }"
102
+ :class="{ 'djm-is-fullscreen': fullscreen, 'djm-is-glass': glass }"
101
103
  :style="dialogStyle"
102
104
  role="dialog"
103
105
  aria-modal="true"
@@ -1,17 +1,24 @@
1
1
  /**
2
- * 进度条:横向进度,支持语义状态与自定义高度
2
+ * 进度条:横向与环形两种形态,支持语义状态与自定义高度
3
3
  * 用法:<DjmProgress :percent="60" status="success" />
4
+ * <DjmProgress type="circle" :percent="72" :size="96" />
4
5
  */
5
6
  export default {
6
7
  name: 'DjmProgress',
7
8
  props: {
8
9
  percent: { type: Number, default: 0 },
10
+ // line 横向 / circle 环形
11
+ type: { type: String, default: 'line' },
9
12
  // '' / success / error / warning
10
13
  status: { type: String, default: '' },
11
14
  showText: { type: Boolean, default: true },
12
15
  strokeWidth: { type: Number, default: 6 },
13
16
  // 自定义进度色,不传由状态决定
14
- color: { type: String, default: '' }
17
+ color: { type: String, default: '' },
18
+ // 环形直径(px)
19
+ size: { type: Number, default: 96 },
20
+ // 无障碍名称,默认「进度」
21
+ label: { type: String, default: '' }
15
22
  },
16
23
  computed: {
17
24
  safePercent () {
@@ -24,10 +31,72 @@ export default {
24
31
  },
25
32
  trackStyle () {
26
33
  return { height: this.strokeWidth + 'px' }
34
+ },
35
+ circleSize () {
36
+ return Math.max(48, Number(this.size) || 96)
37
+ },
38
+ circleRadius () {
39
+ return (this.circleSize - this.strokeWidth) / 2
40
+ },
41
+ circleLength () {
42
+ return 2 * Math.PI * this.circleRadius
43
+ },
44
+ circleOffset () {
45
+ return this.circleLength * (1 - this.safePercent / 100)
46
+ },
47
+ circleStyle () {
48
+ return { width: this.circleSize + 'px', height: this.circleSize + 'px' }
49
+ },
50
+ circleLabelStyle () {
51
+ return { fontSize: Math.max(12, Math.round(this.circleSize / 5)) + 'px' }
27
52
  }
28
53
  },
29
54
  template: `
30
- <div class="djm-progress-line" :class="status ? 'djm-is-' + status : ''">
55
+ <div
56
+ v-if="type === 'circle'"
57
+ class="djm-progress-circle"
58
+ :class="status ? 'djm-is-' + status : ''"
59
+ :style="circleStyle"
60
+ role="progressbar"
61
+ :aria-label="label || '进度'"
62
+ :aria-valuenow="safePercent"
63
+ aria-valuemin="0"
64
+ aria-valuemax="100"
65
+ >
66
+ <svg :viewBox="'0 0 ' + circleSize + ' ' + circleSize" aria-hidden="true">
67
+ <circle
68
+ class="djm-progress-circle-track"
69
+ :cx="circleSize / 2"
70
+ :cy="circleSize / 2"
71
+ :r="circleRadius"
72
+ :stroke-width="strokeWidth"
73
+ fill="none"
74
+ />
75
+ <circle
76
+ class="djm-progress-circle-bar"
77
+ :cx="circleSize / 2"
78
+ :cy="circleSize / 2"
79
+ :r="circleRadius"
80
+ :stroke-width="strokeWidth"
81
+ fill="none"
82
+ stroke-linecap="round"
83
+ :stroke-dasharray="circleLength"
84
+ :stroke-dashoffset="circleOffset"
85
+ :style="color ? { stroke: color } : null"
86
+ />
87
+ </svg>
88
+ <span v-if="showText" class="djm-progress-circle-label" :style="circleLabelStyle">{{ safePercent }}%</span>
89
+ </div>
90
+ <div
91
+ v-else
92
+ class="djm-progress-line"
93
+ :class="status ? 'djm-is-' + status : ''"
94
+ role="progressbar"
95
+ :aria-label="label || '进度'"
96
+ :aria-valuenow="safePercent"
97
+ aria-valuemin="0"
98
+ aria-valuemax="100"
99
+ >
31
100
  <div class="djm-progress" :style="trackStyle">
32
101
  <div class="djm-progress-bar" :style="barStyle"></div>
33
102
  </div>
@@ -1,42 +1,89 @@
1
1
  /**
2
- * 加载中:单独使用是转圈提示;包裹内容时在内容上盖一层遮罩
3
- * 用法:<DjmSpin /> / <DjmSpin :spinning="loading" tip="加载中"><Table /></DjmSpin>
2
+ * 加载中:支持环形、点状、柱状、脉冲四种形态
3
+ * 用法:<DjmSpin /> / <DjmSpin type="dots" /> / <DjmSpin :spinning="loading" tip="加载中"><Table /></DjmSpin>
4
+ * 延迟显示:<DjmSpin :delay="300" />,避免快速请求时闪一下
4
5
  */
6
+ import { onBeforeUnmount, ref, watch } from 'vue'
7
+
5
8
  export default {
6
9
  name: 'DjmSpin',
7
10
  props: {
8
11
  spinning: { type: Boolean, default: true },
9
- size: { type: String, default: 'md' }, // sm | md | lg
10
- tip: { type: String, default: '' }
12
+ // sm | md | lg
13
+ size: { type: String, default: 'md' },
14
+ // ring 环形 / dots 点状 / bars 柱状 / pulse 脉冲
15
+ type: { type: String, default: 'ring' },
16
+ tip: { type: String, default: '' },
17
+ // 延迟多少毫秒后显示,0 表示立即
18
+ delay: { type: Number, default: 0 },
19
+ // 全屏加载:遮罩铺满视口
20
+ fullscreen: { type: Boolean, default: false },
21
+ // 自定义指示器颜色,默认跟随品牌色
22
+ color: { type: String, default: '' }
23
+ },
24
+ setup (props) {
25
+ const visible = ref(false)
26
+ let timer = null
27
+
28
+ function sync () {
29
+ window.clearTimeout(timer)
30
+ timer = null
31
+ if (!props.spinning) {
32
+ visible.value = false
33
+ return
34
+ }
35
+ if (props.delay > 0) {
36
+ timer = window.setTimeout(() => { visible.value = true }, props.delay)
37
+ } else {
38
+ visible.value = true
39
+ }
40
+ }
41
+
42
+ watch(() => [props.spinning, props.delay], sync, { immediate: true })
43
+ onBeforeUnmount(() => window.clearTimeout(timer))
44
+
45
+ return { visible }
11
46
  },
12
47
  computed: {
13
- // 有默认插槽即为包裹模式
14
48
  wrapped () {
15
49
  return !!this.$slots.default
50
+ },
51
+ rootClass () {
52
+ return [
53
+ 'djm-spin',
54
+ 'djm-spin-' + this.size,
55
+ {
56
+ 'djm-spin-wrap': this.wrapped && !this.fullscreen,
57
+ 'djm-spin-inline': !this.wrapped && !this.fullscreen,
58
+ 'djm-spin-fullscreen': this.fullscreen
59
+ }
60
+ ]
16
61
  }
17
62
  },
18
63
  template: `
19
64
  <div
20
- v-if="wrapped"
21
- class="djm-spin-wrap"
22
- :class="'djm-spin-' + size"
23
- :aria-busy="String(spinning)"
65
+ v-if="fullscreen || wrapped || visible"
66
+ :class="rootClass"
67
+ :aria-busy="String(visible)"
68
+ :role="visible ? 'status' : undefined"
69
+ :aria-label="!wrapped && !fullscreen && !tip && visible ? '加载中' : undefined"
24
70
  >
25
- <slot />
26
- <div v-if="spinning" class="djm-spin-mask" role="status">
27
- <span class="djm-spinner"></span>
71
+ <slot v-if="wrapped && !fullscreen" />
72
+ <div v-if="visible" class="djm-spin-mask">
73
+ <span class="djm-spin-indicator" :class="'djm-spin-' + type" :style="color ? { color } : null">
74
+ <slot name="indicator">
75
+ <i v-if="type === 'ring'" class="djm-spinner"></i>
76
+ <template v-else-if="type === 'dots'">
77
+ <i></i><i></i><i></i>
78
+ </template>
79
+ <template v-else-if="type === 'bars'">
80
+ <i></i><i></i><i></i><i></i>
81
+ </template>
82
+ <i v-else class="djm-spin-core"></i>
83
+ </slot>
84
+ </span>
28
85
  <span v-if="tip" class="djm-spin-tip">{{ tip }}</span>
29
86
  </div>
30
87
  </div>
31
- <span
32
- v-else
33
- class="djm-spin-inline"
34
- :class="'djm-spin-' + size"
35
- role="status"
36
- :aria-label="tip ? undefined : '加载中'"
37
- >
38
- <span class="djm-spinner"></span>
39
- <span v-if="tip" class="djm-spin-tip">{{ tip }}</span>
40
- </span>
41
88
  `
42
89
  }
package/src/index.js CHANGED
@@ -228,6 +228,7 @@ export { moveRows } from './utils/row-move.js'
228
228
  export { setLocale, getLocale, t, localeState } from './locale/index.js'
229
229
  export {
230
230
  theme, setTheme, toggleTheme, initTheme,
231
+ glass, setGlass,
231
232
  primaryColor, PRESET_COLORS, setPrimaryColor, resetPrimaryColor
232
233
  } from './theme/index.js'
233
234
  export { setPermissions, addPermissions, clearPermissions, hasPermission, vPermission } from './utils/permission.js'
@@ -345,7 +346,7 @@ const components = [
345
346
  DjmPageTabs
346
347
  ]
347
348
 
348
- export const version = '0.72.0'
349
+ export const version = '0.73.0'
349
350
 
350
351
  export function install (app, options = {}) {
351
352
  if (options.locale) setLocale(options.locale)
@@ -194,6 +194,52 @@
194
194
  background: var(--djm-amber);
195
195
  }
196
196
 
197
+ /* 环形进度:SVG 逆时针起点在顶部,进度用 dashoffset 控制 */
198
+ .djm-progress-circle {
199
+ position: relative;
200
+ display: inline-flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ }
204
+
205
+ .djm-progress-circle svg {
206
+ width: 100%;
207
+ height: 100%;
208
+ transform: rotate(-90deg);
209
+ }
210
+
211
+ .djm-progress-circle-track {
212
+ stroke: var(--djm-border);
213
+ }
214
+
215
+ .djm-progress-circle-bar {
216
+ stroke: var(--djm-brand-600);
217
+ transition: stroke-dashoffset 0.3s;
218
+ }
219
+
220
+ .djm-progress-circle.djm-is-success .djm-progress-circle-bar {
221
+ stroke: var(--djm-green-strong);
222
+ }
223
+
224
+ .djm-progress-circle.djm-is-error .djm-progress-circle-bar {
225
+ stroke: var(--djm-red-strong);
226
+ }
227
+
228
+ .djm-progress-circle.djm-is-warning .djm-progress-circle-bar {
229
+ stroke: var(--djm-amber);
230
+ }
231
+
232
+ .djm-progress-circle-label {
233
+ position: absolute;
234
+ inset: 0;
235
+ display: flex;
236
+ align-items: center;
237
+ justify-content: center;
238
+ color: var(--djm-text);
239
+ font-weight: 600;
240
+ font-variant-numeric: tabular-nums;
241
+ }
242
+
197
243
  /* 骨架屏组件:头像 + 正文的行结构 */
198
244
  .djm-skeleton-block {
199
245
  display: flex;