@xilonglab/vue-main 1.1.20 → 1.2.1

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.1.20",
3
+ "version": "1.2.1",
4
4
  "description": "xilong vue main",
5
5
  "main": "packages/index.js",
6
6
  "scripts": {
@@ -9,9 +9,9 @@
9
9
  "author": "xilonglab",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
+ "@imengyu/vue3-context-menu": "^1.3.3",
12
13
  "element-plus": "2.3.6",
13
14
  "image-conversion": "^2.1.1",
14
- "@imengyu/vue3-context-menu": "^1.3.3",
15
15
  "vue-router": "^4.2.2"
16
16
  }
17
17
  }
@@ -102,16 +102,7 @@ const { refs, api, params, obj, chartOptions, total } = inject('injections')
102
102
  <div :class="['xl-data-view', english]">
103
103
  <xl-tool-bar :type="type" :table="refs.table" :params="params" @query="() => api.stat()">
104
104
  <template #inputs>
105
- <template v-for="col in columns" :key="col.prop">
106
- <template v-if="col.search">
107
- <component
108
- :is="`xl-${col.search.type || 'input'}`"
109
- :placeholder="col.label"
110
- v-model="params[col.prop]"
111
- v-bind="col.search || {}"
112
- />
113
- </template>
114
- </template>
105
+ <xl-search-inputs :columns="columns" :params="params"/>
115
106
  <slot name="inputs" />
116
107
  </template>
117
108
  <template #buttons>
@@ -121,51 +112,7 @@ const { refs, api, params, obj, chartOptions, total } = inject('injections')
121
112
  </xl-tool-bar>
122
113
  <xl-query-page-table v-show="params.view != 'chart'" :ref="refs.table" :api="api" :params="params"
123
114
  v-bind="$props" :summary-method="summaryMethod?summaryMethod:()=>({0:total})" :sort-change="(data) => api.sort(data)">
124
- <template v-for="col in columns" :key="col.prop">
125
- <template v-if="!col.hidden">
126
- <xl-datetime-col
127
- v-if="col.type === 'datetime'"
128
- :l="col.label"
129
- :p="col.prop"
130
- />
131
- <xl-map-col
132
- v-else-if="col.type === 'map'"
133
- :l="col.label"
134
- :p="col.prop"
135
- :width="col.width"
136
- :map="col.map"
137
- />
138
- <xl-status-col
139
- v-else-if="col.type === 'status'"
140
- :l="col.label"
141
- :p="col.prop"
142
- :map="col.map"
143
- />
144
- <xl-review-col
145
- v-else-if="col.type === 'review'"
146
- :l="col.label"
147
- :p="col.prop"
148
- />
149
- <xl-clamp-col
150
- v-else-if="col.type === 'clamp'"
151
- :l="col.label"
152
- :p="col.prop"
153
- :width="col.width"
154
- />
155
- <xl-bool-col
156
- v-else-if="col.type === 'bool'"
157
- :l="col.label"
158
- :p="col.prop"
159
- :width="col.width"
160
- />
161
- <xl-col
162
- v-else
163
- :l="col.label"
164
- :p="col.prop"
165
- :width="col.width"
166
- />
167
- </template>
168
- </template>
115
+ <xl-table-columns :columns="columns"/>
169
116
  <slot name="columns" />
170
117
  </xl-query-page-table>
171
118
  <xl-chart v-show="params.view == 'chart'" :options="chartOptions" />
@@ -0,0 +1,29 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlSearchInputs" })
3
+
4
+ const props = defineProps({
5
+ columns: {
6
+ type: Array,
7
+ default: () => [],
8
+ },
9
+ params: {
10
+ type: Object,
11
+ default: () => ({}),
12
+ },
13
+ });
14
+
15
+ defineSlots(['default'])
16
+ </script>
17
+
18
+ <template>
19
+ <template v-for="col in columns" :key="col.prop">
20
+ <template v-if="col.search">
21
+ <component
22
+ :is="`xl-${col.search.type || 'input'}`"
23
+ :placeholder="col.label"
24
+ v-model="params[col.prop]"
25
+ v-bind="col.search || {}"
26
+ />
27
+ </template>
28
+ </template>
29
+ </template>
@@ -0,0 +1,60 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlTableColumns" })
3
+
4
+ const props = defineProps({
5
+ columns: {
6
+ type: Array,
7
+ default: () => [],
8
+ },
9
+ });
10
+
11
+ defineSlots(['default'])
12
+ </script>
13
+
14
+ <template>
15
+ <template v-for="col in columns" :key="col.prop">
16
+ <template v-if="!col.hidden">
17
+ <xl-datetime-col
18
+ v-if="col.type === 'datetime'"
19
+ :l="col.label"
20
+ :p="col.prop"
21
+ />
22
+ <xl-map-col
23
+ v-else-if="col.type === 'map'"
24
+ :l="col.label"
25
+ :p="col.prop"
26
+ :width="col.width"
27
+ :map="col.map"
28
+ />
29
+ <xl-status-col
30
+ v-else-if="col.type === 'status'"
31
+ :l="col.label"
32
+ :p="col.prop"
33
+ :map="col.map"
34
+ />
35
+ <xl-review-col
36
+ v-else-if="col.type === 'review'"
37
+ :l="col.label"
38
+ :p="col.prop"
39
+ />
40
+ <xl-clamp-col
41
+ v-else-if="col.type === 'clamp'"
42
+ :l="col.label"
43
+ :p="col.prop"
44
+ :width="col.width"
45
+ />
46
+ <xl-bool-col
47
+ v-else-if="col.type === 'bool'"
48
+ :l="col.label"
49
+ :p="col.prop"
50
+ :width="col.width"
51
+ />
52
+ <xl-col
53
+ v-else
54
+ :l="col.label"
55
+ :p="col.prop"
56
+ :width="col.width"
57
+ />
58
+ </template>
59
+ </template>
60
+ </template>
@@ -1,355 +0,0 @@
1
- <script setup>
2
- defineOptions({ name: "XlSignatureInput" })
3
-
4
- import { ref, computed } from 'vue'
5
- import {
6
- Edit,
7
- Check,
8
- RefreshLeft,
9
- Close,
10
- Document,
11
- InfoFilled
12
- } from '@element-plus/icons-vue'
13
-
14
- const emits = defineEmits(['change', 'update:modelValue'])
15
-
16
- const props = defineProps({
17
- modelValue: {
18
- default: "",
19
- },
20
- api: {
21
- type: Function,
22
- default: () => { },
23
- },
24
- params: {
25
- type: Object,
26
- default: () => ({})
27
- },
28
- disabled: {
29
- default: false,
30
- },
31
- width: {
32
- default: 400
33
- },
34
- height: {
35
- default: 200
36
- }
37
- })
38
-
39
- const refs = {
40
- pad: ref(null)
41
- }
42
- const editing = ref(false)
43
- const loading = ref(false)
44
- const saving = ref(false)
45
-
46
- const url = computed({
47
- get() {
48
- return `/storage/${props.modelValue.uri}`;
49
- },
50
- set(data) {
51
- emits('change', data)
52
- emits('update:modelValue', data)
53
- },
54
- });
55
-
56
- const handlers = {
57
- async save() {
58
- const { api, params } = props
59
- const base64 = refs.pad.value.save('image/png')
60
- saving.value = true
61
- try {
62
- const data = await api({ ...params, base64 })
63
- emits('update:modelValue', data)
64
- editing.value = false
65
- } catch (error) {
66
- console.error('保存签名失败:', error)
67
- } finally {
68
- saving.value = false
69
- }
70
- },
71
- clear() {
72
- refs.pad.value.clear()
73
- },
74
- edit() {
75
- editing.value = true
76
- }
77
- }
78
-
79
- const handleImageError = () => {
80
- console.warn('签名图片加载失败')
81
- }
82
-
83
- </script>
84
-
85
- <template>
86
- <div class="xl-signature-input" :class="{ 'disabled': disabled }">
87
- <div class="signature-wrapper" :style="{ width: width + 'px', height: height + 'px' }">
88
- <!-- 编辑模式 -->
89
- <div v-if="editing" class="signature-pad">
90
- <Vue3Signature
91
- class="pad"
92
- :ref="refs.pad"
93
- :width="width"
94
- :height="height"
95
- />
96
- <div class="pad-overlay">
97
- <div class="hint-text">请在下方区域进行签名</div>
98
- </div>
99
- </div>
100
-
101
- <!-- 预览模式 -->
102
- <div v-else class="signature-preview">
103
- <div v-if="modelValue && modelValue.uri" class="image-container">
104
- <img
105
- v-loading="loading"
106
- :src="url"
107
- :alt="'签名图片'"
108
- @error="handleImageError"
109
- />
110
- <div class="image-overlay">
111
- <div class="preview-actions">
112
- <el-button
113
- type="primary"
114
- size="small"
115
- :icon="Edit"
116
- @click="handlers.edit"
117
- >
118
- 重新签名
119
- </el-button>
120
- </div>
121
- </div>
122
- </div>
123
- <div v-else class="empty-state">
124
- <div class="empty-icon">
125
- <el-icon size="48"><Document /></el-icon>
126
- </div>
127
- <div class="empty-text">暂无签名</div>
128
- <el-button
129
- type="primary"
130
- :icon="Edit"
131
- @click="handlers.edit"
132
- :disabled="disabled"
133
- >
134
- 开始签名
135
- </el-button>
136
- </div>
137
- </div>
138
- </div>
139
-
140
- <!-- 操作按钮 -->
141
- <div v-if="editing" class="signature-controls">
142
- <div class="control-buttons">
143
- <el-button
144
- type="success"
145
- :loading="saving"
146
- :icon="Check"
147
- @click="handlers.save"
148
- >
149
- 保存签名
150
- </el-button>
151
- <el-button
152
- type="warning"
153
- :icon="RefreshLeft"
154
- @click="handlers.clear"
155
- >
156
- 清空重写
157
- </el-button>
158
- <el-button
159
- :icon="Close"
160
- @click="editing = false"
161
- >
162
- 取消
163
- </el-button>
164
- </div>
165
- <div class="signature-tips">
166
- <el-icon><InfoFilled /></el-icon>
167
- <span>请使用鼠标或触控笔进行签名</span>
168
- </div>
169
- </div>
170
- </div>
171
- </template>
172
-
173
- <style lang="less">
174
- .xl-signature-input {
175
- display: flex;
176
- flex-direction: column;
177
- align-items: center;
178
- gap: 12px;
179
-
180
- &.disabled {
181
- opacity: 0.6;
182
- pointer-events: none;
183
- }
184
-
185
- .signature-wrapper {
186
- position: relative;
187
- border: 2px dashed #d9d9d9;
188
- border-radius: 8px;
189
- background: #fafafa;
190
- transition: all 0.3s ease;
191
- overflow: hidden;
192
- margin: 0 auto;
193
-
194
- &:hover {
195
- border-color: #409eff;
196
- background: #f0f9ff;
197
- }
198
-
199
- .signature-pad {
200
- position: relative;
201
- width: 100%;
202
- height: 100%;
203
-
204
- .pad {
205
- width: 100%;
206
- height: 100%;
207
- background: white;
208
- border-radius: 6px;
209
- }
210
-
211
- .pad-overlay {
212
- position: absolute;
213
- top: 0;
214
- left: 0;
215
- right: 0;
216
- bottom: 0;
217
- pointer-events: none;
218
- display: flex;
219
- align-items: center;
220
- justify-content: center;
221
- z-index: 1;
222
-
223
- .hint-text {
224
- background: rgba(0, 0, 0, 0.7);
225
- color: white;
226
- padding: 8px 16px;
227
- border-radius: 4px;
228
- font-size: 14px;
229
- opacity: 0;
230
- animation: fadeInOut 2s infinite;
231
- }
232
- }
233
- }
234
-
235
- .signature-preview {
236
- width: 100%;
237
- height: 100%;
238
- position: relative;
239
-
240
- .image-container {
241
- position: relative;
242
- width: 100%;
243
- height: 100%;
244
- display: flex;
245
- align-items: center;
246
- justify-content: center;
247
-
248
- img {
249
- max-width: 100%;
250
- max-height: 100%;
251
- object-fit: contain;
252
- border-radius: 6px;
253
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
254
- }
255
-
256
- .image-overlay {
257
- position: absolute;
258
- top: 0;
259
- left: 0;
260
- right: 0;
261
- bottom: 0;
262
- background: rgba(0, 0, 0, 0.5);
263
- display: flex;
264
- align-items: center;
265
- justify-content: center;
266
- opacity: 0;
267
- transition: opacity 0.3s ease;
268
-
269
- &:hover {
270
- opacity: 1;
271
- }
272
-
273
- .preview-actions {
274
- .el-button {
275
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
276
- }
277
- }
278
- }
279
-
280
- &:hover .image-overlay {
281
- opacity: 1;
282
- }
283
- }
284
-
285
- .empty-state {
286
- display: flex;
287
- flex-direction: column;
288
- align-items: center;
289
- justify-content: center;
290
- height: 100%;
291
- padding: 20px;
292
- text-align: center;
293
-
294
- .empty-icon {
295
- color: #c0c4cc;
296
- margin-bottom: 12px;
297
- }
298
-
299
- .empty-text {
300
- color: #909399;
301
- font-size: 14px;
302
- margin-bottom: 16px;
303
- }
304
- }
305
- }
306
- }
307
-
308
- .signature-controls {
309
- display: flex;
310
- flex-direction: column;
311
- align-items: center;
312
- gap: 8px;
313
- width: 100%;
314
-
315
- .control-buttons {
316
- display: flex;
317
- gap: 8px;
318
- justify-content: center;
319
- flex-wrap: wrap;
320
- }
321
-
322
- .signature-tips {
323
- display: flex;
324
- align-items: center;
325
- justify-content: center;
326
- gap: 4px;
327
- color: #909399;
328
- font-size: 12px;
329
- padding: 4px 8px;
330
- background: #f5f7fa;
331
- border-radius: 4px;
332
- }
333
- }
334
- }
335
-
336
- @keyframes fadeInOut {
337
- 0%, 100% { opacity: 0; }
338
- 50% { opacity: 1; }
339
- }
340
-
341
- // 响应式设计
342
- @media (max-width: 768px) {
343
- .xl-signature-input {
344
- .signature-controls {
345
- .control-buttons {
346
- flex-direction: column;
347
-
348
- .el-button {
349
- width: 100%;
350
- }
351
- }
352
- }
353
- }
354
- }
355
- </style>