centaline-data-driven-v3 0.1.40 → 0.1.42
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 +96 -96
- package/package.json +1 -1
- package/src/components/web/Form.vue +275 -19
- package/src/components/web/Tree/Tree.vue +766 -176
- package/src/components/web/TreeList.vue +2 -2
- package/src/loader/src/SearchScreen.js +1 -1
- package/src/main.js +5 -4
- package/src/utils/request.js +5 -6
- package/src/views/Form.vue +2 -2
- package/src/views/SearchList.vue +5 -2
- package/src/views/Tree.vue +9 -3
package/package.json
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
:style="{ width: pageWidth ? pageWidth + 'px' : '100%', margin: 'auto', 'min-height': minHeight }">
|
|
4
4
|
<div style="display: flex; width: 100%;">
|
|
5
5
|
<div style="flex: 1; min-width: 0;">
|
|
6
|
-
<div v-if="model !== null && !loading" class="ct-form"
|
|
7
|
-
|
|
6
|
+
<div v-if="model !== null && !loading" class="ct-form"
|
|
7
|
+
:style="{ margin: openType != 'tree' ? '10px' : '0px' }">
|
|
8
|
+
<el-affix target=".ct-form" v-if="model.tip" :offset="tipTopHight">
|
|
8
9
|
<div class="ct-form-tip" ref="refTip">
|
|
9
10
|
<span v-html="model.tip"></span>
|
|
10
11
|
</div>
|
|
@@ -57,7 +58,8 @@
|
|
|
57
58
|
<template v-if="model.isHorizontalLayout">
|
|
58
59
|
<component :is="model.flagFixedTabOnHorizontalLayout ? 'el-affix' : 'div'"
|
|
59
60
|
v-bind="model.flagFixedTabOnHorizontalLayout ? { offset: tabTopHight, target: '.ct-form' } : {}">
|
|
60
|
-
<el-tabs v-model="activeName" @tab-click="tabClick" style="background: #fff;"
|
|
61
|
+
<el-tabs v-model="activeName" @tab-click="tabClick" style="background: #fff;"
|
|
62
|
+
ref="refTabs">
|
|
61
63
|
<template v-for="(item, index) in model.collapse" :key="index">
|
|
62
64
|
<el-tab-pane :name="index.toString()" :lazy="item.lazyLoad"
|
|
63
65
|
v-if="item.show !== false" :key="index">
|
|
@@ -110,10 +112,11 @@
|
|
|
110
112
|
v-if="col.show !== false && col.lineFeed"></div>
|
|
111
113
|
<el-col :span="col.colspan" v-if="col.show !== false" style="padding:5px"
|
|
112
114
|
:class="[col.is == 'ct-button' && col.labelPlacement == '1' ? 'el-col1' : '']">
|
|
113
|
-
<component ref="Fields" :is="col.is" :vmodel="col"
|
|
114
|
-
:
|
|
115
|
-
v-bind="col.bindPara"
|
|
116
|
-
|
|
115
|
+
<component ref="Fields" :is="col.is" :vmodel="col"
|
|
116
|
+
:key="col.fieldItemKey" :listHeight="listHeight"
|
|
117
|
+
:parameterAction="model.parameterAction" v-bind="col.bindPara"
|
|
118
|
+
:fileData="getFileData(col)" @change="changeHandler"
|
|
119
|
+
@fieldClick="fieldClickHandler"
|
|
117
120
|
@popupLocation="popupLocationHandler"
|
|
118
121
|
@popupSearchList="popupSearchListHandler"
|
|
119
122
|
@importComplete="importComplete"
|
|
@@ -272,7 +275,6 @@ const props = defineProps({
|
|
|
272
275
|
dialoWidth: Number,
|
|
273
276
|
listHeight: Number,
|
|
274
277
|
})
|
|
275
|
-
|
|
276
278
|
const itemKey = ref(1)
|
|
277
279
|
const router = useRouter()
|
|
278
280
|
const loading = ref(true)
|
|
@@ -288,7 +290,10 @@ const showAI = ref(false);
|
|
|
288
290
|
const dialogHeight = ref(props.dialogHeight || (window.innerHeight - 60));
|
|
289
291
|
const tabActiveNameKey = ref('')
|
|
290
292
|
const refTip = ref()
|
|
291
|
-
const
|
|
293
|
+
const tipTopHight = ref(0)
|
|
294
|
+
const tabTopHight = ref(0)
|
|
295
|
+
const refTabs = ref()
|
|
296
|
+
const translateX = ref(0)
|
|
292
297
|
|
|
293
298
|
const qrtimer1 = ref(null)
|
|
294
299
|
const qrtimer2 = ref(null)
|
|
@@ -320,8 +325,27 @@ onUpdated(() => {
|
|
|
320
325
|
onDeactivated(() => {
|
|
321
326
|
downloadUrl.value = ''
|
|
322
327
|
})
|
|
328
|
+
|
|
323
329
|
onMounted(() => {
|
|
324
330
|
setCss();
|
|
331
|
+
if (refForm.value) {
|
|
332
|
+
const rect = refForm.value.getBoundingClientRect()
|
|
333
|
+
const distanceFromTop = rect.top + window.scrollY
|
|
334
|
+
tipTopHight.value = distanceFromTop;
|
|
335
|
+
if (refTip.value) {
|
|
336
|
+
tabTopHight.value = tabTopHight.value + refTip.value.clientHeight + 10
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
tabTopHight.value = tipTopHight.value;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
nextTick(() => {
|
|
343
|
+
|
|
344
|
+
setTimeout(() => {
|
|
345
|
+
attachScrollButtonListeners()
|
|
346
|
+
}, 1000);
|
|
347
|
+
|
|
348
|
+
});
|
|
325
349
|
})
|
|
326
350
|
init()
|
|
327
351
|
//初始化数据
|
|
@@ -379,11 +403,6 @@ function load(data) {
|
|
|
379
403
|
|
|
380
404
|
}
|
|
381
405
|
}
|
|
382
|
-
nextTick(() => {
|
|
383
|
-
if (refTip.value) {
|
|
384
|
-
tabTopHight.value = tabTopHight.value + refTip.value.clientHeight + 10
|
|
385
|
-
}
|
|
386
|
-
})
|
|
387
406
|
//通知父组件加载完成
|
|
388
407
|
emit('loaded', model.value);
|
|
389
408
|
}
|
|
@@ -703,11 +722,29 @@ function setCss() {
|
|
|
703
722
|
if (props.topHeight > -1) {
|
|
704
723
|
minHeight.value = (document.documentElement.clientHeight - props.topHeight - 20) + 'px';
|
|
705
724
|
}
|
|
706
|
-
else if(props.dialogHeight){
|
|
725
|
+
else if (props.dialogHeight) {
|
|
707
726
|
minHeight.value = (props.dialogHeight) + 'px';
|
|
708
727
|
}
|
|
709
|
-
else{
|
|
710
|
-
|
|
728
|
+
else if (props.openType == 'tree') {
|
|
729
|
+
if (refForm.value) {
|
|
730
|
+
let parentDom = refForm.value.parentElement;
|
|
731
|
+
minHeight.value = parentDom.clientHeight + 'px';
|
|
732
|
+
refForm.value.style.height = minHeight.value
|
|
733
|
+
refForm.value.style.overflowY = 'auto'
|
|
734
|
+
refForm.value.style.paddingBottom = '45px'
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else if (props.openType == 'detail') {
|
|
738
|
+
if (refForm.value) {
|
|
739
|
+
let parentDom = refForm.value.parentElement;
|
|
740
|
+
minHeight.value = parentDom.clientHeight + 'px';
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
if (refForm.value) {
|
|
745
|
+
let parentDom = refForm.value.parentElement;
|
|
746
|
+
minHeight.value = parentDom.clientHeight + 'px';
|
|
747
|
+
}
|
|
711
748
|
}
|
|
712
749
|
}
|
|
713
750
|
|
|
@@ -726,16 +763,235 @@ function buttonsWidth() {
|
|
|
726
763
|
rtn = props.dialoWidth - model.value.aiAttr.width - 4 + 'px';
|
|
727
764
|
}
|
|
728
765
|
else if (props.pageWidth) {
|
|
729
|
-
rtn = props.pageWidth
|
|
766
|
+
rtn = props.pageWidth + 'px';
|
|
730
767
|
|
|
731
768
|
}
|
|
769
|
+
|
|
732
770
|
return rtn;
|
|
733
771
|
}
|
|
734
772
|
|
|
735
|
-
|
|
773
|
+
|
|
774
|
+
// 点击后让激活 Tab 居中
|
|
775
|
+
async function tabClick(pane: TabsPaneContext) {
|
|
736
776
|
if (props.openType == 'detail') {
|
|
737
777
|
window.localStorage.setItem(tabActiveNameKey.value, model.value.collapse[event.index].fieldName1);//存储
|
|
738
778
|
}
|
|
779
|
+
await nextTick() // 等 DOM 更新完再取节点
|
|
780
|
+
const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
|
|
781
|
+
const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
|
|
782
|
+
const activeBtn = document.querySelector(`.el-tabs__item#tab-${pane.paneName}`) as HTMLElement
|
|
783
|
+
if (!navWrapScroll || !navWrap || !activeBtn) return
|
|
784
|
+
const visibleCount = getVisibleTabCount()
|
|
785
|
+
if (pane.index <= visibleCount / 2) {
|
|
786
|
+
setTimeout(() => {
|
|
787
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
788
|
+
navWrap.style.transform = 'translateX(0px)'
|
|
789
|
+
}, 50);
|
|
790
|
+
translateX.value = 0
|
|
791
|
+
return
|
|
792
|
+
}
|
|
793
|
+
const allTabs = Array.from(navWrap.querySelectorAll('.el-tabs__item')) as HTMLElement[]
|
|
794
|
+
const total = allTabs.length
|
|
795
|
+
if (pane.index >= total - 5) {
|
|
796
|
+
const lastTab = allTabs[total - 1]
|
|
797
|
+
const wrapWidth = navWrapScroll.clientWidth
|
|
798
|
+
const lastWidth = lastTab.offsetWidth
|
|
799
|
+
const lastRight = lastTab.offsetLeft + lastWidth // 最后一个右边到 nav 左边的距离
|
|
800
|
+
const needShift = wrapWidth - lastRight // 负值,让右边对齐容器右边
|
|
801
|
+
setTimeout(() => {
|
|
802
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
803
|
+
navWrap.style.transform = `translateX(${needShift}px)`
|
|
804
|
+
}, 50);
|
|
805
|
+
translateX.value = needShift
|
|
806
|
+
return
|
|
807
|
+
}
|
|
808
|
+
/* ---------- 1. 初始状态:还没滑过 ---------- */
|
|
809
|
+
const neverSlid = navWrap.style.transform == 'translateX(0px)'
|
|
810
|
+
|
|
811
|
+
if (neverSlid && pane.index >= visibleCount / 2) {
|
|
812
|
+
/* 第一次往后走,直接允许滑动 → 走居中逻辑 */
|
|
813
|
+
const wrapWidth = navWrapScroll.clientWidth
|
|
814
|
+
const btnLeft = activeBtn.offsetLeft
|
|
815
|
+
const btnWidth = activeBtn.offsetWidth
|
|
816
|
+
const dx = (wrapWidth - btnWidth) / 2 - btnLeft
|
|
817
|
+
setTimeout(() => {
|
|
818
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
819
|
+
navWrap.style.transform = `translateX(${dx}px)`
|
|
820
|
+
}, 50);
|
|
821
|
+
translateX.value = dx
|
|
822
|
+
return
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/* ---------- 2. 已经滑过 → 恢复两端贴边即锁死 ---------- */
|
|
826
|
+
const firstTab = navWrap.querySelector('.el-tabs__item') as HTMLElement
|
|
827
|
+
const lastTab = navWrap.querySelector('.el-tabs__item:last-child') as HTMLElement
|
|
828
|
+
if (!firstTab || !lastTab) return
|
|
829
|
+
|
|
830
|
+
const lastAtRight = lastTab.getBoundingClientRect().right <= navWrapScroll.getBoundingClientRect().right
|
|
831
|
+
|
|
832
|
+
if ((lastAtRight && pane.index >= total - 5)) {
|
|
833
|
+
return
|
|
834
|
+
} // 已贴边,不滑
|
|
835
|
+
|
|
836
|
+
/* 需要居中 */
|
|
837
|
+
const wrapWidth = navWrapScroll.clientWidth
|
|
838
|
+
const btnLeft = activeBtn.offsetLeft
|
|
839
|
+
const btnWidth = activeBtn.offsetWidth
|
|
840
|
+
const dx = (wrapWidth - btnWidth) / 2 - btnLeft
|
|
841
|
+
translateX.value = dx
|
|
842
|
+
setTimeout(() => {
|
|
843
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
844
|
+
navWrap.style.transform = `translateX(${dx}px)`
|
|
845
|
+
}, 50);
|
|
846
|
+
}
|
|
847
|
+
/** 返回当前屏幕完全可见的 tab 个数 */
|
|
848
|
+
function getVisibleTabCount(): number {
|
|
849
|
+
const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
|
|
850
|
+
const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
|
|
851
|
+
if (!navWrapScroll || !navWrap) return 0
|
|
852
|
+
|
|
853
|
+
const wrapWidth = navWrapScroll.clientWidth // 容器可视宽
|
|
854
|
+
const allTabs = Array.from(navWrap.querySelectorAll('.el-tabs__item')) as HTMLElement[]
|
|
855
|
+
if (!allTabs.length) return 0
|
|
856
|
+
|
|
857
|
+
// ① 如果所有 tab 总宽度 ≤ 容器宽,全部可见
|
|
858
|
+
const totalWidth = allTabs.reduce((sum, tab) => sum + tab.offsetWidth, 0)
|
|
859
|
+
if (totalWidth <= wrapWidth) return allTabs.length
|
|
860
|
+
|
|
861
|
+
// ② 否则按“平均宽度”向下取整
|
|
862
|
+
const avgWidth = totalWidth / allTabs.length
|
|
863
|
+
return Math.floor(wrapWidth / avgWidth)
|
|
864
|
+
}
|
|
865
|
+
function attachScrollButtonListeners() {
|
|
866
|
+
if (refTabs.value) {
|
|
867
|
+
const tabsEl = refTabs.value.$el
|
|
868
|
+
|
|
869
|
+
// 监听原生左右箭头点击事件(事件委托)
|
|
870
|
+
const arrowLeft = tabsEl.querySelector('.el-tabs__nav-prev')
|
|
871
|
+
const arrowRight = tabsEl.querySelector('.el-tabs__nav-next')
|
|
872
|
+
|
|
873
|
+
if (arrowLeft) {
|
|
874
|
+
// 1. 移除所有已有事件监听(保险)
|
|
875
|
+
const newArrowLeft = arrowLeft.cloneNode(true)
|
|
876
|
+
arrowLeft.parentNode.replaceChild(newArrowLeft, arrowLeft)
|
|
877
|
+
// 2. 添加自定义事件,彻底阻断原生行为
|
|
878
|
+
newArrowLeft.addEventListener('click', handleArrowLeft, { capture: true })
|
|
879
|
+
newArrowLeft.addEventListener('mousedown', (e) => e.preventDefault(), { capture: true })
|
|
880
|
+
arrowLeft.addEventListener('click', handleArrowLeft)
|
|
881
|
+
}
|
|
882
|
+
if (arrowRight) {
|
|
883
|
+
// 1. 移除所有已有事件监听(保险)
|
|
884
|
+
const newArrowRight = arrowRight.cloneNode(true)
|
|
885
|
+
arrowRight.parentNode.replaceChild(newArrowRight, arrowRight)
|
|
886
|
+
// 2. 添加自定义事件,彻底阻断原生行为
|
|
887
|
+
newArrowRight.addEventListener('click', handleArrowRight, { capture: true })
|
|
888
|
+
newArrowRight.addEventListener('mousedown', (e) => e.preventDefault(), { capture: true })
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
function handleArrowLeft(e) {
|
|
893
|
+
// 彻底阻断原生事件传播和默认行为
|
|
894
|
+
e.stopImmediatePropagation()
|
|
895
|
+
e.stopPropagation()
|
|
896
|
+
e.preventDefault()
|
|
897
|
+
scrollTabs('left')
|
|
898
|
+
}
|
|
899
|
+
function handleArrowRight(e) {
|
|
900
|
+
// 彻底阻断原生事件传播和默认行为
|
|
901
|
+
e.stopImmediatePropagation()
|
|
902
|
+
e.stopPropagation()
|
|
903
|
+
e.preventDefault()
|
|
904
|
+
scrollTabs('right')
|
|
905
|
+
}
|
|
906
|
+
function scrollTabs(direction) {
|
|
907
|
+
const navWrapScroll = document.querySelector('.el-tabs__nav-scroll') as HTMLElement
|
|
908
|
+
const navWrap = document.querySelector('.el-tabs__nav') as HTMLElement
|
|
909
|
+
if (!navWrapScroll || !navWrap) return
|
|
910
|
+
const allTabs = Array.from(navWrap.querySelectorAll('.el-tabs__item')) as HTMLElement[]
|
|
911
|
+
if (!allTabs.length) return
|
|
912
|
+
// 找到当前第一个可见的标签索引
|
|
913
|
+
const firstVisibleIndex = getFirstVisibleTabIndex(allTabs)
|
|
914
|
+
if (direction == 'left') {
|
|
915
|
+
if (translateX.value >= 0) {
|
|
916
|
+
translateX.value = 0
|
|
917
|
+
setTimeout(() => {
|
|
918
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
919
|
+
navWrap.style.transform = `translateX(${translateX.value}px)`
|
|
920
|
+
}, 50);
|
|
921
|
+
return
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// 找到当前第一个可见的标签索引
|
|
925
|
+
const firstVisibleIndex = getFirstVisibleTabIndex(allTabs)
|
|
926
|
+
// 计算上一个标签的宽度
|
|
927
|
+
const prevTabWidth = getFirstVisibleTabIndex(allTabs) > 0 ? getTabWidth(allTabs, firstVisibleIndex - 1) : 0
|
|
928
|
+
if (prevTabWidth == 0) {
|
|
929
|
+
translateX.value = 0
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
// 更新偏移量(向右平移)
|
|
933
|
+
translateX.value += prevTabWidth
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
setTimeout(() => {
|
|
937
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
938
|
+
navWrap.style.transform = `translateX(${translateX.value}px)`
|
|
939
|
+
}, 50);
|
|
940
|
+
}
|
|
941
|
+
else if (direction == 'right') {
|
|
942
|
+
|
|
943
|
+
// 判断最后一个标签是否已靠右,若是则禁止滚动
|
|
944
|
+
if (isLastTabAlignedRight(navWrapScroll, navWrap)) {
|
|
945
|
+
return
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// 计算下一个标签的宽度
|
|
949
|
+
const nextTabWidth = getTabWidth(allTabs, firstVisibleIndex)
|
|
950
|
+
// 更新偏移量(向左平移)
|
|
951
|
+
translateX.value -= nextTabWidth
|
|
952
|
+
setTimeout(() => {
|
|
953
|
+
navWrap.style.transition = 'transform .3s ease-out'
|
|
954
|
+
navWrap.style.transform = `translateX(${translateX.value}px)`
|
|
955
|
+
}, 50);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
// 获取当前第一个可见的标签索引
|
|
959
|
+
const getFirstVisibleTabIndex = (allTabs) => {
|
|
960
|
+
const scrollLeft = Math.abs(translateX.value)
|
|
961
|
+
let sumWidth = 0
|
|
962
|
+
for (let i = 0; i < allTabs.length; i++) {
|
|
963
|
+
sumWidth += getTabWidth(allTabs, i)
|
|
964
|
+
if (sumWidth > scrollLeft) {
|
|
965
|
+
return i
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return 0
|
|
969
|
+
}
|
|
970
|
+
// 计算单个标签宽度(包含间距)
|
|
971
|
+
const getTabWidth = (allTabs, index) => {
|
|
972
|
+
if (!allTabs[index]) return 0
|
|
973
|
+
const tab = allTabs[index]
|
|
974
|
+
// 获取标签的实际宽度(包含内边距、边框)
|
|
975
|
+
const width = tab.offsetWidth
|
|
976
|
+
// 获取标签的左右外边距(ElementPlus 默认有间距)
|
|
977
|
+
const style = window.getComputedStyle(tab)
|
|
978
|
+
const marginLeft = parseFloat(style.marginLeft) || 0
|
|
979
|
+
const marginRight = parseFloat(style.marginRight) || 0
|
|
980
|
+
return width + marginLeft + marginRight
|
|
981
|
+
}
|
|
982
|
+
// 检查最后一个标签是否已靠最右侧
|
|
983
|
+
const isLastTabAlignedRight = (navWrapScroll, navWrap) => {
|
|
984
|
+
|
|
985
|
+
// 滚动容器的可视宽度
|
|
986
|
+
const containerWidth = navWrapScroll.clientWidth
|
|
987
|
+
// 所有标签的总宽度
|
|
988
|
+
const totalTabsWidth = navWrap.scrollWidth
|
|
989
|
+
// 当前向左偏移的总距离(绝对值)
|
|
990
|
+
const currentOffset = Math.abs(translateX.value)
|
|
991
|
+
|
|
992
|
+
// 最后一个标签靠右的判定条件:偏移量 + 容器宽度 ≥ 总标签宽度
|
|
993
|
+
// 预留2px误差,避免因像素精度问题导致判断失误
|
|
994
|
+
return (currentOffset + containerWidth) >= (totalTabsWidth - 2)
|
|
739
995
|
}
|
|
740
996
|
|
|
741
997
|
</script>
|