@xilonglab/vue-main 1.6.26 → 1.6.28

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xilonglab/vue-main",
3
- "version": "1.6.26",
3
+ "version": "1.6.28",
4
4
  "description": "xilong vue main",
5
5
  "main": "packages/index.js",
6
6
  "scripts": {
@@ -8,12 +8,16 @@ const emits = defineEmits(['change', 'update:modelValue'])
8
8
 
9
9
  const props = defineProps({
10
10
  modelValue: {
11
- default: "",
11
+ default: null,
12
12
  },
13
13
  api: {
14
14
  type: Function,
15
15
  default: () => ({})
16
16
  },
17
+ callback: {
18
+ type: Function,
19
+ default: () => ({})
20
+ },
17
21
  width: {
18
22
  default: 635
19
23
  },
@@ -41,19 +45,23 @@ const props = defineProps({
41
45
  },
42
46
  })
43
47
 
44
-
45
48
  const value = computed({
46
49
  get() {
47
- return props.modelValue && typeof props.modelValue === 'object' && 'uri' in props.modelValue
48
- ? props.modelValue.uri
49
- : props.modelValue;
50
+ return props.modelValue
50
51
  },
51
52
  set(data) {
52
53
  emits('change', data)
53
54
  emits('update:modelValue', data)
54
55
  },
55
- });
56
+ })
56
57
 
58
+ const previewSrcList = computed(() => {
59
+ const v = props.modelValue
60
+ if (v && v.uri) {
61
+ return [`/storage/${v.uri}`]
62
+ }
63
+ return []
64
+ })
57
65
 
58
66
  const loading = ref(false)
59
67
 
@@ -63,8 +71,9 @@ function beforeUpload() {
63
71
  }
64
72
 
65
73
  function onSuccess(data, file, filelist) {
66
- loading.value = false;
74
+ loading.value = false
67
75
  emits('update:modelValue', data)
76
+ props.callback(data)
68
77
  }
69
78
 
70
79
  async function upload(option) {
@@ -91,8 +100,10 @@ async function upload(option) {
91
100
  <el-upload class="xl-image-input" action="" v-loading="loading" :headers="headers" :http-request="upload"
92
101
  :before-upload="beforeUpload" :on-success="onSuccess" :show-file-list="false" :disabled="disabled"
93
102
  :accept="props.accept">
94
- <img v-if="value" class="image" :src="`/storage/${value}`"
95
- :style="`max-width: ${width}px;max-height:${height}px`" />
103
+ <div v-if="value?.uri" class="image-preview-wrap" @click.stop>
104
+ <el-image class="image" :src="`/storage/${value.uri}`" :preview-src-list="previewSrcList" fit="contain"
105
+ :style="`width: ${width}px;height:${height}px`" :preview-teleported="true" />
106
+ </div>
96
107
  <el-icon v-else class="icon" :style="`width: ${width}px;height:${height}px`">
97
108
  <Plus />
98
109
  </el-icon>
@@ -116,10 +127,20 @@ async function upload(option) {
116
127
  }
117
128
  }
118
129
 
130
+ .image-preview-wrap {
131
+ display: block;
132
+ line-height: 0;
133
+ }
134
+
119
135
  .image {
120
136
  display: block;
121
137
  }
122
138
 
139
+ .image :deep(.el-image__inner) {
140
+ max-width: 100%;
141
+ max-height: 100%;
142
+ }
143
+
123
144
  .el-icon.icon {
124
145
  font-size: 28px;
125
146
  color: #8c939d;
@@ -0,0 +1,206 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlImagesInput" })
3
+
4
+ import { Close } from '@element-plus/icons-vue'
5
+ import { ref } from 'vue'
6
+
7
+ const props = defineProps({
8
+ modelValue: {
9
+ type: Array,
10
+ required: true
11
+ },
12
+ api: {
13
+ type: Function,
14
+ default: () => ({})
15
+ },
16
+ callback: {
17
+ type: Function,
18
+ default: () => ({})
19
+ }
20
+ })
21
+
22
+ const emits = defineEmits(['update:modelValue'])
23
+
24
+ const tempImage = ref(null)
25
+
26
+ const handlers = {
27
+ removeImage: (index) => {
28
+ emits('update:modelValue', props.modelValue.filter((_, i) => i !== index))
29
+ },
30
+ handleImageUpload: (image) => {
31
+ emits('update:modelValue', [...props.modelValue, image])
32
+ tempImage.value = null
33
+ }
34
+ }
35
+ </script>
36
+
37
+
38
+ <template>
39
+ <div class="xl-images-input">
40
+ <div
41
+ v-for="(image, index) in modelValue"
42
+ :key="index"
43
+ class="image-card"
44
+ >
45
+ <div class="image-wrapper">
46
+ <el-image
47
+ class="thumb-image"
48
+ :src="`/storage/${image.uri}`"
49
+ :preview-src-list="modelValue.map((i) => `/storage/${i.uri}`)"
50
+ :initial-index="index"
51
+ fit="contain"
52
+ :preview-teleported="true"
53
+ />
54
+ <span class="delete-btn" @click.stop="handlers.removeImage(index)" title="删除">
55
+ <el-icon class="delete-btn__icon" :size="16"><Close /></el-icon>
56
+ </span>
57
+ </div>
58
+ </div>
59
+ <div class="image-card upload-card">
60
+ <xl-image-input
61
+ v-model="tempImage"
62
+ :api="api"
63
+ :callback="handlers.handleImageUpload"
64
+ />
65
+ </div>
66
+ </div>
67
+ </template>
68
+
69
+
70
+ <style lang="less">
71
+ .xl-images-input {
72
+ --xl-image-card-size: 200px;
73
+ display: grid;
74
+ grid-template-columns: repeat(auto-fill, minmax(var(--xl-image-card-size), 1fr));
75
+ gap: 20px;
76
+ align-items: start;
77
+
78
+ @media (max-width: 768px) {
79
+ --xl-image-card-size: 180px;
80
+ grid-template-columns: repeat(auto-fill, minmax(var(--xl-image-card-size), 1fr));
81
+ gap: 16px;
82
+ }
83
+
84
+ .delete-btn {
85
+ position: absolute;
86
+ top: 8px;
87
+ right: 8px;
88
+ width: 32px;
89
+ height: 32px;
90
+ background: linear-gradient(135deg, #f56c6c 0%, #f78989 100%);
91
+ color: white;
92
+ border-radius: 50%;
93
+ display: inline-flex;
94
+ align-items: center;
95
+ justify-content: center;
96
+ padding: 0;
97
+ cursor: pointer;
98
+ box-shadow: 0 3px 10px rgba(245, 108, 108, 0.4);
99
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
100
+ z-index: 10;
101
+ border: 2px solid #ffffff;
102
+ box-sizing: border-box;
103
+
104
+ .delete-btn__icon {
105
+ margin: 0;
106
+ flex-shrink: 0;
107
+ }
108
+
109
+ &:hover {
110
+ background: linear-gradient(135deg, #f78989 0%, #fa9a9a 100%);
111
+ transform: scale(1.15) rotate(90deg);
112
+ box-shadow: 0 4px 16px rgba(245, 108, 108, 0.6);
113
+ }
114
+
115
+ &:active {
116
+ transform: scale(0.9) rotate(90deg);
117
+ }
118
+ }
119
+
120
+ .image-card {
121
+ position: relative;
122
+ width: var(--xl-image-card-size);
123
+ height: var(--xl-image-card-size);
124
+ box-sizing: border-box;
125
+ justify-self: start;
126
+ border-radius: 10px;
127
+ overflow: hidden;
128
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
129
+ background-color: #ffffff;
130
+ border: 1px solid #e4e7ed;
131
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
132
+
133
+ &:hover {
134
+ transform: translateY(-6px);
135
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
136
+ border-color: #b3d8ff;
137
+ }
138
+
139
+ &.upload-card {
140
+ border: 2px dashed #c0c4cc;
141
+ background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
142
+ display: flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+ transition: all 0.3s ease;
146
+
147
+ &:hover {
148
+ border-color: #409eff;
149
+ background: linear-gradient(135deg, #f0f9ff 0%, #e1f3ff 100%);
150
+ transform: translateY(-4px);
151
+ box-shadow: 0 6px 20px rgba(64, 158, 255, 0.2);
152
+ }
153
+
154
+ :deep(.xl-image-input) {
155
+ display: block;
156
+ width: 100%;
157
+ height: 100%;
158
+ }
159
+
160
+ :deep(.xl-image-input .el-upload) {
161
+ width: 100%;
162
+ height: 100%;
163
+ min-height: 0;
164
+ border: none;
165
+ box-sizing: border-box;
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ }
170
+
171
+ :deep(.xl-image-input .el-icon.icon) {
172
+ width: 100% !important;
173
+ height: 100% !important;
174
+ max-width: 100%;
175
+ max-height: 100%;
176
+ box-sizing: border-box;
177
+ }
178
+ }
179
+ }
180
+
181
+ .image-wrapper {
182
+ position: relative;
183
+ width: 100%;
184
+ height: 100%;
185
+ min-height: 0;
186
+ padding: 0;
187
+ box-sizing: border-box;
188
+ background: #fafbfc;
189
+ }
190
+
191
+ .image-wrapper .thumb-image {
192
+ display: block;
193
+ width: 100%;
194
+ height: 100%;
195
+ }
196
+
197
+ .image-wrapper .thumb-image :deep(.el-image__inner) {
198
+ transition: transform 0.3s ease;
199
+ }
200
+
201
+ .image-wrapper:hover .thumb-image :deep(.el-image__inner) {
202
+ transform: scale(1.02);
203
+ }
204
+ }
205
+ </style>
206
+
@@ -1,4 +1,4 @@
1
- <script setup>
1
+ X<script setup>
2
2
  defineOptions({ name: "XlDialogColumns" })
3
3
 
4
4
  const props = defineProps({
@@ -21,7 +21,12 @@ const props = defineProps({
21
21
  :l="col.label"
22
22
  :p="col.prop"
23
23
  >
24
+ <slot
25
+ v-if="col.type === 'slot'"
26
+ :name="`${col.prop}-form`"
27
+ />
24
28
  <component
29
+ v-else
25
30
  :is="`xl-${col.form.type || 'input'}`"
26
31
  v-model="obj[col.prop]"
27
32
  v-bind="col.form || {}"