提交 13aaddb5 编写于 作者: LUCIFER-ZHU's avatar LUCIFER-ZHU

update:更新表单锚点

上级 c5f14fb3
{{item.codeName}}: { {{item.codeName}}: {
caption: '{{item.caption}}', caption: '{{item.caption}}',
name: '{{item.name}}', name: '{{item.name}}',
codeName: '{{item.codeName}}',
disabled: false, disabled: false,
visible: true, visible: true,
detailStyle: '{{item.detailStyle}}', detailStyle: '{{item.detailStyle}}',
detailType: '{{item.detailType}}', detailType: '{{item.detailType}}',
showCaption: {{#if item.showCaption}}true{{else}}false{{/if}}, showCaption: {{#if item.showCaption}}true{{else}}false{{/if}},
enableAnchor: {{#if item.enableAnchor}}true{{else}}false{{/if}},
{{#if item.valueFormat}} {{#if item.valueFormat}}
valueFormat: '{{item.valueFormat}}', valueFormat: '{{item.valueFormat}}',
{{else}} {{else}}
......
{{#neq item.psEditor.editorType "HIDDEN"}}
<AppFormItem
name="{{item.codeName}}"
{{#if item.captionItemName}}
:label="state.data.{{lowerCase item.captionItemName}}"
{{else}}
label="{{item.caption}}"
{{/if}}
{{#if item.labelPos}}
labelPos="{{item.labelPos}}"
{{/if}}
:labelWidth="{{item.labelWidth}}"
:showLabel="{{item.showCaption}}"
:rules="state.rules.{{item.codeName}}"
:required="state.detailsModel.{{item.codeName}}.required"
:visible="state.detailsModel.{{item.codeName}}.visible"
:layoutOpts="{{> @macro/front-end/common/layoutPos.hbs layout=item.psLayout layoutPos=item.psLayoutPos}}"
{{#if item.psSysCss}}
class="{{item.psSysCss.cssName}}"
{{/if}}
{{#if item.labelPSSysCss}}
labelClass="{{item.labelPSSysCss.cssName}}"
{{/if}}
{{#if (or item.width item.height)}}
style="{{#if item.width}}width: {{item.width}}px;{{/if}}{{#if item.height}}height: {{item.height}}px;{{/if}}"
{{/if}}
>
{{#if item.compositeItem}}
{{#if (or (eq item.psEditor.editorType 'DATERANGE') (eq item.psEditor.editorType 'DATERANGE_NOTIME'))}}
<AppDateRange
:refFormItem="
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppDateRange>
{{else if (eq item.psEditor.editorType 'NUMBERRANGE')}}
<AppNumberRange
:refFormItem="
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppNumberRange>
{{else}}
<AppRangeEditor
:refFormItem="
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppRangeEditor>
{{/if}}
{{else}}
{{#if item.psEditor}}
<div class="form-editor-container" style="{{#if item.psEditor.editorWidth}}width: {{item.psEditor.editorWidth}}px;{{/if}}{{#if item.psEditor.editorHeight}}height: {{item.psEditor.editorHeight}}px{{/if}}">
{{> @macro/front-end/editors/include-editor.hbs type=item.psEditor.editorType item=item ctrlType="form"}}
</div>
{{/if}}
{{/if}}
</AppFormItem>
{{/neq}}
...@@ -25,83 +25,10 @@ ...@@ -25,83 +25,10 @@
style="{{#if item.width}}width: {{item.width}}px;{{/if}}{{#if item.height}}height: {{item.height}}px;{{/if}}" style="{{#if item.width}}width: {{item.width}}px;{{/if}}{{#if item.height}}height: {{item.height}}px;{{/if}}"
{{/if}} {{/if}}
> >
{{#if item.compositeItem}} {{#if item.psEditor}}
{{#if (or (eq item.psEditor.editorType 'DATERANGE') (eq item.psEditor.editorType 'DATERANGE_NOTIME'))}} <div class="form-editor-container" style="{{#if item.psEditor.editorWidth}}width: {{item.psEditor.editorWidth}}px;{{/if}}{{#if item.psEditor.editorHeight}}height: {{item.psEditor.editorHeight}}px{{/if}}">
<AppDateRange {{> @macro/front-end/editors/include-editor.hbs type=item.psEditor.editorType item=item ctrlType="form"}}
:refFormItem=" </div>
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppDateRange>
{{else if (eq item.psEditor.editorType 'NUMBERRANGE')}}
<AppNumberRange
:refFormItem="
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppNumberRange>
{{else}}
<AppRangeEditor
:refFormItem="
{{#if item.psDEFormItems}}
{{~#each item.psDEFormItems as | formItem | ~}}
{{#if @first}}[{{/if~}}
'{{formItem.name}}'{{#unless @last}},{{/unless}}
{{~#if @last}}]{{/if~}}
{{/each}}
{{else}}
[]
{{/if}}"
name="{{item.codeName}}"
:value="state.data.{{item.psEditor.name}}"
:activeData="state.data"
editorType="{{item.psEditor.editorType}}"
:disabled="state.detailsModel.{{item.codeName}}.disabled"
{{#if item.psEditor.editorParams.TIMEFMT}}
format="{{item.psEditor.editorParams.TIMEFMT}}"
{{/if}}
@editorEvent="onEditorEvent"
>
</AppRangeEditor>
{{/if}}
{{else}}
{{#if item.psEditor}}
<div class="form-editor-container" style="{{#if item.psEditor.editorWidth}}width: {{item.psEditor.editorWidth}}px;{{/if}}{{#if item.psEditor.editorHeight}}height: {{item.psEditor.editorHeight}}px{{/if}}">
{{> @macro/front-end/editors/include-editor.hbs type=item.psEditor.editorType item=item ctrlType="form"}}
</div>
{{/if}}
{{/if}} {{/if}}
</AppFormItem> </AppFormItem>
{{/neq}} {{/neq}}
{{#eq type "FORMPAGE"}}{{> @macro/front-end/widgets/form-detail/form-page.hbs}}{{/eq}} {{#eq type "FORMPAGE"}}{{> @macro/front-end/widgets/form-detail/form-page.hbs}}{{/eq}}
{{#eq type "GROUPPANEL"}}{{> @macro/front-end/widgets/form-detail/form-group-panel.hbs}}{{/eq}} {{#eq type "GROUPPANEL"}}{{> @macro/front-end/widgets/form-detail/form-group-panel.hbs}}{{/eq}}
{{#eq type "FORMITEM"}}{{> @macro/front-end/widgets/form-detail/form-item.hbs}}{{/eq}} {{#eq type "FORMITEM"}}{{> @macro/front-end/widgets/form-detail/form-item.hbs}}{{/eq}}
{{#eq type "FORMITEMEX"}}{{> @macro/front-end/widgets/form-detail/form-item-ex.hbs}}{{/eq}}
{{#eq type "TABPANEL"}}{{> @macro/front-end/widgets/form-detail/form-tabpanel.hbs}}{{/eq}} {{#eq type "TABPANEL"}}{{> @macro/front-end/widgets/form-detail/form-tabpanel.hbs}}{{/eq}}
{{#eq type "BUTTON"}}{{> @macro/front-end/widgets/form-detail/form-button.hbs}}{{/eq}} {{#eq type "BUTTON"}}{{> @macro/front-end/widgets/form-detail/form-button.hbs}}{{/eq}}
{{#eq type "IFRAME"}}{{> @macro/front-end/widgets/form-detail/form-iframe.hbs}}{{/eq}} {{#eq type "IFRAME"}}{{> @macro/front-end/widgets/form-detail/form-iframe.hbs}}{{/eq}}
......
<script setup lang="ts">
import { IActionParam, IParam } from '@core';
interface Props {
anchorDatas: any[];
viewType: string;
}
const props = withDefaults(defineProps<Props>(), {});
/**
* 绘制UI数据
*
* @type {any}
* @memberof AppAnchor
*/
let datas: any[] = props.anchorDatas;
/**
* 组件ref
*
* @type {any}
* @memberof AppAnchor
*/
let appAnchor = ref(null);
/**
* 滚动盒子
*
* @type {any}
* @memberof AppAnchor
*/
let container: any = ref(null);
/**
* Vue生命周期onBeforeMount
*/
onBeforeMount(() => {
datas.forEach((item: any) => {
item.active = false;
});
});
/**
* Vue生命周期mounted
*/
onMounted(() => {
// 需要异步获取,有些编辑器绘制慢,确保高度获取正确
setTimeout(() => {
// 获取滚动区域
getScrollContainer();
// 获取锚点到滚动条盒子顶部的距离
setSrollHeight();
// 滚动区域滚动时
handleScroll();
// 初始化默认锚点激活状态
initActiveState();
}, 0);
});
/**
* Vue生命周期onUpdated
*/
onUpdated(() => {
// 获取锚点到滚动条盒子顶部的距离
setSrollHeight();
});
/**
* Vue生命周期unmounted
*/
onUnmounted(() => {
if (container.value) {
container.value.removeEventListener('scroll', scrollEvent);
}
});
/**
* 获取滚动区域
*
* @memberof AppAnchor
*/
const getScrollContainer = () => {
switch (props.viewType) {
case 'DEEDITVIEW':
container.value = document.querySelector(`.app-view-layout__body`);
break;
case 'DEEDITVIEW3':
//TODO
break;
default:
container.value = document.querySelector(`.app-view-layout__body`);
break;
}
};
/**
* 滚动事件
*
* @memberof AppAnchor
*/
const scrollEvent = (e: any) => {
let scrollTop = e.target.scrollTop;
datas.forEach(item => {
item.active = false;
});
let i = -1;
while (++i <= datas.length) {
let currentEle = datas[i];
let nextEle = datas[i + 1];
if (scrollTop >= currentEle.scrollTop && scrollTop < ((nextEle && nextEle.scrollTop) || Infinity)) {
datas[i].active = true;
break;
}
}
// 滚动当前组件高度
if (appAnchor.value) {
(appAnchor.value as any).style.top = scrollTop + 20 + 'px';
}
};
/**
* 滚动区域滚动
*
* @memberof AppAnchor
*/
const handleScroll = () => {
if (container.value) {
container.value.addEventListener('scroll', scrollEvent);
}
};
/**
* 获取锚点到滚动条盒子顶部的距离
*
* @memberof AppAnchor
*/
const setSrollHeight = () => {
if (container.value) {
// 容器实际高度
const actualHeight: number = container.value.scrollHeight;
// 容器可视区域高度
const visualHeight: number = container.value.offsetHeight;
// 容器滑动条最大高度
const scrollHeight: number = actualHeight - visualHeight;
// 系数
// const coefficient = scrollHeight / actualHeight;
datas.forEach((item: any) => {
let dom: any = document.querySelector(`.app-form .${item.codeName}`);
if (dom) {
// 获取锚点元素与滚动盒子元素相对于视口的距离
let domTop: number = dom.getBoundingClientRect().top;
let containerTop: number = container.value.getBoundingClientRect().top;
let containerScrollTop: number = container.value.scrollTop;
// 获取需要滚动的距离
let total = Math.trunc(domTop - (containerTop - containerScrollTop));
item.scrollTop = total;
}
});
}
};
/**
* 设置锚点激活状态
*
* @memberof AppAnchor
*/
const initActiveState = () => {
if (datas?.length > 0) {
handleClick(datas[0], 0);
}
};
/**
* 处理点击事件
*/
const handleClick = (item: any, index: any) => {
// 设置滚动
if (container.value) {
container.value.scrollTop = item.scrollTop;
}
};
</script>
<template>
<div
class="app-anchor"
ref="appAnchor"
>
<div class="line"></div>
<div
:class="['anchor-points', item.active ? 'active' : 'inactive']"
v-for="(item, index) in datas"
:key="item.codeName"
@click.stop="handleClick(item, index)"
:ref="item.codeName"
>
<span
class="dot"
v-if="item.active"
></span>
{{ item.caption }}
</div>
</div>
</template>
<style lang="scss" scoped>
.app-anchor {
position: absolute;
top: 20px;
right: -13px;
z-index: 99;
border-radius: 4px;
padding: 10px 10px 10px 20px;
background: rgb(227, 237, 250);
.line {
width: 2px;
position: absolute;
height: calc(100% - 20px);
left: 10px;
background: #fff;
}
.anchor-points {
padding: 2px 0px;
cursor: pointer;
color: #b4bcca;
}
.active {
color: #2196f3;
position: relative;
.dot {
position: absolute;
display: inline-block;
top: 0px;
left: -10px;
width: 2px;
height: 25px;
background-color: #2196f3;
}
}
}
</style>
\ No newline at end of file
...@@ -50,7 +50,7 @@ const handleContentShowStatusChange = (event: MouseEvent) => { ...@@ -50,7 +50,7 @@ const handleContentShowStatusChange = (event: MouseEvent) => {
noRoot noRoot
:visible="visible" :visible="visible"
:layoutOpts="layoutOpts" :layoutOpts="layoutOpts"
:class="['app-form-group', `app-form-group-${name}`]" :class="['app-form-group', `app-form-group-${name}`, `${name}`]"
> >
<template #default="{ slotClass, slotStyle }"> <template #default="{ slotClass, slotStyle }">
<a-card :class="slotClass" :style="slotStyle" :headStyle="titleClass" :bordered="false"> <a-card :class="slotClass" :style="slotStyle" :headStyle="titleClass" :bordered="false">
......
...@@ -54,7 +54,7 @@ const initRules = () => { ...@@ -54,7 +54,7 @@ const initRules = () => {
</script> </script>
<template> <template>
<AppCol :visible="visible" noRoot :layoutOpts="layoutOpts" class="app-form-item"> <AppCol :visible="visible" noRoot :layoutOpts="layoutOpts" :class="['app-form-item', `app-form-item-${name}`, `${name}`]">
<template v-slot:default="{slotStyle, slotClass}"> <template v-slot:default="{slotStyle, slotClass}">
<a-form-item <a-form-item
:class="slotClass" :class="slotClass"
......
...@@ -71,4 +71,11 @@ export interface FormControlState extends MainControlState { ...@@ -71,4 +71,11 @@ export interface FormControlState extends MainControlState {
* @memberof FormControlState * @memberof FormControlState
*/ */
updateDefaultItems: IParam[]; updateDefaultItems: IParam[];
/**
* @description 锚点数据
* @type {IParam[]}
* @memberof FormControlState
*/
anchorDatas: IParam[];
} }
...@@ -46,6 +46,7 @@ export class FormControl extends MainControl { ...@@ -46,6 +46,7 @@ export class FormControl extends MainControl {
super.setState(); super.setState();
this.state.formSubject = new Subject(); this.state.formSubject = new Subject();
this.computeDrCount(); this.computeDrCount();
this.setAnchorDatas();
} }
/** /**
...@@ -64,6 +65,23 @@ export class FormControl extends MainControl { ...@@ -64,6 +65,23 @@ export class FormControl extends MainControl {
} }
} }
/**
* 设置锚点数据
*
* @memberof FormControl
*/
public setAnchorDatas() {
const { detailsModel } = this.state;
Object.values(detailsModel).forEach((item: IParam) => {
if (item.enableAnchor) {
this.state.anchorDatas.push({
caption: item.caption,
codeName: item.codeName
})
}
});
}
/** /**
* @description 检验表单动态逻辑 * @description 检验表单动态逻辑
* @param {IParam} data 表单数据 * @param {IParam} data 表单数据
......
.app-control { .app-control {
height: 100%; height: 100%;
width: 100%; width: 100%;
}
.app-form {
position: relative;
} }
\ No newline at end of file
// 部件样式汇总 // 部件样式汇总
@use './edit-form.scss';
@use './search-form.scss'; @use './search-form.scss';
@use './app-menu.scss'; @use './app-menu.scss';
@use './app-tree-exp-bar.scss'; @use './app-tree-exp-bar.scss';
......
...@@ -164,4 +164,6 @@ export const ctrlState = { ...@@ -164,4 +164,6 @@ export const ctrlState = {
], ],
{{/each}} {{/each}}
}, },
// 锚点数据集合
anchorDatas: [],
}; };
\ No newline at end of file
...@@ -54,6 +54,11 @@ defineExpose({ name, state, load, loadDraft, save, remove, refresh, getData }); ...@@ -54,6 +54,11 @@ defineExpose({ name, state, load, loadDraft, save, remove, refresh, getData });
:rules="state.rules" :rules="state.rules"
ref="xDataCtrl" ref="xDataCtrl"
> >
<AppAnchor
v-if="state.anchorDatas.length > 0"
:anchorDatas="state.anchorDatas"
:viewType="state.parent.state.viewType">
</AppAnchor>
{{#if ctrl.noTabHeader}} {{#if ctrl.noTabHeader}}
{{#each ctrl.psDEFormPages as | ctrlPage | }} {{#each ctrl.psDEFormPages as | ctrlPage | }}
{{#each ctrlPage.psDEFormDetails as | formDetail | }} {{#each ctrlPage.psDEFormDetails as | formDetail | }}
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册