centaline-data-driven-v3 0.1.58 → 0.1.60
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/dist/centaline-data-driven-v3.umd.js +118 -118
- package/package.json +1 -1
- package/src/components/app/FormList.vue +194 -9
- package/src/components/web/File.vue +21 -2
- package/src/components/web/Form.vue +236 -8
- package/src/components/web/SearchList/SearchTable.vue +21 -5
- package/src/components/web/SearchList/TableToolbar.vue +9 -5
- package/src/components/web/SearchList.vue +1 -1
- package/src/components/web/ViewerFile/ViewerImage.vue +1 -1
- package/src/components/web/ViewerFile.vue +63 -21
- package/src/components/web/dialog.vue +18 -7
- package/src/loader/src/File.js +38 -22
- package/src/loader/src/Form.js +15 -5
- package/src/loader/src/SearchTable.js +58 -17
- package/src/main.js +2 -2
- package/src/utils/useDraggable.js +100 -0
- package/src/views/Form.vue +2 -2
- package/src/views/SearchList.vue +3 -9
package/package.json
CHANGED
|
@@ -52,18 +52,28 @@
|
|
|
52
52
|
<span>操作</span>
|
|
53
53
|
</th>
|
|
54
54
|
<template v-for="(column, i) in model.rows[0].field" :key="i">
|
|
55
|
-
<th v-if="column.show" class="ct-th" :
|
|
56
|
-
:colspan="column.colspan">
|
|
55
|
+
<th v-if="column.show" class="ct-th" :class="column.sortAction"
|
|
56
|
+
:rowspan="column.rowspan" :colspan="column.colspan">
|
|
57
57
|
<span>{{ column.controlLabel }}</span>
|
|
58
|
+
<span class="caret-wrapper" v-if="column.autoSearch"
|
|
59
|
+
@click="toSort($event, column)"
|
|
60
|
+
@contextmenu.prevent="clearSort($event, column)">
|
|
61
|
+
<i class="sort-caret ascending"
|
|
62
|
+
@click.left="toSort($event, column, 'asc')"
|
|
63
|
+
@contextmenu.prevent="clearSort($event, column)"></i>
|
|
64
|
+
<i class="sort-caret descending"
|
|
65
|
+
@click.left="toSort($event, column, 'desc')"
|
|
66
|
+
@contextmenu.prevent="clearSort($event, column)"></i>
|
|
67
|
+
</span>
|
|
58
68
|
</th>
|
|
59
69
|
</template>
|
|
60
70
|
</tr>
|
|
61
71
|
</thead>
|
|
62
72
|
<!--表体-->
|
|
63
73
|
<tbody>
|
|
64
|
-
<template v-if="
|
|
65
|
-
<tr v-for="(row, rowindex) in
|
|
66
|
-
|
|
74
|
+
<template v-if="renderList.length > 0">
|
|
75
|
+
<tr v-for="(row, rowindex) in renderList" :key="rowindex" :ref="'rows.' + rowindex"
|
|
76
|
+
class="ct-tr">
|
|
67
77
|
<template
|
|
68
78
|
v-if="model.rows[0].edit || model.rows[0].delete || (model.buttons.length > 0 && model.buttonsShow.length > 0)">
|
|
69
79
|
<td class="ct-td td-edit" align="center" valign="middle">
|
|
@@ -74,7 +84,7 @@
|
|
|
74
84
|
|
|
75
85
|
<van-image v-if="row.delete && !row.isSet"
|
|
76
86
|
style="cursor: pointer;margin-right: 5px;" width="20" height="20"
|
|
77
|
-
@click="deleteRow(
|
|
87
|
+
@click="deleteRow(row.$sourceIndex)"
|
|
78
88
|
:src="util.getAssetsImage('btn_del.png')" />
|
|
79
89
|
</td>
|
|
80
90
|
<template v-for="(b, vi) in model.buttons" :key="vi">
|
|
@@ -157,6 +167,8 @@ const Fields = ref()
|
|
|
157
167
|
const colspansum = ref(0)
|
|
158
168
|
const sumsList = ref([])
|
|
159
169
|
const itemKey = ref(0)
|
|
170
|
+
const renderList = ref([])
|
|
171
|
+
const sortInfo = ref(null)
|
|
160
172
|
const dragOptions = {
|
|
161
173
|
animation: 200,
|
|
162
174
|
group: model.value.fieldName1,
|
|
@@ -193,6 +205,26 @@ function Init() {
|
|
|
193
205
|
colspansum.value++;
|
|
194
206
|
}
|
|
195
207
|
}
|
|
208
|
+
refreshRenderList()
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
function refreshRenderList() {
|
|
212
|
+
// 拷贝一份全新数组,防止sort原地修改原始数据
|
|
213
|
+
const copyArr = [...model.value.tableData]
|
|
214
|
+
if (sortInfo.value) {
|
|
215
|
+
const { prop, order } = sortInfo.value
|
|
216
|
+
copyArr.sort((a, b) => {
|
|
217
|
+
const aValue = getLableShow(a[prop])
|
|
218
|
+
const bValue = getLableShow(b[prop])
|
|
219
|
+
if (typeof a === 'number') {
|
|
220
|
+
return order === 'asc' ? aValue - bValue : bValue - aValue
|
|
221
|
+
} else {
|
|
222
|
+
const res = aValue.localeCompare(bValue, 'zh-CN')
|
|
223
|
+
return order === 'asc' ? res : -res
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
renderList.value = copyArr
|
|
196
228
|
}
|
|
197
229
|
function popupSearchListHandle(field) {
|
|
198
230
|
if (field.isSearchPageWithList) {
|
|
@@ -212,18 +244,24 @@ function addRow() {
|
|
|
212
244
|
return
|
|
213
245
|
}
|
|
214
246
|
FormList.addRow(model.value);
|
|
247
|
+
refreshRenderList()
|
|
215
248
|
}
|
|
216
249
|
//修改
|
|
217
250
|
function editRow(index) {
|
|
218
251
|
FormList.editRow(index, model.value);
|
|
252
|
+
refreshRenderList()
|
|
219
253
|
}
|
|
220
254
|
//删除
|
|
221
|
-
function deleteRow(
|
|
255
|
+
function deleteRow(sourceIndex) {
|
|
222
256
|
FormList.deleteRow(sourceIndex, model.value, () => {
|
|
223
|
-
model.value.tableData.
|
|
257
|
+
const targetIndex = model.value.tableData.findIndex(v => v.$sourceIndex === sourceIndex)
|
|
258
|
+
if (targetIndex > -1) {
|
|
259
|
+
model.value.tableData.splice(targetIndex, 1)
|
|
260
|
+
}
|
|
224
261
|
model.value.onChanged = model.value.formListChange;
|
|
225
262
|
model.value.createText = '';
|
|
226
263
|
model.value.disabled = false;
|
|
264
|
+
refreshRenderList()
|
|
227
265
|
emit('change', model.value);
|
|
228
266
|
});
|
|
229
267
|
}
|
|
@@ -350,13 +388,18 @@ function getSummaries() {
|
|
|
350
388
|
function rolRouterCellClickHandler(routerKey, rowindex, sourceIndex) {
|
|
351
389
|
if (routerKey == 'edit') {
|
|
352
390
|
FormList.editRow(sourceIndex, model.value);
|
|
391
|
+
refreshRenderList()
|
|
353
392
|
}
|
|
354
393
|
else if (routerKey == 'delete') {
|
|
355
394
|
FormList.deleteRow(sourceIndex, model.value, () => {
|
|
356
|
-
model.value.tableData.
|
|
395
|
+
const targetIndex = model.value.tableData.findIndex(v => v.$sourceIndex === sourceIndex)
|
|
396
|
+
if (targetIndex > -1) {
|
|
397
|
+
model.value.tableData.splice(targetIndex, 1)
|
|
398
|
+
}
|
|
357
399
|
model.value.onChanged = model.value.formListChange;
|
|
358
400
|
model.value.createText = '';
|
|
359
401
|
model.value.disabled = false;
|
|
402
|
+
refreshRenderList()
|
|
360
403
|
emit('change', model.value);
|
|
361
404
|
});
|
|
362
405
|
} else {
|
|
@@ -412,6 +455,107 @@ function delRow(row) {
|
|
|
412
455
|
function deleteAll() {
|
|
413
456
|
FormList.deleteAll(model.value);
|
|
414
457
|
}
|
|
458
|
+
function toSort(ev, col, action) {
|
|
459
|
+
model.value.rows[0].field.forEach((v1) => {
|
|
460
|
+
v1.sortAction = "";
|
|
461
|
+
});
|
|
462
|
+
if (sortInfo.value && sortInfo.value.prop == col.fieldName1 && sortInfo.value.order == action) {
|
|
463
|
+
sortInfo.value = null
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
sortInfo.value = {
|
|
467
|
+
prop: col.fieldName1,
|
|
468
|
+
order: action
|
|
469
|
+
}
|
|
470
|
+
col.sortAction = action;
|
|
471
|
+
}
|
|
472
|
+
refreshRenderList()
|
|
473
|
+
ev.cancelBubble = true;
|
|
474
|
+
ev.stopPropagation();
|
|
475
|
+
}
|
|
476
|
+
function getLableShow(data) {
|
|
477
|
+
let labelShow = data.name1;
|
|
478
|
+
if (!labelShow) {
|
|
479
|
+
labelShow = data.code1;
|
|
480
|
+
}
|
|
481
|
+
if (labelShow && data.unitName1) {
|
|
482
|
+
labelShow = labelShow + data.unitName1;
|
|
483
|
+
}
|
|
484
|
+
switch (data.controlType) {
|
|
485
|
+
case Enum.ControlType.Label:
|
|
486
|
+
if (data.value) {
|
|
487
|
+
labelShow = data.value;
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
case Enum.ControlType.MultiSelectNoSearch:
|
|
491
|
+
case Enum.ControlType.MultiSelectWithSearch:
|
|
492
|
+
labelShow = '';
|
|
493
|
+
if (data.code1) {
|
|
494
|
+
JSON.parse(data.code1).forEach((op) => {
|
|
495
|
+
if (op.flagDeleted !== 1) {
|
|
496
|
+
if (op.flagDeleted != undefined && op.flagDeleted == true) {
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
labelShow += op['name'] + ' ';
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
break;
|
|
505
|
+
case Enum.ControlType.PhoneNumberText:
|
|
506
|
+
case Enum.ControlType.EmailText:
|
|
507
|
+
if (data.code2) {
|
|
508
|
+
labelShow = data.name1 + data.code2;
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
case Enum.ControlType.NumericRange:
|
|
512
|
+
if (data.code1 && data.code2) {
|
|
513
|
+
}
|
|
514
|
+
else if (data.code1) {
|
|
515
|
+
labelShow = data.code1 + (data.unitName1 ? data.unitName1 : '') + '以上';
|
|
516
|
+
}
|
|
517
|
+
else if (data.code2) {
|
|
518
|
+
labelShow = data.code2 + (data.unitName1 ? data.unitName1 : '') + '以下';
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
521
|
+
case Enum.ControlType.DateTimeRange:
|
|
522
|
+
case Enum.ControlType.DateRange:
|
|
523
|
+
if (data.code1 && data.code2) {
|
|
524
|
+
}
|
|
525
|
+
else if (data.code1) {
|
|
526
|
+
labelShow = data.code1 + (data.unitName1 ? data.unitName1 : '') + '以后';
|
|
527
|
+
}
|
|
528
|
+
else if (data.code2) {
|
|
529
|
+
labelShow = data.code2 + (data.unitName1 ? data.unitName1 : '') + '以前';
|
|
530
|
+
}
|
|
531
|
+
break;
|
|
532
|
+
case Enum.ControlType.Time:
|
|
533
|
+
case Enum.ControlType.TimeRange:
|
|
534
|
+
if (data.flagrange) {
|
|
535
|
+
if (data.code1 && data.code2) {
|
|
536
|
+
labelShow = data.code1 + '-' + data.code2;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
if (data.code1) {
|
|
541
|
+
labelShow = data.code1
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
break;
|
|
545
|
+
case Enum.ControlType.CheckBoxList:
|
|
546
|
+
labelShow = data.getCheckedName();;
|
|
547
|
+
break;
|
|
548
|
+
case Enum.ControlType.Switch:
|
|
549
|
+
labelShow = data.value ? '开启' : '关闭';
|
|
550
|
+
break;
|
|
551
|
+
case Enum.ControlType.CheckBox:
|
|
552
|
+
labelShow = data.value ? '是' : '否';
|
|
553
|
+
break;
|
|
554
|
+
default:
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
return labelShow;
|
|
558
|
+
}
|
|
415
559
|
defineExpose({
|
|
416
560
|
model
|
|
417
561
|
})
|
|
@@ -494,4 +638,45 @@ th.th-edit {
|
|
|
494
638
|
z-index: 1;
|
|
495
639
|
background-color: #ffffff;
|
|
496
640
|
}
|
|
641
|
+
|
|
642
|
+
.ct-th>.caret-wrapper {
|
|
643
|
+
display: inline-flex;
|
|
644
|
+
flex-direction: column;
|
|
645
|
+
align-items: center;
|
|
646
|
+
height: 34px;
|
|
647
|
+
width: 10px;
|
|
648
|
+
vertical-align: middle;
|
|
649
|
+
cursor: pointer;
|
|
650
|
+
overflow: initial;
|
|
651
|
+
position: relative;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.ct-th>.caret-wrapper>.sort-caret {
|
|
655
|
+
width: 0;
|
|
656
|
+
height: 0;
|
|
657
|
+
border: 5px solid transparent;
|
|
658
|
+
position: absolute;
|
|
659
|
+
left: 7px;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.ct-th>.caret-wrapper>.sort-caret.ascending {
|
|
663
|
+
border-bottom-color: var(--centalinePlaceholder);
|
|
664
|
+
top: 5px;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.ct-th>.caret-wrapper>.sort-caret.descending {
|
|
668
|
+
border-top-color: var(--centalinePlaceholder);
|
|
669
|
+
bottom: 7px;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
.ct-th.asc>.caret-wrapper>.sort-caret.ascending {
|
|
674
|
+
border-bottom-color: #409eff;
|
|
675
|
+
top: 5px;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.ct-th.desc>.caret-wrapper>.sort-caret.descending {
|
|
679
|
+
border-top-color: #409eff;
|
|
680
|
+
bottom: 7px;
|
|
681
|
+
}
|
|
497
682
|
</style>
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
</template>
|
|
167
167
|
</template>
|
|
168
168
|
<script setup lang="ts">
|
|
169
|
-
import { ref, nextTick, computed, onBeforeUnmount } from 'vue'
|
|
169
|
+
import { ref, nextTick, computed, onBeforeUnmount,inject ,watch } from 'vue'
|
|
170
170
|
import { ElMessage, UploadProps } from 'element-plus'
|
|
171
171
|
import common from '../../utils/common'
|
|
172
172
|
import { changeHandler } from '../../utils/mixins';
|
|
@@ -623,12 +623,31 @@ function addClass(el, className) {
|
|
|
623
623
|
newClassName.push(className);
|
|
624
624
|
el.className = newClassName.join(" ");
|
|
625
625
|
}
|
|
626
|
+
const injectedViewerFileToggle = inject('onViewerFileToggle')
|
|
626
627
|
|
|
627
628
|
|
|
628
629
|
//预览文件
|
|
629
630
|
function viewerfile(file) {
|
|
630
|
-
|
|
631
|
+
|
|
632
|
+
File.viewerfile(file, model.value, function (MediaAlbum, groupIndex, index) {
|
|
633
|
+
injectedViewerFileToggle(true, MediaAlbum, groupIndex, index);
|
|
634
|
+
})
|
|
631
635
|
}
|
|
636
|
+
const ChangeFileList = inject('ChangeFileList')
|
|
637
|
+
|
|
638
|
+
watch(
|
|
639
|
+
() => model.value?.fileList, // 直接监听 fileList 数组
|
|
640
|
+
(newFileList) => {
|
|
641
|
+
nextTick(() => {
|
|
642
|
+
if (model.value?.mediaViewPageType === 3) {
|
|
643
|
+
const { album } = File.buildMediaAlbum(model.value);
|
|
644
|
+
const MediaAlbum = [album];
|
|
645
|
+
ChangeFileList(MediaAlbum, 0, 0);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
},
|
|
649
|
+
{ deep: true } // 深度监听,以便捕获数组内元素属性变化(与原 JSON.stringify 效果一致)
|
|
650
|
+
);
|
|
632
651
|
|
|
633
652
|
function PasteUpload(event) {
|
|
634
653
|
if (!model.value.locked && !model.value.disableUpload) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="refForm" v-loading="loading"
|
|
3
3
|
:style="{ width: pageWidth ? pageWidth + 'px' : '100%', margin: 'auto', 'min-height': minHeight }">
|
|
4
|
-
<div style="display: flex; width: 100%;">
|
|
4
|
+
<div style="display: flex; width: 100%;" ref="leftContainerRef">
|
|
5
5
|
<div style="flex: 1; min-width: 0;">
|
|
6
6
|
<div v-if="model !== null && !loading" class="ct-form" :class="{ 'domDisabled': model.pageDisabled }"
|
|
7
7
|
:style="{ margin: openType != 'tree' ? '10px' : '0px' }">
|
|
@@ -194,9 +194,22 @@
|
|
|
194
194
|
@hideAI="AIToggle" :isVisible="showAI" :tablewidth="model.aiAttr.width">
|
|
195
195
|
|
|
196
196
|
</AIChat>
|
|
197
|
+
|
|
198
|
+
|
|
197
199
|
</div>
|
|
198
200
|
</div>
|
|
199
201
|
</template>
|
|
202
|
+
<div :style="{ flex: ' 0 0 ' + 650 + 'px', position: 'sticky', top: '0', 'box-shadow': '-10px 0 5px -9px rgba(0, 0, 0, 0.3)' }"
|
|
203
|
+
v-if="showViewerFile">
|
|
204
|
+
<div
|
|
205
|
+
:style="{ position: 'sticky', top: '0', height: (dialogHeight) + 'px', overflow: 'hidden', 'border-bottom-right-radius': '4px' }">
|
|
206
|
+
<ViewerFile :MediaAlbum="media.MediaAlbum" :groupIndex="media.groupIndex" :index="media.index"
|
|
207
|
+
:key="media.random" :flagLeft="media.flagLeft" @closeViewerFile="ViewerFileToggle(false)"
|
|
208
|
+
@ViewerFilechangeIndex="ViewerFilechangeIndex">
|
|
209
|
+
</ViewerFile>
|
|
210
|
+
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
200
213
|
|
|
201
214
|
</div>
|
|
202
215
|
<template v-if="model?.aiAttr?.showAI && !showAI">
|
|
@@ -205,13 +218,14 @@
|
|
|
205
218
|
:alt="model?.aiRouter.controlLabel" :title="model?.aiRouter.controlLabel">
|
|
206
219
|
</div>
|
|
207
220
|
</template>
|
|
221
|
+
|
|
208
222
|
<div style="min-height:200px" v-if="loading"></div>
|
|
209
223
|
<iframe :src="downloadUrl" style="height:0px;width:0px;border-width: 0px;display: none;"> </iframe>
|
|
210
224
|
|
|
211
225
|
</div>
|
|
212
226
|
</template>
|
|
213
227
|
<script lang="ts" setup>
|
|
214
|
-
import { ref, nextTick, onUpdated, onDeactivated, onMounted, onBeforeUnmount,provide } from 'vue'
|
|
228
|
+
import { ref, nextTick, onUpdated, onDeactivated, onMounted, onBeforeUnmount, provide } from 'vue'
|
|
215
229
|
import { RouterClickHandler } from '../../utils/mixins';
|
|
216
230
|
import common from '../../utils/common'
|
|
217
231
|
import Form from '../../loader/src/Form'
|
|
@@ -220,7 +234,9 @@ import { useRouter } from 'vue-router';
|
|
|
220
234
|
import util from '../../utils/pub-use'
|
|
221
235
|
import Enum from '../../utils/Enum';
|
|
222
236
|
import AIChat from '../web/AIChat.vue';
|
|
223
|
-
|
|
237
|
+
import ViewerFile from '../web/ViewerFile.vue';
|
|
238
|
+
|
|
239
|
+
const emit = defineEmits(['loaded', 'failLoad', 'submit', 'ToggleWdth'])
|
|
224
240
|
const props = defineProps({
|
|
225
241
|
api: String,
|
|
226
242
|
vmodel: Object,
|
|
@@ -283,6 +299,14 @@ const props = defineProps({
|
|
|
283
299
|
dialoWidth: Number,
|
|
284
300
|
listHeight: Number,
|
|
285
301
|
})
|
|
302
|
+
const media = ref({
|
|
303
|
+
MediaAlbum: [],
|
|
304
|
+
groupIndex: 0,
|
|
305
|
+
index: 0,
|
|
306
|
+
flagLeft: false,
|
|
307
|
+
random: Math.random()
|
|
308
|
+
})
|
|
309
|
+
const showViewerFile = ref(false)
|
|
286
310
|
const itemKey = ref(1)
|
|
287
311
|
const router = useRouter()
|
|
288
312
|
const loading = ref(true)
|
|
@@ -292,6 +316,7 @@ const isScroll = ref(false)
|
|
|
292
316
|
const isWebScroll = ref(false)
|
|
293
317
|
const Fields = ref()
|
|
294
318
|
const refForm = ref()
|
|
319
|
+
|
|
295
320
|
const downloadUrl = ref('')
|
|
296
321
|
const minHeight = ref('auto')
|
|
297
322
|
const showAI = ref(false);
|
|
@@ -366,11 +391,11 @@ function init() {
|
|
|
366
391
|
}
|
|
367
392
|
if (typeof props.api !== 'undefined') {
|
|
368
393
|
//根据接口获取数据
|
|
369
|
-
Form.loadFormApi(props.api, load, props.apiParam, failLoad, false,props.appRootUrl);
|
|
394
|
+
Form.loadFormApi(props.api, load, props.apiParam, failLoad, false, props.appRootUrl);
|
|
370
395
|
}
|
|
371
396
|
else if (typeof props.source !== 'undefined') {
|
|
372
397
|
//根据modelFrom获取数据
|
|
373
|
-
load(Form.loadFromModel(props.source,false,props.appRootUrl));
|
|
398
|
+
load(Form.loadFromModel(props.source, false, props.appRootUrl));
|
|
374
399
|
}
|
|
375
400
|
else if (props.vmodel) {
|
|
376
401
|
load(props.vmodel);
|
|
@@ -764,20 +789,223 @@ function setCss() {
|
|
|
764
789
|
|
|
765
790
|
function AIToggle() {
|
|
766
791
|
showAI.value = !showAI.value;
|
|
792
|
+
if (showAI.value) {
|
|
793
|
+
if (showViewerFile.value) {
|
|
794
|
+
ViewerFileToggle(false, [], 0, 0);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
767
798
|
let width = model.value.aiAttr.width;
|
|
768
799
|
dialogHeight.value = (props.dialogHeight || (window.innerHeight - 60));
|
|
769
|
-
emit('
|
|
800
|
+
emit('ToggleWdth', (showAI.value ? width : -width));
|
|
801
|
+
}
|
|
802
|
+
const getVisibleDimensions = () => {
|
|
803
|
+
if (!refForm.value) return { width: 0, height: 0 };
|
|
804
|
+
const rect = refForm.value.getBoundingClientRect();
|
|
805
|
+
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
806
|
+
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
807
|
+
|
|
808
|
+
const visibleTop = Math.max(0, rect.top);
|
|
809
|
+
const visibleBottom = Math.min(viewHeight, rect.bottom);
|
|
810
|
+
const visibleLeft = Math.max(0, rect.left);
|
|
811
|
+
const visibleRight = Math.min(viewWidth, rect.right);
|
|
812
|
+
|
|
813
|
+
return {
|
|
814
|
+
width: Math.max(0, visibleRight - visibleLeft),
|
|
815
|
+
height: Math.max(0, visibleBottom - visibleTop)-60
|
|
816
|
+
};
|
|
817
|
+
};
|
|
818
|
+
function ViewerFileToggle(isOpen, mediaAlbum, groupIndex, index) {
|
|
819
|
+
if (isOpen) {
|
|
820
|
+
media.value = { MediaAlbum: mediaAlbum, groupIndex, index, flagLeft: false, random: Math.random() };
|
|
821
|
+
if (showAI.value) {
|
|
822
|
+
AIToggle();
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
if (showViewerFile.value != isOpen) {
|
|
826
|
+
showViewerFile.value = isOpen;
|
|
827
|
+
let width = 650;
|
|
828
|
+
dialogHeight.value = getVisibleDimensions().height || parseInt(minHeight.value) || window.innerHeight - 60;
|
|
829
|
+
emit('ToggleWdth', (showViewerFile.value ? width : -width));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
provide('onViewerFileToggle', ViewerFileToggle)
|
|
833
|
+
function ViewerFilechangeIndex({ groupIndex, index }) {
|
|
834
|
+
if (media.value) {
|
|
835
|
+
media.value.groupIndex = groupIndex;
|
|
836
|
+
media.value.index = index;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function ChangeFileList(mediaAlbum, groupIndex, index) {
|
|
841
|
+
if (!showViewerFile.value) {
|
|
842
|
+
return;
|
|
843
|
+
} else {
|
|
844
|
+
if (mediaAlbum[0].medias.length <= 0) {
|
|
845
|
+
ViewerFileToggle(false);
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
const oldMedia = media.value;
|
|
850
|
+
let newGroupIndex, newIndex, shouldShow;
|
|
851
|
+
|
|
852
|
+
// 情况1:没有旧记录,直接用传入索引,无效则找第一张
|
|
853
|
+
if (!oldMedia || !oldMedia.MediaAlbum) {
|
|
854
|
+
if (validatePosition(mediaAlbum, groupIndex, index)) {
|
|
855
|
+
newGroupIndex = groupIndex;
|
|
856
|
+
newIndex = index;
|
|
857
|
+
shouldShow = true;
|
|
858
|
+
} else {
|
|
859
|
+
const first = findFirstValidPosition(mediaAlbum);
|
|
860
|
+
if (first) {
|
|
861
|
+
newGroupIndex = first.groupIndex;
|
|
862
|
+
newIndex = first.index;
|
|
863
|
+
shouldShow = true;
|
|
864
|
+
} else {
|
|
865
|
+
// 整个相册无图,直接关闭查看器,但依然要更新 MediaAlbum
|
|
866
|
+
newGroupIndex = 0;
|
|
867
|
+
newIndex = 0;
|
|
868
|
+
shouldShow = false;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} else {
|
|
872
|
+
// 取出旧图片
|
|
873
|
+
const oldAlbumList = oldMedia.MediaAlbum;
|
|
874
|
+
const oldGroup = oldAlbumList && oldAlbumList[oldMedia.groupIndex];
|
|
875
|
+
const oldFile = oldGroup && oldGroup.medias && oldGroup.medias[oldMedia.index];
|
|
876
|
+
|
|
877
|
+
if (oldFile) {
|
|
878
|
+
// 尝试在新相册中定位旧图
|
|
879
|
+
const found = findFileInAlbum(mediaAlbum, oldFile);
|
|
880
|
+
if (found) {
|
|
881
|
+
// 找到了,移动到新位置
|
|
882
|
+
newGroupIndex = found.groupIndex;
|
|
883
|
+
newIndex = found.index;
|
|
884
|
+
shouldShow = true;
|
|
885
|
+
} else {
|
|
886
|
+
// 旧图被删,回退
|
|
887
|
+
const fallback = fallbackPosition(mediaAlbum, oldMedia.groupIndex, oldMedia.index);
|
|
888
|
+
newGroupIndex = fallback.groupIndex;
|
|
889
|
+
newIndex = fallback.index;
|
|
890
|
+
shouldShow = fallback.show;
|
|
891
|
+
}
|
|
892
|
+
} else {
|
|
893
|
+
// 旧记录无效,同样回退
|
|
894
|
+
const fallback = fallbackPosition(mediaAlbum, oldMedia.groupIndex, oldMedia.index);
|
|
895
|
+
newGroupIndex = fallback.groupIndex;
|
|
896
|
+
newIndex = fallback.index;
|
|
897
|
+
shouldShow = fallback.show;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
ViewerFileToggle(showViewerFile.value, mediaAlbum, newGroupIndex, newIndex);
|
|
770
901
|
}
|
|
902
|
+
provide('ChangeFileList', ChangeFileList)
|
|
771
903
|
|
|
904
|
+
function validatePosition(albumList, gIdx, idx) {
|
|
905
|
+
if (!albumList || gIdx < 0 || gIdx >= albumList.length) {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
var group = albumList[gIdx];
|
|
909
|
+
var medias = group && group.medias;
|
|
910
|
+
return medias && idx >= 0 && idx < medias.length;
|
|
911
|
+
}
|
|
912
|
+
function findFirstValidPosition(albumList) {
|
|
913
|
+
if (!albumList) {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
for (var g = 0; g < albumList.length; g++) {
|
|
917
|
+
var group = albumList[g];
|
|
918
|
+
var medias = group && group.medias;
|
|
919
|
+
if (medias && medias.length > 0) {
|
|
920
|
+
return { groupIndex: g, index: 0 };
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
function findFileInAlbum(albumList, targetFile) {
|
|
926
|
+
if (!albumList) {
|
|
927
|
+
return null;
|
|
928
|
+
}
|
|
929
|
+
// 先按引用查找
|
|
930
|
+
for (var g = 0; g < albumList.length; g++) {
|
|
931
|
+
var medias = albumList[g].medias;
|
|
932
|
+
if (!medias) continue;
|
|
933
|
+
for (var i = 0; i < medias.length; i++) {
|
|
934
|
+
if (medias[i] === targetFile) {
|
|
935
|
+
return { groupIndex: g, index: i };
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
// 如果引用匹配不到,尝试用 id(如果存在)
|
|
940
|
+
if (targetFile && targetFile.id != null) {
|
|
941
|
+
for (var g2 = 0; g2 < albumList.length; g2++) {
|
|
942
|
+
var medias2 = albumList[g2].medias;
|
|
943
|
+
if (!medias2) continue;
|
|
944
|
+
for (var i2 = 0; i2 < medias2.length; i2++) {
|
|
945
|
+
if (medias2[i2].id === targetFile.id) {
|
|
946
|
+
return { groupIndex: g2, index: i2 };
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
function fallbackPosition(albumList, prefGroup, prefIndex) {
|
|
954
|
+
if (!albumList || albumList.length === 0) {
|
|
955
|
+
return { groupIndex: 0, index: 0, show: false };
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// 确保参考相册索引在有效范围内
|
|
959
|
+
var gIdx = Math.min(prefGroup, albumList.length - 1);
|
|
960
|
+
var group = albumList[gIdx];
|
|
961
|
+
var medias = group && group.medias ? group.medias : [];
|
|
962
|
+
|
|
963
|
+
// 1. 同相册内回退
|
|
964
|
+
if (medias.length > 0) {
|
|
965
|
+
var newIdx;
|
|
966
|
+
if (prefIndex > 0 && prefIndex <= medias.length) {
|
|
967
|
+
// 优先上一张
|
|
968
|
+
newIdx = prefIndex - 1;
|
|
969
|
+
} else if (prefIndex === 0 && medias.length > 1) {
|
|
970
|
+
// 第一张被删了,取下一张(索引 1)
|
|
971
|
+
newIdx = 1;
|
|
972
|
+
} else {
|
|
973
|
+
// 只剩这一张,还是它
|
|
974
|
+
newIdx = 0;
|
|
975
|
+
}
|
|
976
|
+
return { groupIndex: gIdx, index: newIdx, show: true };
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// 2. 向前找非空相册,取最后一张
|
|
980
|
+
for (var g = gIdx - 1; g >= 0; g--) {
|
|
981
|
+
var m = albumList[g].medias || [];
|
|
982
|
+
if (m.length > 0) {
|
|
983
|
+
return { groupIndex: g, index: m.length - 1, show: true };
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// 3. 向后找非空相册,取第一张
|
|
988
|
+
for (var g2 = gIdx + 1; g2 < albumList.length; g2++) {
|
|
989
|
+
var m2 = albumList[g2].medias || [];
|
|
990
|
+
if (m2.length > 0) {
|
|
991
|
+
return { groupIndex: g2, index: 0, show: true };
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// 整个相册没有任何图片了
|
|
996
|
+
return { groupIndex: 0, index: 0, show: false };
|
|
997
|
+
}
|
|
772
998
|
|
|
773
999
|
function buttonsWidth() {
|
|
774
1000
|
let rtn = '100%';
|
|
775
1001
|
if (showAI.value) {
|
|
776
|
-
rtn = props.dialoWidth - model.value.aiAttr.width - 4 + 'px';
|
|
1002
|
+
rtn = (props.dialoWidth||getVisibleDimensions().width) - model.value.aiAttr.width - 4 + 'px';
|
|
1003
|
+
}
|
|
1004
|
+
else if (showViewerFile.value) {
|
|
1005
|
+
rtn = (props.dialoWidth||getVisibleDimensions().width) - 650 - 4 + 'px';
|
|
777
1006
|
}
|
|
778
1007
|
else if (props.pageWidth) {
|
|
779
1008
|
rtn = props.pageWidth + 'px';
|
|
780
|
-
|
|
781
1009
|
}
|
|
782
1010
|
|
|
783
1011
|
return rtn;
|