parent
f131de1dc4
commit
5e7590b474
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 286 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="wk-checkbox">
|
||||
<template v-if="valueIsObject">
|
||||
<el-select
|
||||
v-if="showType === 'default'"
|
||||
v-model="dataValue.select"
|
||||
:disabled="disabled"
|
||||
:clearable="clearable"
|
||||
:placeholder="placeholder"
|
||||
style="width: 100%;"
|
||||
multiple
|
||||
@change="valueChange">
|
||||
<el-option
|
||||
v-for="(item, index) in options"
|
||||
:key="index"
|
||||
:label="!isEmptyValue(item.value) ? item.label || item.name : item "
|
||||
:value="getValue(item)"/>
|
||||
</el-select>
|
||||
<el-checkbox-group
|
||||
v-else-if="showType === 'tiled'"
|
||||
v-model="dataValue.select"
|
||||
:disabled="disabled"
|
||||
@change="valueChange">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in options"
|
||||
:key="index"
|
||||
:label="getValue(item)">
|
||||
{{ !isEmptyValue(item.value) ? item.label || item.name : item }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-input
|
||||
v-if="dataValue.select.includes('其他')"
|
||||
v-model="dataValue.otherValue"
|
||||
:disabled="disabled"
|
||||
:maxlength="100"
|
||||
placeholder="其他选项需填写,否则为无效选项"
|
||||
@blur="inputBlur"/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isObject, isEmpty } from '@/utils/types'
|
||||
import { valueEquals } from 'element-ui/lib/utils/util'
|
||||
import Emitter from 'element-ui/lib/mixins/emitter'
|
||||
|
||||
export default {
|
||||
// 自定义字段库 多选
|
||||
name: 'WkCheckbox',
|
||||
|
||||
components: {},
|
||||
|
||||
mixins: [Emitter],
|
||||
|
||||
props: {
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
value: {},
|
||||
// 选择其他展示input输入框
|
||||
otherShowInput: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: Boolean,
|
||||
clearable: Boolean,
|
||||
placeholder: String,
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
showType: {
|
||||
type: String,
|
||||
default: 'default' // 下拉 default 平铺 tiled
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dataValue: {
|
||||
select: [],
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
valueIsObject() {
|
||||
return isObject(this.dataValue)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal, oldVal) {
|
||||
this.validValue()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 验证值
|
||||
*/
|
||||
validValue() {
|
||||
if (isEmpty(this.value)) {
|
||||
this.dataValue = {
|
||||
select: [],
|
||||
otherValue: ''
|
||||
}
|
||||
} else {
|
||||
if (this.otherShowInput) {
|
||||
const otherItem = this.value.filter((name) => !this.options.includes(name))
|
||||
if (otherItem.length > 0) {
|
||||
const newValue = this.value.filter((name) => !otherItem.includes(name))
|
||||
newValue.push('其他')
|
||||
this.dataValue = {
|
||||
select: newValue,
|
||||
otherValue: otherItem[otherItem.length - 1]
|
||||
}
|
||||
} else {
|
||||
if (!valueEquals(this.value, this.dataValue.select)) {
|
||||
this.dataValue = {
|
||||
select: this.value,
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.dataValue = {
|
||||
select: this.value,
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 选项值
|
||||
*/
|
||||
getValue(item) {
|
||||
return !this.isEmptyValue(item.value) ? item.value : item
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断是空值
|
||||
*/
|
||||
isEmptyValue(value) {
|
||||
return value === null || value == undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* 值更新
|
||||
*/
|
||||
valueChange() {
|
||||
if (this.dataValue.select.includes('其他')) {
|
||||
const newValue = this.dataValue.select.filter(item => item !== '其他')
|
||||
newValue.push(this.dataValue.otherValue.trim())
|
||||
this.$emit('input', newValue)
|
||||
this.$emit('change', newValue)
|
||||
this.dispatch('ElFormItem', 'el.form.change', newValue)
|
||||
} else {
|
||||
this.dataValue.otherValue = ''
|
||||
this.$emit('input', this.dataValue.select)
|
||||
this.$emit('change', this.dataValue.select)
|
||||
this.dispatch('ElFormItem', 'el.form.change', this.dataValue.select)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 失去焦点
|
||||
*/
|
||||
inputBlur() {
|
||||
this.valueChange()
|
||||
// const value = this.dataValue.otherValue
|
||||
// const eIsObject = this.options.length > 0 && !this.isEmptyValue(this.options[0].value)
|
||||
// const has = this.options.find(item => {
|
||||
// if (eIsObject) {
|
||||
// return item.value === value.trim()
|
||||
// } else {
|
||||
// return item === value.trim()
|
||||
// }
|
||||
// })
|
||||
// if (has) {
|
||||
// this.dataValue.otherValue = ''
|
||||
// }
|
||||
// this.$emit('change', this.dataValue.select)
|
||||
// this.$emit('input', this.dataValue.select)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-checkbox {
|
||||
.el-input {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.el-checkbox-group {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div class="wk-desc-text">
|
||||
<tinymce
|
||||
v-bind="$attrs"
|
||||
:disabled="true" :toolbar="[]" :init="{
|
||||
statusbar: false,
|
||||
placeholder: '描述文字内容',
|
||||
content_style: ' * {color: #262626; margin: 0;} body { font-size: 14px; }',
|
||||
quickbars_selection_toolbar: false,
|
||||
contextmenu: '',
|
||||
plugins: 'autoresize',
|
||||
autoresize_bottom_margin: 0
|
||||
}" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tinymce from '@/components/Tinymce'
|
||||
|
||||
export default {
|
||||
// 描述文字
|
||||
name: 'WkDescText',
|
||||
|
||||
components: {
|
||||
Tinymce
|
||||
},
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
props: {},
|
||||
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wk-desc-text {
|
||||
.tox-tinymce {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tox .tox-edit-area__iframe {
|
||||
background-color: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<el-table
|
||||
:data="fieldFrom"
|
||||
:row-key="Date.now().toString()"
|
||||
class="wk-table-items"
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
label="序号"
|
||||
width="50">
|
||||
<template slot-scope="{ row, column, $index }">
|
||||
{{ $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(item, index) in fieldList"
|
||||
v-if="getShowValue(item)"
|
||||
:key="index"
|
||||
:prop="item.field"
|
||||
:min-width="getMinWidth(item.formType)">
|
||||
<template
|
||||
slot="header"
|
||||
slot-scope="scope">
|
||||
<span v-if="item.isNull == 1" class="red">*</span>{{ item.name }}
|
||||
</template>
|
||||
<template slot-scope="{ row, column, $index }">
|
||||
<wk-form-item
|
||||
:prop-prefix="`${propPrefix || ''}[${$index}].`"
|
||||
:item="fieldList[index]"
|
||||
:index="$index"
|
||||
:field-from="fieldFrom[$index]"
|
||||
:disabled="disabled"
|
||||
@change="fieldChange"
|
||||
>
|
||||
<template slot-scope="{ data, index }">
|
||||
<slot :data="data" :index="$index" />
|
||||
</template>
|
||||
</wk-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:resizable="false"
|
||||
fixed="right"
|
||||
label="操作"
|
||||
width="60">
|
||||
<template slot-scope="{ row, column, $index }">
|
||||
<el-button
|
||||
icon="wk wk-icon-bin" type="text" @click="deleteClick($index)"/>
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
// table 风格展示事项
|
||||
name: 'WkTableItems',
|
||||
|
||||
components: {
|
||||
WkFormItem: () => import('../WkForm/WkFormItem')
|
||||
},
|
||||
|
||||
props: {
|
||||
// 表单验证前缀
|
||||
propPrefix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fieldFrom: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
fieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
deleteClick(index) {
|
||||
this.$emit('delete', index)
|
||||
},
|
||||
|
||||
getMinWidth(formType) {
|
||||
if (formType === 'date_interval' ||
|
||||
formType === 'dateRange' ||
|
||||
formType === 'file' ||
|
||||
formType === 'location' ||
|
||||
formType === 'position') {
|
||||
return 250
|
||||
}
|
||||
return 150
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断展示
|
||||
*/
|
||||
getShowValue(item) {
|
||||
if (item.hasOwnProperty('show')) {
|
||||
return item.show
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* 字段change
|
||||
*/
|
||||
fieldChange(item, index, value, valueList) {
|
||||
this.$emit('change', item, index, value, valueList)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wk-table-items {
|
||||
th {
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
.wk-form-item {
|
||||
padding: 8px 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
.el-form-item__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.red {
|
||||
color: #F56C6C;
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="wk-distpicker">
|
||||
<el-cascader
|
||||
v-bind="$attrs"
|
||||
v-model="dataValue"
|
||||
:options="options"
|
||||
:props="config"
|
||||
@change="handleChange"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DISTRICTS from '../../VDistpicker/districts'
|
||||
import { valueEquals } from 'element-ui/lib/utils/util'
|
||||
import { isObject } from '@/utils/types'
|
||||
|
||||
export default {
|
||||
// WkDistpicker
|
||||
name: 'WkDistpicker',
|
||||
|
||||
components: {},
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
props: {
|
||||
hideArea: { type: Boolean, default: false },
|
||||
onlyProvince: { type: Boolean, default: false },
|
||||
value: Array,
|
||||
props: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dataValue: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
options() {
|
||||
return this.getOptions()
|
||||
},
|
||||
|
||||
config() {
|
||||
const props = this.props || {}
|
||||
return {
|
||||
label: 'name',
|
||||
value: 'code',
|
||||
...props
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler() {
|
||||
this.validateValue()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
getOptions() {
|
||||
const list = DISTRICTS
|
||||
if (!this.onlyProvince && !this.hideArea) {
|
||||
return list
|
||||
}
|
||||
|
||||
const newList = []
|
||||
list.forEach(provinceItem => {
|
||||
const province = {
|
||||
code: provinceItem.code,
|
||||
name: provinceItem.name
|
||||
}
|
||||
if (!this.onlyProvince) {
|
||||
province.children = []
|
||||
provinceItem.children.forEach(cityItem => {
|
||||
const city = {
|
||||
code: cityItem.code,
|
||||
name: cityItem.name
|
||||
}
|
||||
province.children.push(city)
|
||||
if (!this.hideArea) {
|
||||
city.children = cityItem.children
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
newList.push(province)
|
||||
})
|
||||
|
||||
return newList
|
||||
},
|
||||
|
||||
validateValue() {
|
||||
if (this.value && this.value.length) {
|
||||
let dataValue = this.value
|
||||
if (isObject(this.value[0])) {
|
||||
dataValue = this.value.map(item => item[this.config.value])
|
||||
}
|
||||
if (!valueEquals(dataValue, this.dataValue)) {
|
||||
this.dataValue = dataValue
|
||||
}
|
||||
} else {
|
||||
this.dataValue = []
|
||||
}
|
||||
},
|
||||
|
||||
handleChange() {
|
||||
const objValue = this.getCascaderValArr(this.dataValue, this.options)
|
||||
this.$emit('input', objValue)
|
||||
this.$emit('change', objValue)
|
||||
},
|
||||
|
||||
getCascaderValArr(value, data) {
|
||||
const res = []
|
||||
if (value.length === 0) return res
|
||||
let index = 0
|
||||
do {
|
||||
const findRes = data.find(o => o.code === value[index])
|
||||
if (findRes) {
|
||||
data = findRes.children || []
|
||||
res.push({
|
||||
code: findRes.code,
|
||||
name: findRes.name,
|
||||
id: index + 1
|
||||
})
|
||||
}
|
||||
index++
|
||||
} while (index <= value.length)
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,322 @@
|
||||
<template>
|
||||
<div v-if="ignoreFields.includes(item.field)">
|
||||
<slot :data="item" :index="index" />
|
||||
</div>
|
||||
<el-input
|
||||
v-else-if="item.form_type == 'text'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:maxlength="100"
|
||||
:placeholder="item.placeholder"
|
||||
:type="item.form_type"
|
||||
@input="commonChange(item, index, $event)"/>
|
||||
<el-input
|
||||
v-else-if="isTrimInput(item.form_type)"
|
||||
v-model.trim="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:prefix-icon="getInputIcon(item.form_type)"
|
||||
:maxlength="getInputMaxlength(item.form_type)"
|
||||
:placeholder="item.placeholder"
|
||||
type="text"
|
||||
@input="commonChange(item, index, $event)"/>
|
||||
<el-input-number
|
||||
v-else-if="item.form_type == 'number'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:placeholder="item.placeholder"
|
||||
:disabled="item.disabled || disabled"
|
||||
:controls="false"
|
||||
@change="commonChange(item, index, $event)" />
|
||||
<el-input-number
|
||||
v-else-if="item.form_type == 'floatnumber'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:placeholder="item.placeholder"
|
||||
:disabled="item.disabled || disabled"
|
||||
:controls="false"
|
||||
@change="commonChange(item, index, $event)" />
|
||||
<wk-percent-input
|
||||
v-else-if="item.form_type == 'percent'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:placeholder="item.placeholder"
|
||||
:disabled="item.disabled || disabled"
|
||||
:controls="false"
|
||||
@change="commonChange(item, index, $event)" />
|
||||
<el-input
|
||||
v-else-if="item.form_type == 'textarea'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:rows="3"
|
||||
:autosize="{ minRows: 3}"
|
||||
:maxlength="item.maxlength || 800"
|
||||
:placeholder="item.placeholder"
|
||||
:type="item.form_type"
|
||||
resize="none"
|
||||
@input="commonChange(item, index, $event)" />
|
||||
<wk-select
|
||||
v-else-if="['select'].includes(item.form_type)"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:clearable="item.clearable"
|
||||
:placeholder="item.placeholder"
|
||||
:options="item.setting"
|
||||
:show-type="item.precisions === 1 ? 'tiled' : 'default'"
|
||||
:other-show-input="item.hasOwnProperty('optionsData')"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<wk-checkbox
|
||||
v-else-if="['checkbox'].includes(item.form_type)"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:clearable="item.clearable"
|
||||
:placeholder="item.placeholder"
|
||||
:options="item.setting"
|
||||
:show-type="item.precisions === 1 ? 'tiled' : 'default'"
|
||||
:other-show-input="item.hasOwnProperty('optionsData')"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<!-- <el-select
|
||||
v-else-if="['checkbox', 'select'].includes(item.form_type)"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:clearable="item.clearable"
|
||||
:placeholder="item.placeholder"
|
||||
:multiple="item.form_type === 'checkbox'"
|
||||
style="width: 100%;"
|
||||
@change="commonChange(item, index, $event)">
|
||||
<el-option
|
||||
v-for="(item, index) in item.setting"
|
||||
:key="index"
|
||||
:label="!isEmptyValue(item.value) ? item.label || item.name : item "
|
||||
:value="!isEmptyValue(item.value) ? item.value : item"/>
|
||||
</el-select> -->
|
||||
<!-- <el-select
|
||||
v-else-if="item.form_type == 'checkbox'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:clearable="item.clearable"
|
||||
:placeholder="item.placeholder"
|
||||
multiple
|
||||
style="width: 100%;"
|
||||
@change="commonChange(item, index, $event)">
|
||||
<el-option
|
||||
v-for="(item, index) in item.setting"
|
||||
:key="index"
|
||||
:label="!isEmptyValue(item.value) ? item.label || item.name : item "
|
||||
:value="!isEmptyValue(item.value) ? item.value : item"/>
|
||||
</el-select> -->
|
||||
<el-date-picker
|
||||
v-else-if="item.form_type == 'date'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
clearable
|
||||
style="width: 100%;"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="选择日期"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<el-date-picker
|
||||
v-else-if="item.form_type == 'dateRange'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:type="item.dateType || 'daterange'"
|
||||
:value-format="item.dateValueFormat || 'yyyy-MM-dd'"
|
||||
clearable
|
||||
style="width: 100%;vertical-align: middle;"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<el-date-picker
|
||||
v-else-if="item.form_type == 'datetime'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
clearable
|
||||
style="width: 100%;"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="选择日期"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<wk-dep-select
|
||||
v-else-if="item.form_type == 'structure'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:request="item.request"
|
||||
:props="item.props"
|
||||
:params="item.params"
|
||||
:disabled="item.disabled || disabled"
|
||||
:radio="!isEmptyValue(item.radio) ? item.radio : true"
|
||||
style="width: 100%;"
|
||||
@change="depOrUserChange(item, index, arguments[0], arguments[1])"
|
||||
/>
|
||||
<wk-user-select
|
||||
v-else-if="['single_user', 'user'].includes(item.form_type)"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:request="item.request"
|
||||
:props="item.props"
|
||||
:params="item.params"
|
||||
:disabled="item.disabled || disabled"
|
||||
:radio="!isEmptyValue(item.radio) ? item.radio : true"
|
||||
style="width: 100%;"
|
||||
@change="depOrUserChange(item, index, arguments[0], arguments[1])"
|
||||
/>
|
||||
<el-radio-group
|
||||
v-else-if="item.form_type == 'radio'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
:placeholder="item.placeholder"
|
||||
@change="commonChange(item, index, $event)">
|
||||
<el-radio
|
||||
v-for="(item, index) in item.setting"
|
||||
:key="index"
|
||||
:label="!isEmptyValue(item.value) ? item.value : item">
|
||||
{{ !isEmptyValue(item.value) ? item.label || item.name : item }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-switch
|
||||
v-else-if="item.form_type == 'boolean_value'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<wk-position
|
||||
v-else-if="item.form_type == 'position'"
|
||||
:hide-area="item.hideArea"
|
||||
:only-province="item.onlyProvince"
|
||||
:show-detail="item.showDetail"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<wk-location
|
||||
v-else-if="item.form_type == 'location'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<wk-signature-pad
|
||||
v-else-if="item.form_type == 'handwriting_sign'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"/>
|
||||
<wk-desc-text
|
||||
v-else-if="item.form_type == 'desc_text'"
|
||||
:value="fieldFrom[item.field]"/>
|
||||
<el-date-picker
|
||||
v-else-if="item.form_type === 'date_interval'"
|
||||
v-model="fieldFrom[item.field]"
|
||||
:type="item.dateType || 'daterange'"
|
||||
:value-format="item.dateValueFormat || 'yyyy-MM-dd'"
|
||||
:disabled="item.disabled || disabled"
|
||||
style="width: 100%;vertical-align: middle;"
|
||||
clearable
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="commonChange(item, index, $event)"/>
|
||||
<v-distpicker
|
||||
v-else-if="item.form_type == 'address'"
|
||||
:province="fieldFrom[item.field].province"
|
||||
:city="fieldFrom[item.field].city"
|
||||
:area="fieldFrom[item.field].area"
|
||||
@province="selectProvince($event, item, index)"
|
||||
@city="selectCity($event, item, index)"
|
||||
@area="selectArea($event, item, index)"/>
|
||||
<xh-files
|
||||
v-else-if="item.form_type == 'file'"
|
||||
:value="fieldFrom[item.field]"
|
||||
:disabled="item.disabled || disabled"
|
||||
@value-change="oldChange($event, item, index)"
|
||||
/>
|
||||
<wk-detail-table
|
||||
v-else-if="item.form_type == 'detail_table'"
|
||||
:show-type="item.precisions === 2 ? 'table' : 'default'"
|
||||
:title="item.name"
|
||||
:prop-prefix="item.field"
|
||||
:btn-name="item.remark"
|
||||
:add-field-list="item.fieldExtendList"
|
||||
:add-field-form="item.fieldForm"
|
||||
:field-form="fieldFrom[item.field]"
|
||||
:field-list="item.fieldList"
|
||||
:disabled="item.disabled || disabled"/>
|
||||
<div v-else>
|
||||
<slot :data="item" :index="index" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkUserSelect from '@/components/NewCom/WkUserSelect'
|
||||
import WkDepSelect from '@/components/NewCom/WkDepSelect'
|
||||
import WkPosition from '@/components/NewCom/WkPosition'
|
||||
import WkLocation from '@/components/NewCom/WkLocation'
|
||||
import WkSignaturePad from '@/components/NewCom/WkSignaturePad'
|
||||
import WkDescText from '@/components/NewCom/WkDescText'
|
||||
import WkPercentInput from '@/components/NewCom/WkPercentInput'
|
||||
import WkSelect from '@/components/NewCom/WkSelect'
|
||||
import WkCheckbox from '@/components/NewCom/WkCheckbox'
|
||||
import WkDetailTable from '@/components/NewCom/WkDetailTable'
|
||||
import VDistpicker from '@/components/VDistpicker'
|
||||
import { XhFiles } from '@/components/CreateCom'
|
||||
|
||||
import Mixin from './Mixin'
|
||||
|
||||
export default {
|
||||
// 字段
|
||||
name: 'WkField',
|
||||
|
||||
components: {
|
||||
WkUserSelect,
|
||||
WkDepSelect,
|
||||
WkPosition,
|
||||
WkLocation,
|
||||
WkSignaturePad,
|
||||
WkDescText,
|
||||
WkPercentInput,
|
||||
WkSelect,
|
||||
WkCheckbox,
|
||||
WkDetailTable,
|
||||
VDistpicker,
|
||||
XhFiles
|
||||
},
|
||||
|
||||
mixins: [Mixin],
|
||||
|
||||
props: {
|
||||
item: Object,
|
||||
index: Number,
|
||||
fieldFrom: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 忽略的字段直接输出
|
||||
ignoreFields: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-input-number {
|
||||
width: 100%;
|
||||
/deep/ .el-input__inner {
|
||||
text-align: left;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div
|
||||
:class="`is-${form_type}`"
|
||||
class="wk-field-view"
|
||||
>
|
||||
<template v-if="ignoreFields.includes(props.field)">
|
||||
<slot :data="$props" />
|
||||
</template>
|
||||
<span v-else-if="isCommonType">{{ getCommonShowValue() }}</span>
|
||||
<el-switch
|
||||
v-else-if="form_type == 'boolean_value'"
|
||||
:value="value"
|
||||
disabled
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
/>
|
||||
<wk-signature-image
|
||||
v-else-if="form_type == 'handwriting_sign'"
|
||||
:src=" !!value ? value.url:''"
|
||||
:height="config.signatureHeight"
|
||||
/>
|
||||
<wk-desc-text
|
||||
v-else-if="form_type == 'desc_text'"
|
||||
:key="Date.now().toString()"
|
||||
:value="value"
|
||||
/>
|
||||
<span
|
||||
v-else-if="form_type == 'location'"
|
||||
:class="{'can-check':objectHasValue(value, 'address')}"
|
||||
@click.stop="mapViewShow=true"
|
||||
>{{ objectHasValue(value, 'address') ? value.address : '--' }}</span>
|
||||
<span
|
||||
v-else-if="form_type == 'website'"
|
||||
:class="{'can-check': !isEmpty}"
|
||||
@click.stop="openUrl(value)"
|
||||
>{{ value }}</span>
|
||||
<file-list-view
|
||||
v-else-if="form_type == 'file'"
|
||||
:list="value || []"
|
||||
/>
|
||||
<wk-detail-table-view
|
||||
v-else-if="form_type == 'detail_table'"
|
||||
:show-type="props.precisions === 2 ? 'table' : 'default'"
|
||||
:title="props.name"
|
||||
:add-field-list="props.fieldExtendList"
|
||||
:field-form="value"
|
||||
:field-list="props.fieldList"
|
||||
>
|
||||
<template slot-scope="{ data }">
|
||||
<slot :data="data" />
|
||||
</template>
|
||||
</wk-detail-table-view>
|
||||
<template v-else>
|
||||
<slot :data="$props" />
|
||||
</template>
|
||||
|
||||
<map-view
|
||||
v-if="mapViewShow"
|
||||
:title="value.address"
|
||||
:lat="value.lat"
|
||||
:lng="value.lng"
|
||||
@hidden="mapViewShow=false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkSignatureImage from '@/components/NewCom/WkSignaturePad/Image'
|
||||
import WkDescText from '@/components/NewCom/WkDescText'
|
||||
import MapView from '@/components/MapView' // 地图详情
|
||||
import FileListView from '@/components/FileListView' // 附件
|
||||
import WkDetailTableView from '@/components/NewCom/WkDetailTable/View'
|
||||
|
||||
import merge from '@/utils/merge'
|
||||
import { isObject, isEmpty } from '@/utils/types'
|
||||
import { getFormFieldShowName } from './utils'
|
||||
|
||||
const DefaultWkFieldView = {
|
||||
signatureHeight: '26px'
|
||||
}
|
||||
|
||||
export default {
|
||||
// 特殊字段展示
|
||||
name: 'WkFieldView',
|
||||
|
||||
components: {
|
||||
WkSignatureImage,
|
||||
WkDescText,
|
||||
MapView,
|
||||
FileListView,
|
||||
WkDetailTableView
|
||||
},
|
||||
|
||||
props: {
|
||||
props: Object, // 自定义字段参数信息
|
||||
form_type: String,
|
||||
value: [String, Object, Array, Number],
|
||||
// 忽略的字段直接输出
|
||||
ignoreFields: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
// 控制展示地图详情
|
||||
mapViewShow: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
config() {
|
||||
return merge({ ...DefaultWkFieldView }, this.props || {})
|
||||
},
|
||||
isEmpty() {
|
||||
return isEmpty(this.value)
|
||||
},
|
||||
isCommonType() {
|
||||
return [
|
||||
'text',
|
||||
'textarea',
|
||||
'website',
|
||||
'select',
|
||||
'checkbox',
|
||||
'number',
|
||||
'floatnumber',
|
||||
'percent',
|
||||
'mobile',
|
||||
'email',
|
||||
'date',
|
||||
'datetime',
|
||||
'date_interval',
|
||||
'user',
|
||||
'structure',
|
||||
'position'
|
||||
].includes(this.form_type)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 判断对象是否值
|
||||
*/
|
||||
objectHasValue(obj, key) {
|
||||
if (isObject(obj)) {
|
||||
return !isEmpty(obj[key])
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
openUrl(url) {
|
||||
if (!url.match(/^https?:\/\//i)) {
|
||||
url = 'http://' + url
|
||||
}
|
||||
window.open(url)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取类型的展示值
|
||||
*/
|
||||
getCommonShowValue() {
|
||||
return getFormFieldShowName(this.form_type, this.value, '', this.props)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-field-view {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.can-check {
|
||||
color: $xr-color-primary;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.is-website {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<el-form-item
|
||||
v-if="getShowValue(item)"
|
||||
:key="index"
|
||||
:prop="`${propPrefix || ''}${item.field}`"
|
||||
:rules="item.rules"
|
||||
:class="[item.className || '', `is-${item.form_type}`]"
|
||||
:style="{width: item.style_percent ? `${item.style_percent}%` : 'auto'}"
|
||||
class="wk-form-item">
|
||||
<template slot="label">
|
||||
{{ item.name }}
|
||||
<el-tooltip
|
||||
v-if="item.tipType == 'tooltip'"
|
||||
effect="dark"
|
||||
placement="top">
|
||||
<div slot="content" v-html="getTips(item)"/>
|
||||
<i class="wk wk-help wk-help-tips"/>
|
||||
</el-tooltip>
|
||||
<span v-else style="color:#999;">
|
||||
{{ getTips(item) }}
|
||||
</span>
|
||||
</template>
|
||||
<wk-field
|
||||
:item="item"
|
||||
:index="index"
|
||||
:field-from="fieldFrom"
|
||||
:ignore-fields="ignoreFields"
|
||||
:disabled="disabled"
|
||||
@change="fieldChange"
|
||||
>
|
||||
<template slot-scope="{ data, index }">
|
||||
<slot :data="data" :index="index" />
|
||||
</template>
|
||||
</wk-field>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkField from './WkField'
|
||||
|
||||
import Mixin from './Mixin'
|
||||
|
||||
export default {
|
||||
// item
|
||||
name: 'WkFormItem',
|
||||
|
||||
components: {
|
||||
WkField
|
||||
},
|
||||
|
||||
mixins: [Mixin],
|
||||
|
||||
props: {
|
||||
// 表单验证前缀
|
||||
propPrefix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
item: Object,
|
||||
index: Number,
|
||||
fieldFrom: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 忽略的字段直接输出
|
||||
ignoreFields: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
fieldChange(item, index, value, valueList) {
|
||||
this.$emit('change', item, index, value, valueList)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wk-form-item {
|
||||
.el-form-item__label {
|
||||
line-height: 1.5;
|
||||
padding-bottom: 8px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.el-form-item__error {
|
||||
position: relative;
|
||||
top: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.el-form-item.is-desc_text {
|
||||
.el-form-item__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-form-item {
|
||||
padding: 12px 12px 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,62 @@
|
||||
import { isArray, isObject, isEmpty } from '@/utils/types'
|
||||
import CheckStatusMixin from '@/mixins/CheckStatusMixin'
|
||||
import CustomFieldsMixin from '@/mixins/CustomFields'
|
||||
import { separator } from '@/filters/vueNumeralFilter/filters'
|
||||
import { getWkDateTime } from '@/utils'
|
||||
|
||||
/**
|
||||
* 获取自定义字段展示值
|
||||
* @param {*} form_type
|
||||
* @param {*} value
|
||||
* @param {*} placeholder
|
||||
* @param {*} item 自定义字段模型
|
||||
* @returns 字符串
|
||||
*/
|
||||
export function getFormFieldShowName(form_type, value, placeholder = '--', item) {
|
||||
if (form_type === 'position') {
|
||||
return isArray(value) ? value.map(item => item.name).join() : placeholder
|
||||
} else if (form_type === 'floatnumber') {
|
||||
return isEmpty(value) ? '' : separator(value)
|
||||
} else if (form_type === 'date') {
|
||||
return getWkDateTime(value)
|
||||
} else if (form_type === 'location') {
|
||||
return isObject(value) ? value.address : placeholder
|
||||
} else if (form_type === 'date_interval') {
|
||||
return isArray(value) ? value.join('-') : placeholder
|
||||
} else if (form_type === 'percent') {
|
||||
return isEmpty(value) ? placeholder : `${value}%`
|
||||
} else if (form_type === 'single_user') {
|
||||
if (isObject(value)) {
|
||||
return value.realname || placeholder
|
||||
}
|
||||
return value || placeholder
|
||||
} else if (form_type === 'select') {
|
||||
const newValue = CustomFieldsMixin.methods.getRealParams({ form_type }, value)
|
||||
if (isEmpty(newValue)) {
|
||||
return placeholder
|
||||
} else {
|
||||
return newValue
|
||||
}
|
||||
} else if (form_type === 'checkbox') {
|
||||
const newValue = CustomFieldsMixin.methods.getRealParams({ form_type }, value)
|
||||
if (isEmpty(newValue)) {
|
||||
return placeholder
|
||||
} else {
|
||||
return newValue
|
||||
}
|
||||
} else if (form_type === 'structure') {
|
||||
if (isArray(value)) {
|
||||
return value.map(item => item.name).join() || placeholder
|
||||
}
|
||||
return value || placeholder
|
||||
} else if (form_type === 'user') {
|
||||
if (isArray(value)) {
|
||||
return value.map(item => item.realname).join() || placeholder
|
||||
}
|
||||
return value || placeholder
|
||||
} else if (form_type === 'check_status') {
|
||||
return CheckStatusMixin.methods.getStatusName(value)
|
||||
}
|
||||
|
||||
return isEmpty(value) ? placeholder : value
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div
|
||||
class="wk-location"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false">
|
||||
<el-input
|
||||
v-model="dataValue.address"
|
||||
:disabled="disabled"
|
||||
readonly
|
||||
clearable
|
||||
placeholder="点击定位"
|
||||
@click.native="inputClick"
|
||||
@clear="inputClear">
|
||||
<template slot="suffix">
|
||||
<i
|
||||
v-if="dataValue.address && hovering"
|
||||
class="el-icon-circle-close"
|
||||
style="cursor: pointer;"
|
||||
@click.stop="inputClear" />
|
||||
<i v-else class="wk wk-icon-location" />
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<wk-location-point-dialog
|
||||
:value="dataValue"
|
||||
:visible.sync="pointDialogVisible"
|
||||
@select="pointSelect"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkLocationPointDialog from '../WkLocationPointDialog'
|
||||
|
||||
import { isObject } from '@/utils/types'
|
||||
import { valueEquals } from 'element-ui/lib/utils/util'
|
||||
import Emitter from 'element-ui/lib/mixins/emitter'
|
||||
|
||||
export default {
|
||||
// 定位
|
||||
name: 'WkLocation',
|
||||
|
||||
components: {
|
||||
WkLocationPointDialog
|
||||
},
|
||||
|
||||
mixins: [Emitter],
|
||||
|
||||
props: {
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
value: {
|
||||
required: true
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
hovering: false,
|
||||
dataValue: this.getDefaultValue(),
|
||||
pointDialogVisible: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
if (!valueEquals(val, this.dataValue)) {
|
||||
if (isObject(this.value)) {
|
||||
this.dataValue = val
|
||||
} else {
|
||||
this.dataValue = this.getDefaultValue()
|
||||
this.$emit('input', this.dataValue)
|
||||
}
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
getDefaultValue() {
|
||||
return {
|
||||
lat: '',
|
||||
lng: '',
|
||||
address: ''
|
||||
}
|
||||
},
|
||||
|
||||
inputClick() {
|
||||
if (!this.disabled) {
|
||||
this.pointDialogVisible = true
|
||||
}
|
||||
},
|
||||
|
||||
inputClear() {
|
||||
this.dataValue = this.getDefaultValue()
|
||||
this.valueChange()
|
||||
},
|
||||
|
||||
pointSelect(data) {
|
||||
if (data) {
|
||||
this.dataValue = {
|
||||
lat: data.point.lat,
|
||||
lng: data.point.lng,
|
||||
address: data.address + data.title
|
||||
}
|
||||
}
|
||||
|
||||
this.valueChange()
|
||||
},
|
||||
|
||||
valueChange() {
|
||||
this.$emit('input', this.dataValue)
|
||||
this.$emit('change', this.dataValue)
|
||||
this.dispatch('ElFormItem', 'el.form.change', this.dataValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible="visible"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
title="选择位置"
|
||||
width="500px"
|
||||
@close="close">
|
||||
<flexbox align="stretch">
|
||||
<flexbox-item>
|
||||
<div class="area-title">定位</div>
|
||||
<el-autocomplete
|
||||
v-model="searchInput"
|
||||
:fetch-suggestions="querySearchAsync"
|
||||
style="width: 100%;"
|
||||
placeholder="请输入详细位置名称"
|
||||
@blur="inputBlur"
|
||||
@focus="inputFocus"
|
||||
@select="handleSelect">
|
||||
<template slot-scope="{ item }">
|
||||
<div class="name">{{ item.address + item.title }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<div
|
||||
ref="myMap"
|
||||
class="map"/>
|
||||
</flexbox-item>
|
||||
</flexbox>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="close">取 消</el-button>
|
||||
<el-button type="primary" @click="selectSure">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
import VDistpicker from '@/components/VDistpicker'
|
||||
import { getBaiduMap } from '@/utils'
|
||||
import { isEmpty } from '@/utils/types'
|
||||
|
||||
export default {
|
||||
name: 'WkLocationPointDialog',
|
||||
components: {
|
||||
VDistpicker
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
map: null,
|
||||
searchInput: '', // 搜索
|
||||
searchCopyInput: '', // 避免修改
|
||||
pointAddress: null // 经纬度点
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
getBaiduMap()
|
||||
.then(() => {
|
||||
const map = new BMap.Map(this.$refs.myMap, { enableMapClick: true })
|
||||
let point = new BMap.Point(116.404, 39.915)
|
||||
if (this.value) {
|
||||
if (!isEmpty(this.value.lat) && !isEmpty(this.value.lng)) {
|
||||
point = new BMap.Point(this.value.lng, this.value.lat)
|
||||
}
|
||||
|
||||
if (!isEmpty(this.value.address)) {
|
||||
this.searchInput = this.value.address
|
||||
this.searchCopyInput = this.searchInput
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.value || (
|
||||
this.value && isEmpty(this.value.lat) && isEmpty(this.value.lng) &&
|
||||
isEmpty(this.value.address)
|
||||
)) {
|
||||
const self = this
|
||||
// 定位逻辑
|
||||
var geolocation = new BMap.Geolocation()
|
||||
geolocation.getCurrentPosition(function(r) {
|
||||
if (this.getStatus() == BMAP_STATUS_SUCCESS) {
|
||||
var myGeo = new BMap.Geocoder({ extensions_town: true })
|
||||
// 根据坐标得到地址描述
|
||||
myGeo.getLocation(r.point, function(result) {
|
||||
if (result) {
|
||||
self.searchInput = result.address
|
||||
self.searchCopyInput = result.address
|
||||
self.addMarkerLabel(result.point)
|
||||
result.title = ''
|
||||
self.pointAddress = result
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
map.centerAndZoom(point, 14)
|
||||
map.enableScrollWheelZoom()
|
||||
this.map = map
|
||||
this.addMarkerLabel(point)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
querySearchAsync(queryString, cb) {
|
||||
if (queryString) {
|
||||
var options = {
|
||||
onSearchComplete: function(results) {
|
||||
if (local.getStatus() == BMAP_STATUS_SUCCESS) {
|
||||
var address = []
|
||||
for (var i = 0; i < results.getCurrentNumPois(); i++) {
|
||||
address.push(results.getPoi(i))
|
||||
}
|
||||
cb(address)
|
||||
} else {
|
||||
cb([])
|
||||
}
|
||||
},
|
||||
pageCapacity: 20
|
||||
}
|
||||
var local = new BMap.LocalSearch(this.map, options)
|
||||
local.search(queryString)
|
||||
} else {
|
||||
cb([])
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 搜索结果选择
|
||||
**/
|
||||
handleSelect(item) {
|
||||
this.searchInput = item.address + item.title
|
||||
this.searchCopyInput = this.searchInput // 只能通过这种方式修改
|
||||
|
||||
this.addMarkerLabel(item.point)
|
||||
this.pointAddress = item
|
||||
},
|
||||
/**
|
||||
* Input 失去焦点 searchInput 只能通过选择更改
|
||||
**/
|
||||
inputBlur() {
|
||||
if (this.searchCopyInput !== this.searchInput) {
|
||||
this.searchInput = this.searchCopyInput
|
||||
}
|
||||
},
|
||||
inputFocus() {
|
||||
this.searchCopyInput = this.searchInput
|
||||
},
|
||||
/**
|
||||
* 创建标注
|
||||
*/
|
||||
addMarkerLabel(point) {
|
||||
this.map.clearOverlays()
|
||||
this.map.centerAndZoom(point, 14)
|
||||
this.map.addOverlay(new BMap.Marker(point))
|
||||
},
|
||||
/**
|
||||
* 关闭
|
||||
*/
|
||||
close() {
|
||||
this.$emit('update:visible', false)
|
||||
},
|
||||
/**
|
||||
* 确定选择
|
||||
*/
|
||||
selectSure() {
|
||||
this.$emit('select', this.pointAddress)
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.map {
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.area-title {
|
||||
font-size: 12px;
|
||||
color: #aaa;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.distpicker-address-wrapper /deep/ select {
|
||||
height: 34px;
|
||||
font-size: 12px;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
/deep/ .el-dialog__body {
|
||||
padding: 10px 20px 20px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,281 @@
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
'el-input-number',
|
||||
inputNumberSize ? 'el-input-number--' + inputNumberSize : '',
|
||||
{ 'is-disabled': inputNumberDisabled },
|
||||
{ 'is-without-controls': !controls },
|
||||
{ 'is-controls-right': controlsAtRight }
|
||||
]"
|
||||
@dragstart.prevent>
|
||||
<span
|
||||
v-repeat-click="decrease"
|
||||
v-if="controls"
|
||||
:class="{'is-disabled': minDisabled}"
|
||||
class="el-input-number__decrease"
|
||||
role="button"
|
||||
@keydown.enter="decrease">
|
||||
<i :class="`el-icon-${controlsAtRight ? 'arrow-down' : 'minus'}`"/>
|
||||
</span>
|
||||
<span
|
||||
v-repeat-click="increase"
|
||||
v-if="controls"
|
||||
:class="{'is-disabled': maxDisabled}"
|
||||
class="el-input-number__increase"
|
||||
role="button"
|
||||
@keydown.enter="increase">
|
||||
<i :class="`el-icon-${controlsAtRight ? 'arrow-up' : 'plus'}`"/>
|
||||
</span>
|
||||
<el-input
|
||||
ref="input"
|
||||
:value="displayValue"
|
||||
:placeholder="placeholder"
|
||||
:disabled="inputNumberDisabled"
|
||||
:size="inputNumberSize"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:name="name"
|
||||
:label="label"
|
||||
@keydown.up.native.prevent="increase"
|
||||
@keydown.down.native.prevent="decrease"
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
@input="handleInput"
|
||||
@change="handleInputChange">
|
||||
<template slot="suffix">%</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Focus from 'element-ui/src/mixins/focus'
|
||||
import RepeatClick from 'element-ui/src/directives/repeat-click'
|
||||
|
||||
export default {
|
||||
name: 'WkPercentInput',
|
||||
directives: {
|
||||
RepeatClick
|
||||
},
|
||||
mixins: [Focus('input')],
|
||||
inject: {
|
||||
elForm: {
|
||||
default: ''
|
||||
},
|
||||
elFormItem: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
stepStrictly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: Infinity
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: -Infinity
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
value: {},
|
||||
disabled: Boolean,
|
||||
size: String,
|
||||
controls: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
controlsPosition: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
name: String,
|
||||
label: String,
|
||||
placeholder: String,
|
||||
precision: {
|
||||
type: Number,
|
||||
validator(val) {
|
||||
return val >= 0 && val === parseInt(val, 10)
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentValue: 0,
|
||||
userInput: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
minDisabled() {
|
||||
return this._decrease(this.value, this.step) < this.min
|
||||
},
|
||||
maxDisabled() {
|
||||
return this._increase(this.value, this.step) > this.max
|
||||
},
|
||||
numPrecision() {
|
||||
const { value, step, getPrecision, precision } = this
|
||||
const stepPrecision = getPrecision(step)
|
||||
if (precision !== undefined) {
|
||||
if (stepPrecision > precision) {
|
||||
console.warn('[Element Warn][InputNumber]precision should not be less than the decimal places of step')
|
||||
}
|
||||
return precision
|
||||
} else {
|
||||
return Math.max(getPrecision(value), stepPrecision)
|
||||
}
|
||||
},
|
||||
controlsAtRight() {
|
||||
return this.controls && this.controlsPosition === 'right'
|
||||
},
|
||||
_elFormItemSize() {
|
||||
return (this.elFormItem || {}).elFormItemSize
|
||||
},
|
||||
inputNumberSize() {
|
||||
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size
|
||||
},
|
||||
inputNumberDisabled() {
|
||||
return this.disabled || !!(this.elForm || {}).disabled
|
||||
},
|
||||
displayValue() {
|
||||
if (this.userInput !== null) {
|
||||
return this.userInput
|
||||
}
|
||||
|
||||
let currentValue = this.currentValue
|
||||
|
||||
if (typeof currentValue === 'number') {
|
||||
if (this.stepStrictly) {
|
||||
const stepPrecision = this.getPrecision(this.step)
|
||||
const precisionFactor = Math.pow(10, stepPrecision)
|
||||
currentValue = Math.round(currentValue / this.step) * precisionFactor * this.step / precisionFactor
|
||||
}
|
||||
|
||||
if (this.precision !== undefined) {
|
||||
currentValue = currentValue.toFixed(this.precision)
|
||||
}
|
||||
}
|
||||
|
||||
return currentValue
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(value) {
|
||||
let newVal = value === undefined ? value : Number(value)
|
||||
if (newVal !== undefined) {
|
||||
if (isNaN(newVal)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.stepStrictly) {
|
||||
const stepPrecision = this.getPrecision(this.step)
|
||||
const precisionFactor = Math.pow(10, stepPrecision)
|
||||
newVal = Math.round(newVal / this.step) * precisionFactor * this.step / precisionFactor
|
||||
}
|
||||
|
||||
if (this.precision !== undefined) {
|
||||
newVal = this.toPrecision(newVal, this.precision)
|
||||
}
|
||||
}
|
||||
if (newVal >= this.max) newVal = this.max
|
||||
if (newVal <= this.min) newVal = this.min
|
||||
this.currentValue = newVal
|
||||
this.userInput = null
|
||||
this.$emit('input', newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const innerInput = this.$refs.input.$refs.input
|
||||
innerInput.setAttribute('role', 'spinbutton')
|
||||
innerInput.setAttribute('aria-valuemax', this.max)
|
||||
innerInput.setAttribute('aria-valuemin', this.min)
|
||||
innerInput.setAttribute('aria-valuenow', this.currentValue)
|
||||
innerInput.setAttribute('aria-disabled', this.inputNumberDisabled)
|
||||
},
|
||||
updated() {
|
||||
if (!this.$refs || !this.$refs.input) return
|
||||
const innerInput = this.$refs.input.$refs.input
|
||||
innerInput.setAttribute('aria-valuenow', this.currentValue)
|
||||
},
|
||||
methods: {
|
||||
toPrecision(num, precision) {
|
||||
if (precision === undefined) precision = this.numPrecision
|
||||
return parseFloat(Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision))
|
||||
},
|
||||
getPrecision(value) {
|
||||
if (value === undefined) return 0
|
||||
const valueString = value.toString()
|
||||
const dotPosition = valueString.indexOf('.')
|
||||
let precision = 0
|
||||
if (dotPosition !== -1) {
|
||||
precision = valueString.length - dotPosition - 1
|
||||
}
|
||||
return precision
|
||||
},
|
||||
_increase(val, step) {
|
||||
if (typeof val !== 'number' && val !== undefined) return this.currentValue
|
||||
|
||||
const precisionFactor = Math.pow(10, this.numPrecision)
|
||||
// Solve the accuracy problem of JS decimal calculation by converting the value to integer.
|
||||
return this.toPrecision((precisionFactor * val + precisionFactor * step) / precisionFactor)
|
||||
},
|
||||
_decrease(val, step) {
|
||||
if (typeof val !== 'number' && val !== undefined) return this.currentValue
|
||||
|
||||
const precisionFactor = Math.pow(10, this.numPrecision)
|
||||
|
||||
return this.toPrecision((precisionFactor * val - precisionFactor * step) / precisionFactor)
|
||||
},
|
||||
increase() {
|
||||
if (this.inputNumberDisabled || this.maxDisabled) return
|
||||
const value = this.value || 0
|
||||
const newVal = this._increase(value, this.step)
|
||||
this.setCurrentValue(newVal)
|
||||
},
|
||||
decrease() {
|
||||
if (this.inputNumberDisabled || this.minDisabled) return
|
||||
const value = this.value || 0
|
||||
const newVal = this._decrease(value, this.step)
|
||||
this.setCurrentValue(newVal)
|
||||
},
|
||||
handleBlur(event) {
|
||||
this.$emit('blur', event)
|
||||
},
|
||||
handleFocus(event) {
|
||||
this.$emit('focus', event)
|
||||
},
|
||||
setCurrentValue(newVal) {
|
||||
const oldVal = this.currentValue
|
||||
if (typeof newVal === 'number' && this.precision !== undefined) {
|
||||
newVal = this.toPrecision(newVal, this.precision)
|
||||
}
|
||||
if (newVal >= this.max) newVal = this.max
|
||||
if (newVal <= this.min) newVal = this.min
|
||||
if (oldVal === newVal) return
|
||||
this.userInput = null
|
||||
this.$emit('input', newVal)
|
||||
this.$emit('change', newVal, oldVal)
|
||||
this.currentValue = newVal
|
||||
},
|
||||
handleInput(value) {
|
||||
this.userInput = value
|
||||
},
|
||||
handleInputChange(value) {
|
||||
const newVal = value === '' ? undefined : Number(value)
|
||||
if (!isNaN(newVal) || value === '') {
|
||||
this.setCurrentValue(newVal)
|
||||
}
|
||||
this.userInput = null
|
||||
},
|
||||
select() {
|
||||
this.$refs.input.select()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div class="wk-position">
|
||||
<wk-distpicker
|
||||
:hide-area="hideArea"
|
||||
:only-province="onlyProvince"
|
||||
:disabled="disabled"
|
||||
v-bind="$attrs"
|
||||
v-model="distpickerValue"
|
||||
clearable
|
||||
@change="valueChange"/>
|
||||
<el-input
|
||||
v-if="showDetail"
|
||||
:rows="2"
|
||||
:disabled="disabled"
|
||||
v-model="detailAddress"
|
||||
:maxlength="100"
|
||||
type="textarea"
|
||||
placeholder="详细地址"
|
||||
@change="valueChange"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkDistpicker from '../WkDistpicker'
|
||||
|
||||
import { isArray, isEmpty } from '@/utils/types'
|
||||
import Emitter from 'element-ui/lib/mixins/emitter'
|
||||
|
||||
export default {
|
||||
// 地址
|
||||
name: 'WkPosition',
|
||||
|
||||
components: {
|
||||
WkDistpicker
|
||||
},
|
||||
|
||||
mixins: [Emitter],
|
||||
|
||||
inheritAttrs: false,
|
||||
|
||||
props: {
|
||||
hideArea: { type: Boolean, default: false },
|
||||
onlyProvince: { type: Boolean, default: false },
|
||||
showDetail: { type: Boolean, default: true },
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
value: {
|
||||
required: true
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
distpickerValue: [],
|
||||
detailAddress: '',
|
||||
dataValue: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
if (!this.valueEquals(val, this.dataValue)) {
|
||||
this.getDefaultValue()
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
getDefaultValue() {
|
||||
const value = isArray(this.value) ? this.value : []
|
||||
|
||||
const distpickerValue = []
|
||||
let hasAddress = false
|
||||
value.forEach(item => {
|
||||
if (item.id === 4) {
|
||||
hasAddress = true
|
||||
this.detailAddress = item.name
|
||||
} else {
|
||||
distpickerValue.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
if (!hasAddress) {
|
||||
this.detailAddress = ''
|
||||
}
|
||||
|
||||
this.distpickerValue = distpickerValue
|
||||
},
|
||||
|
||||
/**
|
||||
* 值更新
|
||||
*/
|
||||
valueChange() {
|
||||
const dataValue = this.showDetail && isEmpty(this.detailAddress) ? this.distpickerValue : this.distpickerValue.concat([{
|
||||
code: '',
|
||||
name: this.detailAddress,
|
||||
id: 4
|
||||
}])
|
||||
this.dataValue = dataValue
|
||||
|
||||
this.$emit('input', this.dataValue)
|
||||
this.$emit('change', this.dataValue)
|
||||
this.dispatch('ElFormItem', 'el.form.change', this.dataValue)
|
||||
},
|
||||
|
||||
valueEquals(a, b) {
|
||||
if (a === b) return true
|
||||
if (!(a instanceof Array)) return false
|
||||
if (!(b instanceof Array)) return false
|
||||
if (a.length !== b.length) return false
|
||||
for (let i = 0; i !== a.length; ++i) {
|
||||
const aValue = a[i]
|
||||
const bValue = b[i]
|
||||
if (aValue.id !== bValue.id || aValue.name !== bValue.name) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-position {
|
||||
.el-textarea {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<div class="wk-select">
|
||||
<template v-if="valueIsObject">
|
||||
<el-select
|
||||
v-if="showType === 'default'"
|
||||
v-model="dataValue.select"
|
||||
:disabled="disabled"
|
||||
:clearable="clearable"
|
||||
:placeholder="placeholder"
|
||||
style="width: 100%;"
|
||||
@change="valueChange">
|
||||
<el-option
|
||||
v-for="(item, index) in options"
|
||||
:key="index"
|
||||
:label="!isEmptyValue(item.value) ? item.label || item.name : item "
|
||||
:value="getValue(item)"/>
|
||||
</el-select>
|
||||
<el-radio-group
|
||||
v-else-if="showType === 'tiled'"
|
||||
v-model="dataValue.select"
|
||||
@change="valueChange">
|
||||
<el-radio
|
||||
v-for="(item, index) in options"
|
||||
:key="index"
|
||||
:label="getValue(item)">
|
||||
{{ !isEmptyValue(item.value) ? item.label || item.name : item }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-input
|
||||
v-if="dataValue.select === '其他' && otherShowInput"
|
||||
v-model="dataValue.otherValue"
|
||||
:disabled="disabled"
|
||||
:maxlength="100"
|
||||
placeholder="其他选项需填写,否则为无效选项"
|
||||
@blur="inputBlur"/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isObject, isEmpty } from '@/utils/types'
|
||||
import Emitter from 'element-ui/lib/mixins/emitter'
|
||||
|
||||
export default {
|
||||
// 自定义字段库 单选
|
||||
name: 'WkSelect',
|
||||
|
||||
components: {},
|
||||
|
||||
mixins: [Emitter],
|
||||
|
||||
props: {
|
||||
value: [String, Number],
|
||||
// 选择其他展示input输入框
|
||||
otherShowInput: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
disabled: Boolean,
|
||||
clearable: Boolean,
|
||||
placeholder: String,
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
showType: {
|
||||
type: String,
|
||||
default: 'default' // 下拉 default 平铺 tiled
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dataValue: {
|
||||
select: '',
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
valueIsObject() {
|
||||
return isObject(this.dataValue)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler(newVal, oldVal) {
|
||||
this.validValue()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// this.validValue()
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 验证值
|
||||
*/
|
||||
validValue() {
|
||||
if (this.value !== this.dataValue.select && this.value !== this.dataValue.otherValue) {
|
||||
if (isEmpty(this.value)) {
|
||||
this.dataValue = {
|
||||
select: '',
|
||||
otherValue: ''
|
||||
}
|
||||
} else {
|
||||
if (this.otherShowInput) {
|
||||
const valueObj = this.options.find(item => this.getValue(item) === this.value)
|
||||
if (valueObj) {
|
||||
if (this.dataValue.select !== this.value) {
|
||||
this.dataValue = {
|
||||
select: this.value,
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.dataValue.otherValue !== this.value) {
|
||||
this.dataValue = {
|
||||
select: '其他',
|
||||
otherValue: this.value
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.dataValue = {
|
||||
select: this.value,
|
||||
otherValue: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 选项值
|
||||
*/
|
||||
getValue(item) {
|
||||
return !this.isEmptyValue(item.value) ? item.value : item
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断是空值
|
||||
*/
|
||||
isEmptyValue(value) {
|
||||
return value === null || value == undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* 值更新
|
||||
*/
|
||||
valueChange() {
|
||||
const value = this.dataValue.select === '其他' ? this.dataValue.otherValue.trim() : this.dataValue.select
|
||||
this.$emit('input', value)
|
||||
this.$emit('change', value)
|
||||
this.dispatch('ElFormItem', 'el.form.change', value)
|
||||
},
|
||||
|
||||
/**
|
||||
* 失去焦点
|
||||
*/
|
||||
inputBlur() {
|
||||
// 暂未加input触发change逻辑
|
||||
const value = this.dataValue.otherValue
|
||||
const eIsObject = this.options.length > 0 && !this.isEmptyValue(this.options[0].value)
|
||||
const has = this.options.find(item => {
|
||||
if (eIsObject) {
|
||||
return item.value === value.trim()
|
||||
} else {
|
||||
return item === value.trim()
|
||||
}
|
||||
})
|
||||
if (has) {
|
||||
this.dataValue.otherValue = ''
|
||||
}
|
||||
|
||||
this.$emit('input', this.dataValue.otherValue)
|
||||
this.$emit('change', this.dataValue.otherValue)
|
||||
this.dispatch('ElFormItem', 'el.form.change', this.dataValue.otherValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-select {
|
||||
.el-input {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.el-radio {
|
||||
margin: 5px 30px 5px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<el-popover
|
||||
:disabled="!hasContent"
|
||||
placement="bottom"
|
||||
width="200"
|
||||
trigger="hover">
|
||||
<el-image
|
||||
:src="url"
|
||||
:style="styleObj"
|
||||
style="width: 100%; height: 100%"
|
||||
fit="contain"/>
|
||||
<div slot="reference">
|
||||
<el-image
|
||||
v-if="hasContent"
|
||||
:src="url"
|
||||
:style="{height: height, ...styleObj}"
|
||||
style="width: 100%;"
|
||||
fit="contain"/>
|
||||
<template v-else>--</template>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { adminFileQueryOneByBatchIdAPI } from '@/api/admin/file'
|
||||
|
||||
export default {
|
||||
// WkSignatureImage
|
||||
name: 'WkSignatureImage',
|
||||
|
||||
components: {},
|
||||
|
||||
props: {
|
||||
height: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
src: String // batchId 交互
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
url: '',
|
||||
styleObj: {}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasContent() {
|
||||
return !!this.url
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
src(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.getData()
|
||||
} else {
|
||||
this.url = ''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.src) {
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
getData() {
|
||||
// adminFileQueryOneByBatchIdAPI(this.src).then(res => {
|
||||
// const resData = res.data
|
||||
// if (resData) {
|
||||
// const url = process.env.BASE_API + resData.url
|
||||
// if (this.url !== url) {
|
||||
// this.url = url
|
||||
// }
|
||||
// } else {
|
||||
// this.url = ''
|
||||
// }
|
||||
// }).catch(() => {
|
||||
|
||||
// })
|
||||
this.url = this.src
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
@ -0,0 +1,196 @@
|
||||
<script>
|
||||
import SignaturePad from 'signature_pad'
|
||||
// import mergeImages from 'merge-images'
|
||||
import {
|
||||
DEFAULT_OPTIONS,
|
||||
TRANSPARENT_PNG,
|
||||
IMAGE_TYPES,
|
||||
checkSaveType,
|
||||
convert2NonReactive
|
||||
} from '../utils/index'
|
||||
|
||||
export default {
|
||||
name: 'VueSignaturePad',
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '100%'
|
||||
},
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
images: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
signaturePad: {},
|
||||
cacheImages: [],
|
||||
signatureData: TRANSPARENT_PNG,
|
||||
onResizeHandler: null
|
||||
}),
|
||||
computed: {
|
||||
propsImagesAndCustomImages() {
|
||||
const nonReactiveProrpImages = convert2NonReactive(this.images)
|
||||
const nonReactiveCachImages = convert2NonReactive(this.cacheImages)
|
||||
return [...nonReactiveProrpImages, ...nonReactiveCachImages]
|
||||
},
|
||||
canvas() {
|
||||
return this.$refs.signaturePadCanvas
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: function(nextOptions) {
|
||||
Object.keys(nextOptions).forEach(option => {
|
||||
if (this.signaturePad[option]) {
|
||||
this.signaturePad[option] = nextOptions[option]
|
||||
}
|
||||
})
|
||||
},
|
||||
height() {
|
||||
this.resizeCanvas()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const { options } = this
|
||||
const canvas = this.$refs.signaturePadCanvas
|
||||
const signaturePad = new SignaturePad(canvas, {
|
||||
...DEFAULT_OPTIONS,
|
||||
...options
|
||||
})
|
||||
this.signaturePad = signaturePad
|
||||
this.onResizeHandler = this.resizeCanvas.bind(this)
|
||||
window.addEventListener('resize', this.onResizeHandler, false)
|
||||
this.resizeCanvas()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.onResizeHandler) {
|
||||
window.removeEventListener('resize', this.onResizeHandler, false)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resizeCanvas() {
|
||||
const canvas = this.$refs.signaturePadCanvas
|
||||
const data = this.signaturePad.toData()
|
||||
const ratio = Math.max(window.devicePixelRatio || 1, 1)
|
||||
canvas.width = canvas.offsetWidth * ratio
|
||||
canvas.height = canvas.offsetHeight * ratio
|
||||
canvas.getContext('2d').scale(ratio, ratio)
|
||||
this.signaturePad.clear()
|
||||
this.signatureData = TRANSPARENT_PNG
|
||||
this.signaturePad.fromData(data)
|
||||
},
|
||||
saveSignature(type = IMAGE_TYPES[0], encoderOptions) {
|
||||
const { signaturePad } = this
|
||||
const status = { isEmpty: false, data: undefined }
|
||||
if (!checkSaveType(type)) {
|
||||
const imageTypesString = IMAGE_TYPES.join(', ')
|
||||
throw new Error(
|
||||
`The Image type is incorrect! We are support ${imageTypesString} types.`
|
||||
)
|
||||
}
|
||||
if (signaturePad.isEmpty()) {
|
||||
return {
|
||||
...status,
|
||||
isEmpty: true
|
||||
}
|
||||
} else {
|
||||
this.signatureData = signaturePad.toDataURL(type, encoderOptions)
|
||||
return {
|
||||
...status,
|
||||
data: this.signatureData
|
||||
}
|
||||
}
|
||||
},
|
||||
undoSignature() {
|
||||
const { signaturePad } = this
|
||||
const record = signaturePad.toData()
|
||||
if (record) {
|
||||
return signaturePad.fromData(record.slice(0, -1))
|
||||
}
|
||||
},
|
||||
// mergeImageAndSignature(customSignature) {
|
||||
// this.signatureData = customSignature
|
||||
// return mergeImages([
|
||||
// ...this.images,
|
||||
// ...this.cacheImages,
|
||||
// this.signatureData
|
||||
// ])
|
||||
// },
|
||||
// addImages(images = []) {
|
||||
// this.cacheImages = [...this.cacheImages, ...images]
|
||||
// return mergeImages([
|
||||
// ...this.images,
|
||||
// ...this.cacheImages,
|
||||
// this.signatureData
|
||||
// ])
|
||||
// },
|
||||
fromDataURL(data, options = {}, callback) {
|
||||
return this.signaturePad.fromDataURL(data, options, callback)
|
||||
},
|
||||
fromData(data) {
|
||||
return this.signaturePad.fromData(data)
|
||||
},
|
||||
toData() {
|
||||
return this.signaturePad.toData()
|
||||
},
|
||||
lockSignaturePad() {
|
||||
return this.signaturePad.off()
|
||||
},
|
||||
openSignaturePad() {
|
||||
return this.signaturePad.on()
|
||||
},
|
||||
isEmpty() {
|
||||
return this.signaturePad.isEmpty()
|
||||
},
|
||||
getPropImagesAndCacheImages() {
|
||||
return this.propsImagesAndCustomImages
|
||||
},
|
||||
clearCacheImages() {
|
||||
this.cacheImages = []
|
||||
return this.cacheImages
|
||||
},
|
||||
clearSignature() {
|
||||
return this.signaturePad.clear()
|
||||
},
|
||||
toBlob(callback, type, encoderOptions) {
|
||||
this.$refs.signaturePadCanvas.toBlob(callback, type, encoderOptions)
|
||||
}
|
||||
},
|
||||
render(createElement) {
|
||||
const { width, height, customStyle } = this
|
||||
const urlObj = require('./signature.png')
|
||||
return createElement(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
width,
|
||||
height,
|
||||
...customStyle
|
||||
}
|
||||
},
|
||||
[
|
||||
createElement('canvas', {
|
||||
style: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
cursor: `url(${urlObj}),default`
|
||||
},
|
||||
ref: 'signaturePadCanvas'
|
||||
})
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
After Width: | Height: | Size: 394 B |
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div ref="wkSignaturePad" class="wk-signature-pad">
|
||||
<wk-signature-image
|
||||
v-if="disabled"
|
||||
:src="value.url"
|
||||
:height="height"
|
||||
/>
|
||||
<template v-else>
|
||||
<vue-signature-pad
|
||||
ref="signaturePad"
|
||||
:key="height"
|
||||
:options="options"
|
||||
:height="height"
|
||||
width="100%"
|
||||
/>
|
||||
<div class="wk-signature-pad__handle">
|
||||
<el-button type="text" icon="wk wk-icon-reply" @click="handleClick('undo')">撤回</el-button>
|
||||
<el-button type="text" icon="wk wk-icon-bin" @click="handleClick('clear')">清空</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { crmFileSingleSaveAPI } from '@/api/common'
|
||||
|
||||
import VueSignaturePad from './VueSignaturePad'
|
||||
import WkSignatureImage from './Image'
|
||||
|
||||
import { valueEquals } from 'element-ui/lib/utils/util'
|
||||
import { getImageData } from '@/utils'
|
||||
|
||||
|
||||
export default {
|
||||
// 签名
|
||||
name: 'WkSignaturePad',
|
||||
|
||||
components: {
|
||||
VueSignaturePad,
|
||||
WkSignatureImage
|
||||
},
|
||||
|
||||
props: {
|
||||
value: [Object, String], // batchId 交互
|
||||
data: String, // 同步数据源
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
backgroundColor: '#fff',
|
||||
onEnd: this.onEnd,
|
||||
minWidth: 1,
|
||||
maxWidth: 3
|
||||
},
|
||||
height: '150px'
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
},
|
||||
|
||||
watch: {
|
||||
data(newVal, oldVal) {
|
||||
if (!valueEquals(newVal, oldVal)) {
|
||||
this.$refs.signaturePad.fromDataURL(newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {
|
||||
if (this.value) {
|
||||
this.getData()
|
||||
} else {
|
||||
this.$emit('input', {})
|
||||
}
|
||||
|
||||
this.height = `${parseInt(this.$refs.wkSignaturePad.clientWidth / 2.6)}px`
|
||||
},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
getData() {
|
||||
getImageData(this.value.url)
|
||||
.then(data => {
|
||||
var img = new Image()
|
||||
img.onload = () => {
|
||||
const canvasWidth = this.$refs.signaturePad.canvas.width
|
||||
const width = img.width
|
||||
const ratio = canvasWidth / width
|
||||
console.log(width, canvasWidth, ratio)
|
||||
this.options.minWidth = this.options.minWidth * ratio
|
||||
this.options.maxWidth = this.options.maxWidth * ratio
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.signaturePad.fromDataURL(data.src)
|
||||
})
|
||||
}
|
||||
img.src = data.src
|
||||
})
|
||||
.catch(() => {
|
||||
})
|
||||
},
|
||||
|
||||
onEnd() {
|
||||
const { isEmpty, data } = this.$refs.signaturePad.saveSignature()
|
||||
this.$emit('update:data', data)
|
||||
if (!isEmpty) {
|
||||
this.$refs.signaturePad.toBlob((blob) => {
|
||||
this.uploadFile(blob)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
uploadFile(blob) {
|
||||
crmFileSingleSaveAPI({
|
||||
file: blob,
|
||||
batchId: this.value
|
||||
}).then((res) => {
|
||||
this.$emit('input', res.data)
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
handleClick(type) {
|
||||
if (type === 'clear') {
|
||||
this.$refs.signaturePad.clearSignature()
|
||||
} else if (type === 'undo') {
|
||||
this.$refs.signaturePad.undoSignature()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.el-form-item.is-error {
|
||||
.wk-signature-pad {
|
||||
border-color: #f56c6c;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wk-signature-pad {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #dcdfe6;
|
||||
overflow: hidden;
|
||||
|
||||
&__handle {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 0;
|
||||
.el-button--text {
|
||||
color: #999;
|
||||
&:hover {
|
||||
color: $xr-color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,26 @@
|
||||
export const IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/svg+xml']
|
||||
|
||||
export const checkSaveType = type => IMAGE_TYPES.includes(type)
|
||||
|
||||
export const DEFAULT_OPTIONS = {
|
||||
dotSize: (0.5 + 2.5) / 2,
|
||||
minWidth: 0.5,
|
||||
maxWidth: 2.5,
|
||||
throttle: 16,
|
||||
minDistance: 5,
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
penColor: 'black',
|
||||
velocityFilterWeight: 0.7,
|
||||
onBegin: () => {},
|
||||
onEnd: () => {}
|
||||
}
|
||||
|
||||
export const convert2NonReactive = observerValue =>
|
||||
JSON.parse(JSON.stringify(observerValue))
|
||||
|
||||
export const TRANSPARENT_PNG = {
|
||||
src:
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="wk-empty">
|
||||
<div class="wk-empty__title">{{ config.emptyText || '暂无数据' }}</div>
|
||||
<el-button
|
||||
v-if="config.showButton"
|
||||
:icon="config.buttonIcon"
|
||||
class="wk-empty__button xr-btn--orange"
|
||||
type="primary"
|
||||
@click="btnClick">{{ config.buttonTitle || '新建' }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import merge from '@/utils/merge'
|
||||
|
||||
const DefaultEmptyProps = {
|
||||
emptyText: '', // 是否搜索
|
||||
showButton: false,
|
||||
buttonIcon: 'el-icon-plus', // 员工列表请求
|
||||
buttonTitle: '' // 空参数
|
||||
}
|
||||
|
||||
export default {
|
||||
// 空数据
|
||||
name: 'WkEmpty',
|
||||
|
||||
components: {},
|
||||
|
||||
props: {
|
||||
props: Object
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
config() {
|
||||
return merge({ ...DefaultEmptyProps }, this.props || {})
|
||||
}
|
||||
},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
|
||||
methods: {
|
||||
btnClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wk-empty {
|
||||
color: #999;
|
||||
|
||||
&__button {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<div class="import-history">
|
||||
<div class="import-history__hd">
|
||||
<span class="import-history__title">查看历史导入记录</span>
|
||||
<span class="import-history__des">(错误数据只保存七天,七天后将自动失效)</span>
|
||||
|
||||
<el-button
|
||||
class="xr-icon-close-btn"
|
||||
icon="el-icon-close"
|
||||
@click="closeClick" />
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="tableList"
|
||||
class="import-history__bd"
|
||||
height="250"
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="导入时间"
|
||||
width="120">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.createTime | createTime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="realname"
|
||||
label="操作人"
|
||||
width="80"/>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="导入结果">
|
||||
<template slot-scope="scope">
|
||||
{{ `导入总数据${scope.row.title}条,${getImportContent(scope.row.title, scope.row.content)}` }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="option"
|
||||
width="150"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<template v-if="getErrorNum(scope.row.content) > 0">
|
||||
<el-button
|
||||
v-if="scope.row.valid == 1"
|
||||
type="text"
|
||||
@click="downloadError(scope.row.messageId)">下载错误数据</el-button>
|
||||
<span v-else-if="scope.row.valid == 0" class="invalid-tips">已失效</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="import-history__ft">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="closeClick">关闭</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { systemMessageListAPI } from '@/api/common'
|
||||
import {
|
||||
crmDownImportErrorAPI
|
||||
} from '@/api/crm/common'
|
||||
|
||||
import { downloadExcelWithResData } from '@/utils/index'
|
||||
|
||||
export default {
|
||||
// 导入历史
|
||||
name: 'CRMImportHistory',
|
||||
components: {},
|
||||
filters: {
|
||||
createTime(time) {
|
||||
const times = time.split(' ')
|
||||
return times.length > 0 ? times[0] : ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// CRM类型
|
||||
crmType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// moduleType
|
||||
props: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
tableList: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
watch: {
|
||||
show(value) {
|
||||
if (value) {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
systemMessageListAPI({
|
||||
page: 1,
|
||||
limit: 9999,
|
||||
type: {
|
||||
customer: 14,
|
||||
contacts: 16,
|
||||
leads: 18,
|
||||
product: 20,
|
||||
hrm: 50
|
||||
}[this.crmType] || this.props.moduleType
|
||||
})
|
||||
.then(res => {
|
||||
this.loading = false
|
||||
this.tableList = res.data.list
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 下载错误数据
|
||||
*/
|
||||
downloadError(messageId) {
|
||||
crmDownImportErrorAPI({ messageId })
|
||||
.then(res => {
|
||||
downloadExcelWithResData(res)
|
||||
})
|
||||
.catch(() => {
|
||||
})
|
||||
},
|
||||
|
||||
getImportContent(totalSize, content) {
|
||||
const list = content.split(',') || []
|
||||
const updateSize = Number(list[1] || '0')
|
||||
const errSize = Number(list[0] || '0')
|
||||
return `覆盖${updateSize}条,导入成功${totalSize - errSize}条,导入失败${errSize}条。`
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取错误数据数
|
||||
*/
|
||||
getErrorNum(content) {
|
||||
const list = content.split(',') || []
|
||||
const errSize = Number(list[0] || '0')
|
||||
return parseInt(errSize)
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭
|
||||
*/
|
||||
closeClick() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.import-history {
|
||||
&__hd {
|
||||
padding: 20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&__des {
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
&__bd {
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
&__ft {
|
||||
padding: 10px;
|
||||
background-color: #F7F8FA;
|
||||
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.xr-icon-close-btn {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.invalid-tips {
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,77 @@
|
||||
import { crmQueryImportNumAPI } from '@/api/crm/common'
|
||||
|
||||
import Lockr from 'lockr'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
showCRMImport: false,
|
||||
crmType: '',
|
||||
crmProps: null,
|
||||
crmImportStatus: '',
|
||||
cacheShow: false, // 缓存展示
|
||||
cacheDone: false, // 缓存导入是否完成
|
||||
|
||||
userInfo: null
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// 处理上次缓存
|
||||
const beforeImportInfo = Lockr.get('crmImportInfo')
|
||||
if (beforeImportInfo && beforeImportInfo.messageId) {
|
||||
this.crmType = beforeImportInfo.crmType
|
||||
this.crmProps = beforeImportInfo.crmProps
|
||||
this.lockrSecondQueryNum(beforeImportInfo.messageId)
|
||||
this.cacheShow = true
|
||||
} else {
|
||||
this.cacheShow = false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
// 1.导入框展示 2.导入状态状态为空或者是等待状态 缩小框不展示
|
||||
showFixImport() {
|
||||
return !this.showCRMImport && this.crmImportStatus && this.crmImportStatus != 'wait'
|
||||
}
|
||||
},
|
||||
|
||||
watch: {},
|
||||
|
||||
methods: {
|
||||
crmImportChange(status) {
|
||||
this.crmImportStatus = this.showCRMImport && status == 'finish' ? '' : status
|
||||
},
|
||||
|
||||
fixImportClick() {
|
||||
this.showCRMImport = true
|
||||
},
|
||||
|
||||
crmImportClose(status) {
|
||||
if (status == 'finish') {
|
||||
this.crmImportStatus = ''
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 第二步查询数量
|
||||
*/
|
||||
lockrSecondQueryNum(messageId) {
|
||||
crmQueryImportNumAPI({ messageId: messageId })
|
||||
.then(res => {
|
||||
if (res.data === null) { // 结束 否则 进行中
|
||||
this.crmImportStatus = 'finish'
|
||||
this.cacheDone = true
|
||||
} else {
|
||||
this.cacheDone = false
|
||||
this.crmImportStatus = 'process'
|
||||
}
|
||||
this.showCRMImport = false
|
||||
})
|
||||
.catch(() => {
|
||||
Lockr.rm('crmImportInfo')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<flexbox class="xr-import">
|
||||
<div
|
||||
v-loading="loading"
|
||||
v-if="loading"
|
||||
class="xr-import__icon" />
|
||||
<i
|
||||
v-else
|
||||
class="wk wk-success xr-import__icon" />
|
||||
<p
|
||||
:class="{ 'is-loading': loading }"
|
||||
class="xr-import__label">{{ processLabel }}</p>
|
||||
</flexbox>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
// 导入缩小框子
|
||||
name: 'XrImport',
|
||||
components: {},
|
||||
props: {
|
||||
// wait / process / finish / error / success
|
||||
processStatus: {
|
||||
type: String,
|
||||
default: 'wait'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
loading() {
|
||||
return this.processStatus == 'process'
|
||||
},
|
||||
|
||||
processLabel() {
|
||||
return this.loading ? '导入中' : '导入完成'
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
mounted() {},
|
||||
|
||||
beforeDestroy() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.xr-import {
|
||||
position: fixed;
|
||||
right: 50px;
|
||||
bottom: 150px;
|
||||
z-index: 999999;
|
||||
cursor: pointer;
|
||||
|
||||
width: 130px;
|
||||
height: 50px;
|
||||
padding: 10px;
|
||||
border-radius: 25px;
|
||||
background-color: white;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
&__icon {
|
||||
font-size: 30px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&__label.is-loading {
|
||||
margin-left: 35px;
|
||||
}
|
||||
|
||||
/deep/ .el-loading-spinner .circular {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
/deep/ .el-loading-spinner {
|
||||
margin-top: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
.wk-success {
|
||||
color: $xr-color-primary;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,15 @@
|
||||
import WkImportVue from './index.vue'
|
||||
|
||||
const WkImport = {}
|
||||
|
||||
WkImport.install = (Vue) => {
|
||||
const WkCRMImportConstructor = Vue.extend(WkImportVue)
|
||||
const instance = new WkCRMImportConstructor({
|
||||
el: document.createElement('div')
|
||||
})
|
||||
document.body.appendChild(instance.$el)
|
||||
|
||||
Vue.prototype.$wkImport = instance
|
||||
}
|
||||
|
||||
export default WkImport
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 351 KiB After Width: | Height: | Size: 427 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,30 @@
|
||||
.org-tree-company {
|
||||
color: #42526E;
|
||||
background-color: #ECEEF2;
|
||||
box-shadow: none !important;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.org-tree-department {
|
||||
color: #42526E;
|
||||
font-weight: 600;
|
||||
box-shadow: none !important;
|
||||
font-size: 12px;
|
||||
border: 2px solid #42526E;
|
||||
padding: 8px 15px !important;
|
||||
}
|
||||
|
||||
.org-tree-node-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.org-tree-node:not(:last-child):after,
|
||||
.org-tree-node:not(:first-child):before {
|
||||
border-top: 2px solid #42526E;
|
||||
}
|
||||
|
||||
.org-tree-node:after,
|
||||
.org-tree-node-children:before {
|
||||
border-left: 2px solid #42526E;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-boolean"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
<el-switch
|
||||
v-model="field.default_value"
|
||||
active-value="1"
|
||||
inactive-value="0" />
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldBoolean',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
font-size: 14px;
|
||||
padding: 10px 0;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-date-interval"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<flexbox class="range-box">
|
||||
<i class="el-icon-date icon" />
|
||||
<flexbox-item :class="{ placeholder: !Boolean(field.default_value) }">
|
||||
{{ field.default_value[0] || '开始时间' }}
|
||||
</flexbox-item>
|
||||
<span>至</span>
|
||||
<flexbox-item :class="{ placeholder: !Boolean(field.default_value) }">
|
||||
{{ field.default_value[1] || '结束时间' }}
|
||||
</flexbox-item>
|
||||
</flexbox>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldDateInterval',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.range-box {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
|
||||
.icon {
|
||||
color: #999;
|
||||
}
|
||||
.placeholder {
|
||||
flex: 1;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
hidden-title
|
||||
class="field-desc-text"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<tinymce
|
||||
:value="field.default_value"
|
||||
:disabled="true"
|
||||
:toolbar="[]"
|
||||
:init="{
|
||||
menubar: false,
|
||||
toolbar_sticky: true,
|
||||
statusbar: false,
|
||||
placeholder: '描述文字内容',
|
||||
quickbars_selection_toolbar: false,
|
||||
contextmenu: '',
|
||||
content_style: ' * {color: #262626; margin: 0;} body { font-size: 14px; }',
|
||||
plugins: 'autoresize',
|
||||
autoresize_bottom_margin: 0
|
||||
}"
|
||||
class="rich-txt" />
|
||||
<div class="field-desc-text-cover"/>
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import Tinymce from '@/components/Tinymce'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldDescText',
|
||||
components: {
|
||||
FieldWrapper,
|
||||
Tinymce
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.field-desc-text {
|
||||
.tox-tinymce {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tox .tox-edit-area__iframe {
|
||||
background-color: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
.field-desc-text {
|
||||
padding: 15px 10px;
|
||||
|
||||
&-cover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
.rich-txt {
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
border: 0 none;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-file"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<div class="box">
|
||||
请选择文件
|
||||
</div>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldFile',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
padding: 10px 0;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-input"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<flexbox align="center" class="box">
|
||||
<span class="default-val">
|
||||
{{ typeof field.default_value == 'string' ? field.default_value : '' }}
|
||||
</span>
|
||||
</flexbox>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldInput',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
background: white;
|
||||
padding: 0 10px;
|
||||
|
||||
.default-val {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-current-position"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<flexbox align="center" class="box">
|
||||
<flexbox-item class="default-val" />
|
||||
<span class="wk wk-icon-location" />
|
||||
</flexbox>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldCurrentPosition',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
background: white;
|
||||
padding: 0 10px;
|
||||
.wk-icon-location {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-percent"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<div class="box">
|
||||
<span class="default-val">{{ field.default_value || '' }}</span>
|
||||
<span class="rate">%</span>
|
||||
</div>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldPercent',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
background: white;
|
||||
padding: 0 30px 0 10px;
|
||||
|
||||
.rate {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-map-position"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<flexbox class="box-select">
|
||||
<div :class="{placeholder: !Boolean(areaText)}">
|
||||
{{ areaText || '请选择' }}
|
||||
</div>
|
||||
<i class="el-icon-arrow-down el-icon--right"/>
|
||||
</flexbox>
|
||||
<div
|
||||
v-if="field.precisions === 1"
|
||||
class="box-textarea">
|
||||
<div :class="{placeholder: !Boolean(detailAddress)}">
|
||||
{{ detailAddress || '详细地址' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
import { isEmpty } from '@/utils/types'
|
||||
|
||||
export default {
|
||||
name: 'FieldPosition',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
computed: {
|
||||
areaText() {
|
||||
if (isEmpty(this.field.default_value)) return ''
|
||||
return this.field.default_value
|
||||
.filter(o => o.id !== 4)
|
||||
.map(o => o.name)
|
||||
.join('/')
|
||||
},
|
||||
detailAddress() {
|
||||
if (isEmpty(this.field.default_value)) return ''
|
||||
const findRes = this.field.default_value.find(o => o.id === 4)
|
||||
if (!findRes) return ''
|
||||
return findRes.name
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.box-select {
|
||||
width: 100%;
|
||||
color: #333;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
padding: 10px;
|
||||
div {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.box-textarea {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-textarea"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<div class="box">
|
||||
<div class="default-val">
|
||||
{{ typeof field.default_value == 'string' ? field.default_value : '' }}
|
||||
</div>
|
||||
<div class="max-tips">
|
||||
{{ field.default_value.length+'/'+(field.max_length || 800) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldTextarea',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
background: white;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: $xr-border-radius-base;
|
||||
padding: 10px 10px 15px 10px;
|
||||
|
||||
.default-val {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
.max-tips {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<field-wrapper
|
||||
:activate="activate"
|
||||
:field="field"
|
||||
:control-flag="controlFlag"
|
||||
class="field-writing-sign"
|
||||
@click="emitClick"
|
||||
@action="handleAction">
|
||||
|
||||
<div class="box" />
|
||||
|
||||
</field-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FieldWrapper from './FieldWrapper'
|
||||
import mixins from './mixins'
|
||||
|
||||
export default {
|
||||
name: 'FieldWritingSign',
|
||||
components: {
|
||||
FieldWrapper
|
||||
},
|
||||
mixins: [mixins],
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
border: 1px solid #e1e1e1;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
padding: 10px 0;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,13 @@
|
||||
export { default as FieldInput } from './FieldInput'
|
||||
export { default as FieldTextarea } from './FieldTextarea'
|
||||
export { default as FieldSelect } from './FieldSelect'
|
||||
export { default as FieldCheckbox } from './FieldCheckbox'
|
||||
export { default as FieldFile } from './FieldFile'
|
||||
export { default as FieldBoolean } from './FieldBoolean'
|
||||
export { default as FieldPercent } from './FieldPercent'
|
||||
export { default as FieldPosition } from './FieldPosition'
|
||||
export { default as FieldLocation } from './FieldLocation'
|
||||
export { default as FieldDetailTable } from './FieldDetailTable'
|
||||
export { default as FieldWritingSign } from './FieldWritingSign'
|
||||
export { default as FieldDateInterval } from './FieldDateInterval'
|
||||
export { default as FieldDescText } from './FieldDescText'
|
@ -0,0 +1,132 @@
|
||||
import { getFieldAuth } from '../../utils'
|
||||
import { isEmpty } from '@/utils/types'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
field: { // 当前字段信息
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
fieldArr: { // 全部字段数组,为空时则禁止点击改变位置
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
point: { // 当前字段坐标
|
||||
type: Array
|
||||
},
|
||||
activePoint: { // 选中的字段坐标
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
specialFormType: [
|
||||
// 'detail_table' // 明细表格
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前字段是否激活
|
||||
activate() {
|
||||
return this.point[0] === this.activePoint[0] &&
|
||||
this.point[1] === this.activePoint[1]
|
||||
},
|
||||
/** 只读 */
|
||||
disabled() {
|
||||
return !this.fieldAuth.defaultEdit
|
||||
},
|
||||
|
||||
fieldAuth() {
|
||||
return getFieldAuth(this.field.operating)
|
||||
},
|
||||
// 向上操作按钮
|
||||
topFlag() {
|
||||
if (isEmpty(this.fieldArr)) return false
|
||||
// 第一行、上一行有4个、上一行为特殊字段类型不显示
|
||||
const row = this.point[0]
|
||||
if (row === 0) return false
|
||||
const prevRow = this.fieldArr[row - 1]
|
||||
if (prevRow.length === 4) return false
|
||||
if (this.specialFormType.includes(prevRow[0].form_type)) return false
|
||||
return true
|
||||
},
|
||||
// 向下操作按钮
|
||||
bottomFlag() {
|
||||
if (isEmpty(this.fieldArr)) return false
|
||||
// 最后一行、当前行只有一个不显示
|
||||
const row = this.point[0]
|
||||
if (row === this.fieldArr.length - 1) return false
|
||||
// if (this.fieldArr[row].length <= 1) return false
|
||||
return true
|
||||
},
|
||||
// 左侧操作按钮
|
||||
leftFlag() {
|
||||
if (isEmpty(this.fieldArr)) return false
|
||||
// 第一列不显示
|
||||
const column = this.point[1]
|
||||
if (column === 0) return false
|
||||
return true
|
||||
},
|
||||
// 右侧操作按钮
|
||||
rightFlag() {
|
||||
if (isEmpty(this.fieldArr)) return false
|
||||
// 最后一列不显示
|
||||
const column = this.point[1]
|
||||
const row = this.point[0]
|
||||
if (column === this.fieldArr[row].length - 1) return false
|
||||
return true
|
||||
},
|
||||
// 复制按钮
|
||||
copyFlag() {
|
||||
if (isEmpty(this.fieldArr)) return false
|
||||
return ![
|
||||
'customer',
|
||||
'business',
|
||||
'contacts',
|
||||
'contract',
|
||||
'receivables_plan',
|
||||
'single_user'
|
||||
].includes(this.field.form_type)
|
||||
},
|
||||
controlFlag() {
|
||||
return {
|
||||
top: this.topFlag,
|
||||
bottom: this.bottomFlag,
|
||||
left: this.leftFlag,
|
||||
right: this.rightFlag,
|
||||
delete: this.fieldAuth.deleteEdit,
|
||||
copy: this.copyFlag
|
||||
}
|
||||
}
|
||||
},
|
||||
// watch: {
|
||||
// field: {
|
||||
// handler() {
|
||||
// this.$nextTick(() => {
|
||||
// this.$forceUpdate()
|
||||
// })
|
||||
// },
|
||||
// deep: true,
|
||||
// immediate: true
|
||||
// }
|
||||
// },
|
||||
methods: {
|
||||
/**
|
||||
* click
|
||||
* @param evt
|
||||
*/
|
||||
emitClick(evt) {
|
||||
this.$emit('click', evt)
|
||||
},
|
||||
|
||||
/**
|
||||
* 点击删除
|
||||
* @param action
|
||||
* @param evt
|
||||
*/
|
||||
handleAction(action, evt) {
|
||||
this.$emit('action', action, this.point, evt)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,372 @@
|
||||
<template>
|
||||
<div class="setting-default">
|
||||
<el-input
|
||||
v-if="type === 'text'"
|
||||
v-model="field.default_value"
|
||||
:maxlength="field.max_length || 100"
|
||||
:disabled="disabled"
|
||||
@blur="inputBlur" />
|
||||
|
||||
<el-input
|
||||
v-else-if="type === 'textarea'"
|
||||
v-model="field.default_value"
|
||||
:maxlength="field.max_length || 800"
|
||||
:disabled="disabled"
|
||||
@blur="inputBlur" />
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="type === 'datePicker'"
|
||||
v-model="field.default_value"
|
||||
:disabled="disabled"
|
||||
:type="field.form_type === 'date' ? 'date' : 'datetime'"
|
||||
:value-format="field.form_type === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
|
||||
placeholder="请选择" />
|
||||
|
||||
<el-date-picker
|
||||
v-else-if="type === 'date_interval'"
|
||||
v-model="field.default_value"
|
||||
:type="field.precisions === 1 ? 'daterange' : 'datetimerange'"
|
||||
:value-format="field.precisions === 1 ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
|
||||
:disabled="disabled"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期" />
|
||||
|
||||
<el-select
|
||||
v-else-if="type === 'select'"
|
||||
v-model="field.default_value"
|
||||
:clearable="canClearable"
|
||||
:multiple="field.form_type === 'checkbox'"
|
||||
:disabled="disabled"
|
||||
placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
|
||||
<template v-else-if="type === 'number'">
|
||||
<el-input
|
||||
v-model="field.default_value"
|
||||
:disabled="disabled"
|
||||
@blur="inputBlur">
|
||||
<div
|
||||
v-if="field.form_type === 'percent'"
|
||||
slot="suffix"
|
||||
class="el-input__icon">%</div>
|
||||
</el-input>
|
||||
<div class="input-tips">
|
||||
<span>*</span>
|
||||
数字的位数必须少于{{ field.form_type === 'percent' ? 10 : 15 }}位
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="type === 'position'">
|
||||
<wk-distpicker
|
||||
v-model="selectedMapValue"
|
||||
:hide-area="field.precisions >= 3"
|
||||
:only-province="field.precisions === 4"
|
||||
:disabled="disabled"
|
||||
clearable
|
||||
@change="handleCascaderChange" />
|
||||
<el-input
|
||||
v-if="field.precisions === 1"
|
||||
v-model="detailAddress"
|
||||
:rows="3"
|
||||
:maxlength="100"
|
||||
:disabled="disabled"
|
||||
type="textarea"
|
||||
style="margin-top: 5px"
|
||||
@change="inputPositionChange" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WkDistpicker from '@/components/NewCom/WkDistpicker'
|
||||
|
||||
import { isEmpty, isArray } from '@/utils/types'
|
||||
import { regexIsCRMMobile, regexIsCRMEmail, objDeepCopy } from '@/utils'
|
||||
import { getFieldAuth } from '../../utils'
|
||||
|
||||
export default {
|
||||
name: 'SettingDefault',
|
||||
components: {
|
||||
WkDistpicker
|
||||
},
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedMapValue: [],
|
||||
detailAddress: '',
|
||||
oldPrecisions: null,
|
||||
|
||||
areaData: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 只读
|
||||
disabled() {
|
||||
return !getFieldAuth(this.field.operating).defaultEdit
|
||||
},
|
||||
// 是否允许清除默认选项
|
||||
canClearable() {
|
||||
const form_type = this.field.form_type
|
||||
if ([
|
||||
'boolean_value'
|
||||
].includes(form_type)) return false
|
||||
return true
|
||||
},
|
||||
// 类型
|
||||
type() {
|
||||
const form_type = this.field.form_type
|
||||
if ([
|
||||
'date',
|
||||
'datetime'
|
||||
].includes(form_type)) return 'datePicker'
|
||||
if ([
|
||||
'number',
|
||||
'floatnumber',
|
||||
'percent'
|
||||
].includes(form_type)) return 'number'
|
||||
if ([
|
||||
'select',
|
||||
'checkbox',
|
||||
'boolean_value'
|
||||
].includes(form_type)) return 'select'
|
||||
switch (this.field.form_type) {
|
||||
case 'date_interval':
|
||||
return 'date_interval'
|
||||
case 'position':
|
||||
return 'position'
|
||||
case 'textarea':
|
||||
return 'textarea'
|
||||
default:
|
||||
return 'text'
|
||||
}
|
||||
},
|
||||
// 选项
|
||||
options() {
|
||||
if (this.type !== 'select') return []
|
||||
const form_type = this.field.form_type
|
||||
if ([
|
||||
'select',
|
||||
'checkbox'
|
||||
].includes(form_type)) {
|
||||
return this.field.setting.map(o => {
|
||||
return { label: o, value: o }
|
||||
})
|
||||
}
|
||||
switch (form_type) {
|
||||
case 'boolean_value':
|
||||
return [
|
||||
{ label: '选中', value: '1' },
|
||||
{ label: '不选中', value: '0' }
|
||||
]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
field: {
|
||||
handler() {
|
||||
if (this.field.form_type === 'boolean_value') {
|
||||
// 布尔值
|
||||
this.field.default_value = isEmpty(this.field.default_value) ? '0' : this.field.default_value
|
||||
return
|
||||
}
|
||||
if (
|
||||
this.type === 'select' &&
|
||||
isEmpty(this.field.setting) &&
|
||||
!isEmpty(this.field.options)
|
||||
) {
|
||||
this.$set(this.field, 'setting', this.field.options.split(','))
|
||||
}
|
||||
if (this.type === 'position') {
|
||||
this.resetDefaultValue()
|
||||
// 地址默认值
|
||||
if (isEmpty(this.field.default_value)) {
|
||||
this.selectedMapValue = []
|
||||
if (!isArray(this.field.default_value)) {
|
||||
this.field.default_value = []
|
||||
}
|
||||
this.detailAddress = ''
|
||||
} else {
|
||||
this.selectedMapValue = this.field.default_value.filter(o => o.id !== 4)
|
||||
if (this.field.precisions === 1) {
|
||||
const findRes = this.field.default_value.find(o => o.id === 4)
|
||||
if (findRes) {
|
||||
this.detailAddress = findRes.name
|
||||
} else {
|
||||
this.detailAddress = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
inputBlur() {
|
||||
// this.$emit('input', this.value)
|
||||
if (!this.field.default_value) return
|
||||
if (this.field.form_type === 'mobile') {
|
||||
// 校验手机号
|
||||
if (!regexIsCRMMobile(this.field.default_value)) {
|
||||
this.$message.error('输入的手机格式有误')
|
||||
this.field.default_value = ''
|
||||
}
|
||||
} else if (this.field.form_type === 'email') {
|
||||
// 校验邮箱
|
||||
if (!regexIsCRMEmail(this.field.default_value)) {
|
||||
this.$message.error('输入的邮箱格式有误')
|
||||
this.field.default_value = ''
|
||||
}
|
||||
} else if (this.type === 'number') {
|
||||
// 校验数字类型
|
||||
const num = Number(this.field.default_value) // 去0
|
||||
if (isNaN(num)) {
|
||||
this.field.default_value = null
|
||||
return
|
||||
}
|
||||
this.field.default_value = String(num)
|
||||
const arr = String(num).split('.')
|
||||
|
||||
const len = String(num)
|
||||
.replace('.', '')
|
||||
.replace('-', '')
|
||||
.length
|
||||
const maxlength = this.field.form_type === 'percent' ? 10 : 15
|
||||
if (len > maxlength) {
|
||||
this.$message.error(`最多支持${maxlength}位数字(包含小数位)`)
|
||||
this.field.default_value = null
|
||||
return
|
||||
}
|
||||
|
||||
const min = isEmpty(this.field.minNumRestrict) ? -Infinity : Number(this.field.minNumRestrict || -Infinity)
|
||||
const max = isEmpty(this.field.maxNumRestrict) ? Infinity : Number(this.field.maxNumRestrict || Infinity)
|
||||
if (num < min) {
|
||||
this.$message.error('默认值不能小于最小值')
|
||||
this.field.default_value = null
|
||||
return
|
||||
}
|
||||
if (num > max) {
|
||||
this.$message.error('默认值不能大于最大值')
|
||||
this.field.default_value = null
|
||||
return
|
||||
}
|
||||
|
||||
// null 不支持小数 0 不限制小数位
|
||||
if (isEmpty(this.field.precisions)) {
|
||||
this.field.default_value = arr[0]
|
||||
return
|
||||
}
|
||||
if (this.field.precisions === 0) return
|
||||
if (arr.length > 1 && arr[1].length > Number(this.field.precisions)) {
|
||||
this.$message.error(`默认值的小数位不能大于${this.field.precisions}`)
|
||||
this.field.default_value = null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改精度重置默认值
|
||||
*/
|
||||
resetDefaultValue() {
|
||||
if (
|
||||
!this.oldPrecisions ||
|
||||
(this.oldPrecisions === this.field.precisions)
|
||||
) {
|
||||
this.oldPrecisions = this.field.precisions
|
||||
return
|
||||
}
|
||||
this.oldPrecisions = this.field.precisions
|
||||
this.selectedMapValue = []
|
||||
if (!isEmpty(this.field.default_value)) {
|
||||
this.field.default_value = []
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改详细地址
|
||||
*/
|
||||
inputPositionChange() {
|
||||
if (this.field.precisions !== 1) {
|
||||
const findIndex = this.field.default_value.findIndex(o => o.id === 4)
|
||||
if (findIndex === -1) return
|
||||
this.field.default_value.splice(findIndex, 1)
|
||||
} else {
|
||||
const findRes = this.field.default_value.find(o => o.id === 4)
|
||||
if (findRes) {
|
||||
findRes.name = this.detailAddress
|
||||
} else {
|
||||
this.field.default_value.push({
|
||||
code: '',
|
||||
name: this.detailAddress,
|
||||
id: 4
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择省市区
|
||||
*/
|
||||
handleCascaderChange() {
|
||||
this.field.default_value = this.selectedMapValue
|
||||
this.inputPositionChange()
|
||||
},
|
||||
|
||||
getCascaderValArr(data, value) {
|
||||
const res = []
|
||||
if (value.length === 0) return res
|
||||
let index = 0
|
||||
let _data = objDeepCopy(data)
|
||||
do {
|
||||
const findRes = _data.find(o => o.code === value[index])
|
||||
if (findRes) {
|
||||
_data = findRes.children || []
|
||||
res.push({
|
||||
code: findRes.code,
|
||||
name: findRes.name,
|
||||
id: index + 1
|
||||
})
|
||||
}
|
||||
index++
|
||||
} while (index <= value.length)
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
.el-input__icon {
|
||||
color: #333333;
|
||||
}
|
||||
.input-tips {
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
color: #999;
|
||||
span {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="setting-rich-text">
|
||||
<tinymce
|
||||
ref="createTinymce"
|
||||
v-model="field.default_value"
|
||||
:init="getEditConfig()"
|
||||
:height="200"
|
||||
toolbar="bold italic underline strikethrough | fontselect | forecolor backcolor | fontsizeselect | numlist bullist | alignleft aligncenter alignright | image link | removeformat"
|
||||
class="rich-txt"
|
||||
@input="debouncedEditorInput" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Tinymce from '@/components/Tinymce'
|
||||
import { debounce } from 'throttle-debounce'
|
||||
|
||||
export default {
|
||||
name: 'SettingRichText',
|
||||
components: {
|
||||
Tinymce
|
||||
},
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
debouncedEditorInput: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.debouncedEditorInput = debounce(300, this.editInputChange)
|
||||
},
|
||||
methods: {
|
||||
getEditConfig() {
|
||||
return {
|
||||
menubar: false,
|
||||
statusbar: false,
|
||||
paste_data_images: true, // 允许粘贴图片
|
||||
paste_enable_default_filters: false,
|
||||
placeholder: '描述文字内容',
|
||||
content_style: ' * {color: #262626; margin: 0;} body { margin: 8px; font-size: 14px; }',
|
||||
paste_retain_style_properties: 'border', // 粘贴内容时要保留的样式
|
||||
toolbar_mode: 'scrolling',
|
||||
paste_preprocess: function(plugin, args) {
|
||||
// 删除部分标签
|
||||
var delTag = ['b', 'strong', 'i', 'em']
|
||||
delTag.forEach(tag => {
|
||||
var reg = new RegExp(`(<${tag}>)|(</${tag}>)]`, 'g')
|
||||
args.content = args.content.replace(reg, '')
|
||||
})
|
||||
// 替换部分标签
|
||||
var replaceTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
|
||||
replaceTag.forEach(tag => {
|
||||
var reg1 = new RegExp(`<${tag}>`, 'g')
|
||||
var reg2 = new RegExp(`</${tag}>`, 'g')
|
||||
args.content = args.content.replace(reg1, '<p>')
|
||||
args.content = args.content.replace(reg2, '</p>')
|
||||
})
|
||||
// 删除所有font标签
|
||||
args.content = args.content.replace(/<\/font>/ig, '').replace(/<font[^>]+>/ig, '')
|
||||
console.log(args.content)
|
||||
},
|
||||
paste_postprocess: function(plugin, args) {
|
||||
var doms = Array.from(args.node.querySelectorAll('*'))
|
||||
// 删除字体样式
|
||||
doms.forEach(dom => {
|
||||
dom.style.color = ''
|
||||
dom.style.fontWeight = ''
|
||||
dom.style.fontFamily = ''
|
||||
dom.style.fontSize = ''
|
||||
dom.style.background = ''
|
||||
console.log(dom)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
editInputChange() {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<div class="setting-detail-table">
|
||||
<div class="item-section">
|
||||
<div class="name">表格字段</div>
|
||||
<draggable
|
||||
:list="field.fieldExtendList"
|
||||
:options="dragConfig"
|
||||
@sort="handleChange">
|
||||
<flexbox
|
||||
v-for="(item, index) in field.fieldExtendList"
|
||||
:key="index"
|
||||
align="center"
|
||||
justify="flex-start"
|
||||
class="option-item">
|
||||
<i
|
||||
:class="typeObj(item.form_type).icon"
|
||||
class="type-icon" />
|
||||
<div class="option-item__name">{{ item.name }}</div>
|
||||
<el-button
|
||||
type="text"
|
||||
class="option-item__icon wk wk-write"
|
||||
@click="handleEdit(index)" />
|
||||
<el-button
|
||||
type="text"
|
||||
class="option-item__icon wk wk-icon-bin"
|
||||
@click="handleDelete(index)" />
|
||||
<div class="option-item__icon drag-hook wk wk-grid" />
|
||||
</flexbox>
|
||||
</draggable>
|
||||
</div>
|
||||
|
||||
<div class="item-section">
|
||||
<div class="name">动作名</div>
|
||||
<div>
|
||||
<el-input v-model="field.remark" :maxlength="10" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-section">
|
||||
<div class="name">
|
||||
填写方式
|
||||
<el-tooltip
|
||||
content="选择明细的填写方式"
|
||||
effect="dark"
|
||||
popper-class="setting-number-tooltip"
|
||||
placement="top">
|
||||
<i class="wk wk-help wk-help-tips" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-radio-group v-model="field.precisions">
|
||||
<el-radio :label="1">列表</el-radio>
|
||||
<el-radio :label="2">表格</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
import { guid } from '@/utils'
|
||||
import FieldTypeLib from '../../fieldTypeLib'
|
||||
|
||||
export default {
|
||||
name: 'SettingDetailTable',
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragConfig: {
|
||||
group: guid(),
|
||||
forceFallback: false,
|
||||
fallbackClass: 'draggingStyle',
|
||||
handle: '.drag-hook',
|
||||
filter: '.el-input__inner',
|
||||
preventOnFilter: false
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
field: {
|
||||
handler() {
|
||||
if (!this.field.precisions) {
|
||||
this.$set(this.field, 'precisions', 1)
|
||||
}
|
||||
this.$set(this.field, 'precisions', this.field.precisions)
|
||||
this.$set(this.field, 'remark', this.field.remark)
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
typeObj(form_type) {
|
||||
return FieldTypeLib.find(o => o.form_type === form_type)
|
||||
},
|
||||
|
||||
handleChange() {
|
||||
this.$set(this.field, 'fieldExtendList', this.field.fieldExtendList)
|
||||
},
|
||||
|
||||
handleEdit(index) {
|
||||
this.$emit('child-edit', this.field.fieldExtendList[index])
|
||||
},
|
||||
|
||||
handleDelete(index) {
|
||||
this.field.fieldExtendList.splice(index, 1)
|
||||
this.$set(this.field, 'fieldExtendList', this.field.fieldExtendList)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.setting-detail-table {
|
||||
.item-section {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
.name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.option-item {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
border: 1px solid #e6e6e6;
|
||||
border-radius: 3px;
|
||||
padding: 0 8px;
|
||||
margin: 5px 0;
|
||||
|
||||
.drag-hook {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.option-item__name {
|
||||
width: 174px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.option-item__icon {
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div class="setting-number">
|
||||
<flexbox
|
||||
align="center"
|
||||
justify="flex-start"
|
||||
class="setting-number-item">
|
||||
<el-checkbox v-model="checked" @change="checkedChange" />
|
||||
<span style="font-size: 13px;">支持小数</span>
|
||||
<el-tooltip
|
||||
content="不选择只能输入整数,勾选后可规定小数位数"
|
||||
effect="dark"
|
||||
popper-class="setting-number-tooltip"
|
||||
placement="top">
|
||||
<i class="wk wk-help wk-help-tips" />
|
||||
</el-tooltip>
|
||||
<template v-if="checked">
|
||||
<span>限制 </span>
|
||||
<el-select
|
||||
v-model="field.precisions"
|
||||
size="small"
|
||||
placeholder=""
|
||||
@change="handleSelectChange">
|
||||
<el-option
|
||||
v-for="item in precisionList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
<span> 位</span>
|
||||
</template>
|
||||
</flexbox>
|
||||
<flexbox
|
||||
align="flex-start"
|
||||
justify="flex-start"
|
||||
direction="column"
|
||||
class="setting-number-item">
|
||||
<el-checkbox v-model="limitChecked" @change="limitChange">
|
||||
限制数值范围
|
||||
</el-checkbox>
|
||||
<flexbox
|
||||
v-if="limitChecked"
|
||||
align="center"
|
||||
justify="flex-start"
|
||||
class="number-range-body">
|
||||
<flexbox-item>
|
||||
<el-input-number
|
||||
v-model="minNumRestrict"
|
||||
:controls="false"
|
||||
placeholder="最小值"
|
||||
@change="handleChangeNumber('minNumRestrict')" />
|
||||
</flexbox-item>
|
||||
<div class="number-range-text">~</div>
|
||||
<flexbox-item>
|
||||
<el-input-number
|
||||
v-model="maxNumRestrict"
|
||||
:controls="false"
|
||||
placeholder="最大值"
|
||||
@change="handleChangeNumber('maxNumRestrict')" />
|
||||
</flexbox-item>
|
||||
</flexbox>
|
||||
</flexbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isEmpty } from '@/utils/types'
|
||||
|
||||
export default {
|
||||
name: 'SettingNumber',
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checked: false,
|
||||
precisionList: [],
|
||||
|
||||
limitChecked: false,
|
||||
minNumRestrict: undefined, // 定义为 undefined 防止input number自动填充0
|
||||
maxNumRestrict: undefined
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
field: {
|
||||
handler() {
|
||||
if ([
|
||||
'number',
|
||||
'floatnumber',
|
||||
'percent'
|
||||
].includes(this.field.form_type)) {
|
||||
if (!this.field.hasOwnProperty('minNumRestrict')) {
|
||||
this.field.minNumRestrict = null
|
||||
}
|
||||
if (!this.field.hasOwnProperty('maxNumRestrict')) {
|
||||
this.field.maxNumRestrict = null
|
||||
}
|
||||
this.minNumRestrict = isEmpty(this.field.minNumRestrict) ? undefined : Number(this.field.minNumRestrict)
|
||||
this.maxNumRestrict = isEmpty(this.field.maxNumRestrict) ? undefined : Number(this.field.maxNumRestrict)
|
||||
|
||||
// 小数位
|
||||
const max = this.field.form_type === 'percent' ? 5 : 14
|
||||
this.precisionList = Array.from({ length: max })
|
||||
.map((o, i) => {
|
||||
return { label: i + 1, value: i + 1 }
|
||||
})
|
||||
// if (this.field.form_type !== 'percent') {
|
||||
// this.precisionList.unshift({ label: '不限', value: 0 })
|
||||
// }
|
||||
if (!this.field.hasOwnProperty('precisions')) {
|
||||
this.field.precisions = this.field.form_type === 'number' ? 4 : 2
|
||||
}
|
||||
if (this.field.precisions > max) {
|
||||
// 不能大于最大值
|
||||
this.field.precisions = max
|
||||
}
|
||||
this.checked = !isEmpty(this.field.precisions)
|
||||
this.limitChecked = !isEmpty(this.minNumRestrict) || !isEmpty(this.maxNumRestrict)
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkedChange() {
|
||||
if (!this.checked) {
|
||||
this.field.precisions = null
|
||||
} else {
|
||||
this.field.precisions = 2
|
||||
}
|
||||
},
|
||||
handleSelectChange() {
|
||||
this.$set(this.field, 'precisions', this.field.precisions)
|
||||
this.$forceUpdate()
|
||||
},
|
||||
limitChange() {
|
||||
if (!this.limitChecked) {
|
||||
this.minNumRestrict = undefined
|
||||
this.maxNumRestrict = undefined
|
||||
|
||||
this.field.minNumRestrict = ''
|
||||
this.field.maxNumRestrict = ''
|
||||
}
|
||||
},
|
||||
handleChangeNumber(type) {
|
||||
const current = this[type]
|
||||
const len = String(current || '')
|
||||
.replace('.', '')
|
||||
.replace('-', '')
|
||||
.length
|
||||
|
||||
const maxlength = this.field.form_type === 'percent' ? 10 : 15
|
||||
if (len > maxlength) {
|
||||
this.$message.error(`最多支持${maxlength}位数字`)
|
||||
this.field[type] = null
|
||||
return
|
||||
}
|
||||
|
||||
const min = this.minNumRestrict
|
||||
const max = this.maxNumRestrict
|
||||
|
||||
if (!isEmpty(min) && !isEmpty(max)) {
|
||||
if (Number(min) > Number(max)) {
|
||||
this.$message.error('请输入正确的数值范围')
|
||||
this.field[type] = null
|
||||
}
|
||||
}
|
||||
const minNum = isEmpty(min) ? '' : min
|
||||
const maxNum = isEmpty(max) ? '' : max
|
||||
this.field.minNumRestrict = this.minNumRestrict !== null ? String(minNum) : null
|
||||
this.field.maxNumRestrict = this.maxNumRestrict !== null ? String(maxNum) : null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.setting-number-tooltip {
|
||||
max-width: 250px;
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
.setting-number-item {
|
||||
height: 32px;
|
||||
&:nth-child(2) {
|
||||
height: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.el-checkbox {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.el-tooltip {
|
||||
margin: 0 10px 0 5px;
|
||||
}
|
||||
.el-select {
|
||||
width: 70px;
|
||||
}
|
||||
.el-input-number {
|
||||
width: 100%;
|
||||
}
|
||||
.number-range-body {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.number-range-text {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="setting-precisions">
|
||||
<el-select
|
||||
:disabled="!optionsEditAuth"
|
||||
v-model="field.precisions"
|
||||
placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFieldAuth } from '../../utils'
|
||||
|
||||
export default {
|
||||
name: 'SettingPrecisions',
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 选项不能配置
|
||||
optionsEditAuth() {
|
||||
return getFieldAuth(this.field.operating).optionsEdit
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
field: {
|
||||
handler() {
|
||||
if (![
|
||||
'date_interval',
|
||||
'position',
|
||||
'select',
|
||||
'checkbox'
|
||||
].includes(this.field.form_type)) return
|
||||
if (this.field.form_type === 'date_interval') {
|
||||
this.options = [
|
||||
{ label: '日期', value: 1 },
|
||||
{ label: '日期时间', value: 2 }
|
||||
]
|
||||
} else if (this.field.form_type === 'position') {
|
||||
this.options = [
|
||||
{ label: '省/地区、市、区/县、详细地址', value: 1 },
|
||||
{ label: '省/地区、市、区/县', value: 2 },
|
||||
{ label: '省/地区、市', value: 3 },
|
||||
{ label: '省/地区', value: 4 }
|
||||
]
|
||||
} else {
|
||||
this.options = [
|
||||
{ label: '平铺', value: 1 },
|
||||
{ label: '下拉', value: 2 }
|
||||
]
|
||||
if (!this.field.precisions) {
|
||||
this.$set(this.field, 'precisions', this.field.form_type === 'checkbox' ? 1 : 2)
|
||||
}
|
||||
}
|
||||
if (!this.field.precisions) {
|
||||
this.$set(this.field, 'precisions', 1)
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<div
|
||||
v-clickoutside="clickOutSide"
|
||||
v-if="typeObj"
|
||||
class="field-setting">
|
||||
<div class="setting-title">
|
||||
{{ typeObj.name }}
|
||||
</div>
|
||||
|
||||
<div class="setting-body">
|
||||
<template v-if="!isDescText">
|
||||
<div class="item-section">
|
||||
<div class="name">标识名</div>
|
||||
<el-input
|
||||
v-model="field.name"
|
||||
:disabled="!fieldAuth.nameEdit"/>
|
||||
<div class="input-tips"><span>*</span>标识名不能为空</div>
|
||||
</div>
|
||||
|
||||
<div class="item-section">
|
||||
<div class="name">提示文字</div>
|
||||
<el-input
|
||||
v-model="field.input_tips"
|
||||
:rows="3"
|
||||
type="textarea"
|
||||
resize="none"/>
|
||||
<div class="input-tips"><span>*</span>显示在标识名右侧的说明文字</div>
|
||||
</div>
|
||||
|
||||
<setting-detail-table
|
||||
v-if="field.form_type === 'detail_table'"
|
||||
:field="field"
|
||||
@child-edit="emitChildEdit" />
|
||||
|
||||
<template v-if="canOptions">
|
||||
<div class="item-section">
|
||||
<div class="name">选项内容</div>
|
||||
<div class="input-tips"><span>*</span>修改选项后该项设置的逻辑表单会失效</div>
|
||||
<setting-options
|
||||
:field="field"
|
||||
:is-table-child="isTableChild" />
|
||||
</div>
|
||||
|
||||
<div v-if="!isTableChild" class="item-section">
|
||||
<div class="name">逻辑表单</div>
|
||||
<setting-logic-form
|
||||
:field="field"
|
||||
:point="point"
|
||||
:field-arr="fieldArr" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="canPrecisions" class="item-section">
|
||||
<div class="name">
|
||||
{{ precisionsTitle }}
|
||||
</div>
|
||||
<setting-precisions :field="field" />
|
||||
</div>
|
||||
|
||||
<div v-if="canDefault" class="item-section">
|
||||
<div class="name">默认值</div>
|
||||
<setting-default :field="field" />
|
||||
</div>
|
||||
|
||||
<div v-if="canNumber" class="item-section">
|
||||
<setting-number :field="field" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="isDescText" class="item-section">
|
||||
<div class="name">内容</div>
|
||||
<setting-desc-text :field="field" />
|
||||
</div>
|
||||
|
||||
<div v-if="fieldAuth.percentEdit" class="item-section">
|
||||
<div class="name">
|
||||
字段占比 %
|
||||
<el-tooltip
|
||||
content="配置表单布局,可以单行多字段排布"
|
||||
effect="dark"
|
||||
placement="top">
|
||||
<i class="wk wk-help wk-help-tips" style="margin-left: 3px;"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-radio-group
|
||||
v-model="field.style_percent"
|
||||
size="medium"
|
||||
@change="emitUpdateWidth">
|
||||
<el-radio-button
|
||||
v-for="item in widthOptions"
|
||||
:label="item.value"
|
||||
:key="item.value">{{ item.value }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div v-if="canTransform && transformData && transformData[field.form_type]" class="item-section">
|
||||
<div class="name">转化客户字段</div>
|
||||
<el-select
|
||||
v-model="field.relevant"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="item in transformData[field.form_type]"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<template v-if="!isDescText">
|
||||
<div
|
||||
v-if="fieldAuth.nullEdit"
|
||||
class="item-check-section">
|
||||
<el-checkbox
|
||||
v-model="field.is_null"
|
||||
:true-label="1"
|
||||
:false-label="0">设为必填</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="fieldAuth.uniqueEdit"
|
||||
class="item-check-section">
|
||||
<el-checkbox
|
||||
v-model="field.is_unique"
|
||||
:true-label="1"
|
||||
:false-label="0">设为唯一</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="fieldAuth.hiddenEdit"
|
||||
class="item-check-section">
|
||||
<el-checkbox
|
||||
v-model="field.is_hidden"
|
||||
:true-label="1"
|
||||
:false-label="0">隐藏字段</el-checkbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingDefault from './SettingDefault'
|
||||
import SettingOptions from './SettingOptions'
|
||||
import SettingNumber from './SettingNumber'
|
||||
import SettingPrecisions from './SettingPrecisions'
|
||||
import SettingDescText from './SettingDescText'
|
||||
import SettingDetailTable from './SettingDetailTable'
|
||||
import SettingLogicForm from './SettingLogicForm'
|
||||
|
||||
import FieldTypeLib from '../../fieldTypeLib'
|
||||
import { getFieldAuth } from '../../utils'
|
||||
|
||||
export default {
|
||||
name: 'FieldSetting',
|
||||
components: {
|
||||
SettingDefault,
|
||||
SettingOptions,
|
||||
SettingNumber,
|
||||
SettingPrecisions,
|
||||
SettingDescText,
|
||||
SettingDetailTable,
|
||||
SettingLogicForm
|
||||
},
|
||||
props: {
|
||||
// 是否开启转移 转移对应数据
|
||||
canTransform: Boolean,
|
||||
transformData: Object,
|
||||
field: { // 要编辑的字段信息
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
fieldArr: { // 所有字段
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
point: { // 被选中的字段坐标
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
widthOptions: [
|
||||
{ value: 25 },
|
||||
{ value: 50 },
|
||||
{ value: 75 },
|
||||
{ value: 100 }
|
||||
],
|
||||
stylePercentValue: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
typeObj() {
|
||||
const field = FieldTypeLib.find(o => o.form_type === this.field.form_type)
|
||||
return field || this.field
|
||||
},
|
||||
fieldAuth() {
|
||||
return getFieldAuth(this.field.operating)
|
||||
},
|
||||
// 是否允许设置字段默认值
|
||||
canDefault() {
|
||||
return ![
|
||||
'user',
|
||||
'structure',
|
||||
'file',
|
||||
'location',
|
||||
'handwriting_sign',
|
||||
'detail_table'
|
||||
].includes(this.field.form_type)
|
||||
},
|
||||
// 是否允许设置选项内容
|
||||
canOptions() {
|
||||
return [
|
||||
'select',
|
||||
'checkbox'
|
||||
].includes(this.field.form_type)
|
||||
},
|
||||
// 是否允许设置小数
|
||||
canNumber() {
|
||||
return [
|
||||
'number',
|
||||
'floatnumber',
|
||||
'percent'
|
||||
].includes(this.field.form_type)
|
||||
},
|
||||
// 精度
|
||||
canPrecisions() {
|
||||
return [
|
||||
'date_interval',
|
||||
'position',
|
||||
'select',
|
||||
'checkbox'
|
||||
].includes(this.field.form_type)
|
||||
},
|
||||
// 精度标题
|
||||
precisionsTitle() {
|
||||
if (!this.canPrecisions) return ''
|
||||
switch (this.field.form_type) {
|
||||
case 'date_interval':
|
||||
return '日期类型'
|
||||
case 'position':
|
||||
return '地址精度'
|
||||
case 'select':
|
||||
return '展示方式'
|
||||
case 'checkbox':
|
||||
return '展示方式'
|
||||
default:
|
||||
return '精度'
|
||||
}
|
||||
},
|
||||
// 是否为描述文字类型
|
||||
isDescText() {
|
||||
return this.field.form_type === 'desc_text'
|
||||
},
|
||||
|
||||
// 是否为明细表格内部字段
|
||||
isTableChild() {
|
||||
const fatherField = this.fieldArr[this.point[0]][this.point[1]]
|
||||
return fatherField.form_type === 'detail_table'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
field: {
|
||||
handler() {
|
||||
this.stylePercentValue = [Number(this.field.style_percent) || 100]
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
emitUpdateWidth() {
|
||||
this.$emit('update-width')
|
||||
},
|
||||
emitChildEdit(field = null) {
|
||||
this.$emit('child-edit', field)
|
||||
},
|
||||
clickOutSide() {
|
||||
this.emitChildEdit()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-checkbox /deep/ .el-checkbox__label {
|
||||
font-size: 13px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.field-setting {
|
||||
.setting-title {
|
||||
padding: 20px 15px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.setting-body {
|
||||
padding: 0 15px 10px;
|
||||
.input-tips {
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
color: #999;
|
||||
span {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.item-section {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
.name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.item-check-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,39 @@
|
||||
export default class Field {
|
||||
constructor(obj) {
|
||||
this.field_type = 0 // 新增字段默认加入0 1是系统字段 2 客户行业 级别 来源 等 3 特殊
|
||||
this.field_id = obj.field_id || '' // 字段id 1
|
||||
this.name = obj.name || '' // 标识名 1
|
||||
this.form_type = obj.form_type || '' // 字段类型 1
|
||||
this.is_unique = obj.is_unique || 0 // 是否唯一
|
||||
this.is_null = obj.is_null || 0 // 是否必填
|
||||
this.is_hidden = obj.is_hidden || 0 // 是否隐藏字段
|
||||
this.input_tips = obj.input_tips || '' // 输入提示
|
||||
if (this.form_type === 'textarea') {
|
||||
this.max_length = obj.max_length || 800 // textarea 多行文本有最大数量
|
||||
}
|
||||
|
||||
if (this.form_type === 'checkbox') {
|
||||
this.default_value = obj.default_value || []
|
||||
} else {
|
||||
this.default_value = obj.default_value || ''
|
||||
}
|
||||
|
||||
// 表格的特殊处理
|
||||
if (this.form_type === 'form') {
|
||||
this.formValue = obj.formValue || [] // 内部布局
|
||||
}
|
||||
|
||||
this.setting = obj.setting || [] // 单选选项
|
||||
// this.showSetting = obj.showSetting || [] // 单选选项
|
||||
// this.componentName = '' // 组件名字
|
||||
this.is_deleted = 0 // 是删除标示这个字段是无效的 1是无效的
|
||||
}
|
||||
|
||||
// 校验数据
|
||||
check() {
|
||||
if (this.name === '') {
|
||||
return '字段名称不能为空'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue