@ -1,5 +1,5 @@ |
||||
import Vue from 'vue' |
||||
import SvgIcon from '@/components/SvgIcon' |
||||
import SvgIcon from '@/component/SvgIcon' |
||||
|
||||
Vue.component('svg-icon', SvgIcon) |
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 605 B After Width: | Height: | Size: 605 B |
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 944 B After Width: | Height: | Size: 944 B |
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 669 B After Width: | Height: | Size: 669 B |
|
Before Width: | Height: | Size: 335 B After Width: | Height: | Size: 335 B |
|
Before Width: | Height: | Size: 623 B After Width: | Height: | Size: 623 B |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 532 B After Width: | Height: | Size: 532 B |
|
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 440 B After Width: | Height: | Size: 440 B |
@ -0,0 +1,128 @@ |
||||
<template> |
||||
<div class="form-anchor"> |
||||
<div |
||||
v-for="i in data" |
||||
:key="i.ref" |
||||
:class="{'active':i.ref === cur}" |
||||
@click="() => click(i.ref)" |
||||
> |
||||
{{ i.label }} |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import {debounce} from "@/util" |
||||
import {getScroll, getOffsetTop, scrollTo} from "@/util/browser" |
||||
|
||||
export default { |
||||
name: "FormAnchor", |
||||
|
||||
props: { |
||||
reference: Function, |
||||
data: {type: Array, default: () => []}, |
||||
offsetTop: Number, |
||||
bounds: Number, |
||||
getContainer: { |
||||
type: Function, |
||||
default: () => document.querySelector('#app .app-main>.el-scrollbar>.el-scrollbar__wrap') |
||||
}, |
||||
}, |
||||
|
||||
data: () => ({cur: null}), |
||||
|
||||
methods: { |
||||
getCur(offsetTop = 0, bounds = 5) { |
||||
const sections = [] |
||||
const container = this.getContainer() |
||||
this.data.forEach(({ref}) => { |
||||
const target = this.getDomFromRef(ref) |
||||
const top = getOffsetTop(target, container) |
||||
if (top < offsetTop + bounds) { |
||||
sections.push({ref, top}) |
||||
} |
||||
}) |
||||
|
||||
if (sections.length) { |
||||
const max = sections.reduce((prev, curr) => (curr.top > prev.top ? curr : prev)) |
||||
return max.ref |
||||
} |
||||
return '' |
||||
}, |
||||
|
||||
getDomFromRef(ref) { |
||||
const refs = this.reference() |
||||
return refs[ref]['$el'] || refs[ref][0]['$el'] |
||||
}, |
||||
|
||||
click(ref) { |
||||
if (!ref || this.animating || !this.reference) return |
||||
this.cur = ref |
||||
const {offsetTop, getContainer, targetOffset} = this |
||||
const container = getContainer() |
||||
const scrollTop = getScroll(container, true) |
||||
const targetElement = this.getDomFromRef(ref) |
||||
if (!targetElement) return |
||||
const eleOffsetTop = getOffsetTop(targetElement, container) |
||||
let y = scrollTop + eleOffsetTop |
||||
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0 |
||||
this.animating = true |
||||
scrollTo(y, {callback: () => this.animating = false, getContainer}) |
||||
}, |
||||
|
||||
scroll() { |
||||
if (this.animating || !this.reference) return |
||||
const {offsetTop, bounds, targetOffset} = this |
||||
this.cur = this.getCur(targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds) |
||||
} |
||||
}, |
||||
|
||||
mounted() { |
||||
this.scroll() |
||||
|
||||
const container = this.getContainer() |
||||
this.handleScroll = debounce(this.scroll) |
||||
|
||||
container.addEventListener('scroll', this.handleScroll) |
||||
this.$once('hook:beforeDestroy', () => { |
||||
container.removeEventListener('scroll', this.handleScroll) |
||||
}) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
@import "~@/asset/style/variables.scss"; |
||||
|
||||
.form-anchor { |
||||
position: fixed; |
||||
right: 0; |
||||
top: 200px; |
||||
min-width: 72px; |
||||
overflow: hidden; |
||||
border-radius: 4px 0 0 4px; |
||||
background: #fff; |
||||
box-shadow: 0 2px 12px 0 rgba(166, 167, 173, 0.5); |
||||
z-index: 100; |
||||
|
||||
> div { |
||||
width: inherit; |
||||
height: 28px; |
||||
line-height: 28px; |
||||
text-align: center; |
||||
color: #7C7E85; |
||||
padding: 0 10px; |
||||
font-size: 12px; |
||||
cursor: pointer; |
||||
|
||||
&:hover, |
||||
&.active { |
||||
color: $--color-primary |
||||
} |
||||
|
||||
&:not(:last-child) { |
||||
box-shadow: 0 1px 0 0 rgba(166, 167, 173, 0.1); |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
@ -0,0 +1,129 @@ |
||||
<template> |
||||
<el-popover |
||||
ref="popover" |
||||
:disabled="error.length === 0" |
||||
placement="top" |
||||
width="256" |
||||
trigger="click" |
||||
popper-class="form-validate-info" |
||||
> |
||||
<div class="form-validate-info-title">表单校验信息</div> |
||||
<div class="form-validate-info-content"> |
||||
<div v-for="i in error" :key="i.prop" class="form-validate-info-item" @click="() => onClick(i)"> |
||||
<i class="el-icon-circle-close"/> |
||||
<div class="form-validate-info-item-msg">{{ i.msg }}</div> |
||||
<div class="form-validate-info-item-label">{{ i.label }}</div> |
||||
</div> |
||||
</div> |
||||
<template slot="reference"> |
||||
<span v-show="error.length > 0" class="form-validate-info-ref"> |
||||
<i class="el-icon-circle-close"/> |
||||
{{ error.length }} |
||||
</span> |
||||
</template> |
||||
</el-popover> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: "FormValidateInfo", |
||||
|
||||
props: {form: Function}, |
||||
|
||||
data() { |
||||
return { |
||||
visible: false, |
||||
error: [] |
||||
} |
||||
}, |
||||
|
||||
methods: { |
||||
onValidate(prop, success, msg) { |
||||
const alreadyIndex = this.error.findIndex(i => i.prop === prop) |
||||
if (alreadyIndex !== -1) { |
||||
if (success) this.error.splice(alreadyIndex, 1) |
||||
else this.$set(this.error, alreadyIndex, {...this.error[alreadyIndex], msg}) |
||||
} |
||||
else { |
||||
if (success) return |
||||
const formItem = this.findFormItem(prop) |
||||
this.error.push({prop, msg, label: formItem.label}) |
||||
} |
||||
}, |
||||
|
||||
onClick({prop}) { |
||||
const formItem = this.findFormItem(prop) |
||||
formItem && formItem.$el.scrollIntoView({block: 'center'}) |
||||
this.$refs.popover.doClose() |
||||
}, |
||||
|
||||
findFormItem(prop) { |
||||
return this.form().fields.find(i => i.prop === prop) |
||||
} |
||||
}, |
||||
|
||||
mounted() { |
||||
const form = this.form() |
||||
form.$on('validate', this.onValidate) |
||||
this.$once('hook:beforeDestroy', () => { |
||||
form.$off('validate', this.onValidate) |
||||
}) |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
@import "~@/asset/style/variables.scss"; |
||||
|
||||
.form-validate-info { |
||||
&.el-popper { |
||||
padding: 0; |
||||
} |
||||
|
||||
&-ref { |
||||
padding: 0 10px; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
&-title { |
||||
text-align: center; |
||||
padding: 5px 16px 4px; |
||||
border-bottom: 1px solid #f0f0f0; |
||||
} |
||||
|
||||
&-content { |
||||
max-height: 300px; |
||||
overflow: overlay; |
||||
} |
||||
|
||||
&-item { |
||||
padding: 8px 16px; |
||||
background-color: #fff; |
||||
border-bottom: 1px solid #f0f0f0; |
||||
cursor: pointer; |
||||
transition: background-color .3s; |
||||
|
||||
&:hover { |
||||
background-color: #e6f7ff; |
||||
} |
||||
|
||||
.el-icon-circle-close { |
||||
float: left; |
||||
margin-top: 4px; |
||||
margin-right: 12px; |
||||
padding-bottom: 22px; |
||||
} |
||||
|
||||
&-label { |
||||
margin-top: 2px; |
||||
color: rgba(0, 0, 0, .45); |
||||
font-size: 12px; |
||||
} |
||||
} |
||||
|
||||
&-ref, |
||||
&-item .el-icon-circle-close { |
||||
color: $--color-danger; |
||||
} |
||||
} |
||||
</style> |
||||
@ -1,5 +1,5 @@ |
||||
<script type="text/jsx"> |
||||
import Empty from "@/components/Empty" |
||||
import Empty from "@/component/Empty" |
||||
|
||||
export default { |
||||
name: "AbstractTable", |
||||
@ -1,5 +1,5 @@ |
||||
<script type="text/jsx"> |
||||
import LoadingMask from '@/components/LoadingMask' |
||||
import LoadingMask from '@/component/LoadingMask' |
||||
|
||||
export default { |
||||
name: "FormDialog", |
||||
@ -1,4 +1,4 @@ |
||||
@import "~@/assets/styles/variables.scss"; |
||||
@import "~@/asset/style/variables.scss"; |
||||
|
||||
.liner-progress { |
||||
position: relative; |
||||
@ -1,7 +1,7 @@ |
||||
<script type="text/jsx"> |
||||
import {store, init} from '../store' |
||||
import FormDialog from "@/components/FormDialog" |
||||
import {createLimitTree, getNodeId} from "@/utils/tree" |
||||
import FormDialog from "@/component/FormDialog" |
||||
import {createLimitTree, getNodeId} from "@/util/tree" |
||||
|
||||
export default { |
||||
components: {FormDialog}, |
||||
@ -1,5 +1,5 @@ |
||||
<script type="text/jsx"> |
||||
import {isExternal} from '@/utils/validate' |
||||
import {isExternal} from '@/util/validate' |
||||
|
||||
export default { |
||||
name: 'SvgIcon', |
||||
@ -1,4 +1,4 @@ |
||||
@import "~@/assets/styles/variables.scss"; |
||||
@import "~@/asset/style/variables.scss"; |
||||
|
||||
.disabled .el-upload--picture-card { |
||||
display: none; |
||||
@ -1,6 +1,6 @@ |
||||
import Vue from 'vue' |
||||
import Main from './main.vue' |
||||
import {mergeObj} from "@/utils" |
||||
import {mergeObj} from "@/util" |
||||
|
||||
const GuideConstructor = Vue.extend(Main) |
||||
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
|
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |