wkcrm_web/src/views/admin/crm/HandleField.vue

644 lines
18 KiB

<template>
<flexbox
:style="{'height': contentHeight + 'px'}"
class="main"
orient="vertical"
align="stretch">
<div class="title">{{ '编辑'+getTitle()+'字段' }}</div>
<el-container class="wrapper">
<el-aside class="left">
<div class="mini-title">字段库</div>
<ul>
<draggable
:list="fieldList"
:options="{group: {pull: 'clone', put: false, name: 'list'},forceFallback:true, sort:false }"
:clone="handleMove"
class="list-wrapper"
@end="handleEnd">
<li
v-for="item in fieldList"
:key="item.id"
class="field-item"
@click="handleClick(item)">
<img
:src="item.icon"
class="icon" >
<span>{{ item.name }}</span>
</li>
</draggable>
</ul>
</el-aside>
<el-container
v-loading="loading"
class="content">
<el-header>
<el-button
type="text"
style="padding: 8px 22px;border-radius:2px;"
@click="handlePreview">预览</el-button>
<el-button
v-debounce="handleSave"
type="primary"
style="padding: 8px 22px;border-radius:2px;">保存</el-button>
<el-button
style="padding: 8px 22px;border-radius:2px;"
@click="handleCancel">返回</el-button>
</el-header>
<el-main>
<draggable
:list="fieldArr"
:options="{group: 'list',forceFallback:true, fallbackClass:'draggingStyle'}"
@end="handleListMove">
<component
v-for="(item, index) in fieldArr"
:class="{selected: selectedIndex == index}"
:is-show="selectedIndex == index && (item.operating == null || item.operating == 0 || item.operating == 2)"
:key="index"
:attr="item"
:is="item | typeToComponentName"
@delete="handleDelete(item, index)"
@select="handleChildSelect"
@click.native="handleSelect(item, index)"/>
</draggable>
<p
v-if="fieldArr.length == 0"
class="no-list">从左侧点击或拖拽来添加字段</p>
</el-main>
</el-container>
<el-aside
class="right"
width="310px">
<div class="mini-title">字段属性</div>
<field-info
v-if="form"
:field="form"
:can-transform="canTransform"
:transform-data="transformData"
:can-unique="canUnique"/>
</el-aside>
</el-container>
<!-- 表单预览 -->
<preview-field-view
v-if="showTablePreview"
:types="tablePreviewData.type"
:types-id="tablePreviewData.id"
:label="tablePreviewData.label"
@hiden-view="showTablePreview=false"/>
</flexbox>
</template>
<script>
import crmTypeModel from '@/views/crm/model/crmTypeModel'
import {
customFieldHandleAPI,
oaFieldHandleAPI,
customFieldListAPI,
oaExamineFieldListAPI
} from '@/api/admin/crm'
import { filedGetFieldAPI } from '@/api/crm/common'
import PreviewFieldView from '@/views/admin/components/PreviewFieldView'
import {
SingleLineText,
MultiLineText,
SelectForm,
CheckboxForm,
FileForm,
TableForm
} from './components/Fields'
import draggable from 'vuedraggable'
import Field from './model/field'
import FieldList from './model/fieldList'
import FieldInfo from './components/FieldInfo'
import { objDeepCopy, regexIsCRMMobile, regexIsCRMEmail } from '@/utils'
export default {
name: 'Handlefield',
components: {
SingleLineText,
MultiLineText,
SelectForm,
CheckboxForm,
FileForm,
TableForm,
draggable,
FieldInfo,
PreviewFieldView
},
filters: {
/** 根据type 找到组件 */
typeToComponentName(item) {
if (
item.form_type === 'text' ||
item.form_type === 'number' ||
item.form_type === 'floatnumber' ||
item.form_type === 'mobile' ||
item.form_type === 'email' ||
item.form_type === 'date' ||
item.form_type === 'datetime' ||
item.form_type === 'user' ||
item.form_type === 'structure' ||
item.form_type === 'contacts' ||
item.form_type === 'customer' ||
item.form_type === 'contract' ||
item.form_type === 'business' ||
item.form_type === 'single_user'
) {
return 'SingleLineText'
} else if (item.form_type === 'textarea') {
return 'MultiLineText'
} else if (item.form_type === 'select') {
return 'SelectForm'
} else if (item.form_type === 'checkbox') {
return 'CheckboxForm'
} else if (item.form_type === 'file') {
return 'FileForm'
} else if (item.form_type === 'form') {
return 'TableForm'
}
}
},
data() {
return {
fieldList: FieldList,
fieldArr: [], // 数据没有返回时 根据null 判断不能操作
movedItem: {},
selectedIndex: -1,
rejectHandle: true, // 请求未获取前不能操作
/** 右边展示数据 */
form: null, // operating 0 改删 1改 2删 3无
loading: false, // 加载动画
// 展示表单预览
tablePreviewData: { types: '', id: '' },
showTablePreview: false,
contentHeight: document.documentElement.clientHeight - 75,
// 转移匹配字段源
transformData: null
}
},
computed: {
// 能转移
canTransform() {
return this.$route.params.type == 'crm_leads'
},
canUnique() {
return this.$route.params.type != 'oa_examine' // 办公审批不允许设置唯一
}
},
watch: {
selectedIndex: {
handler(newVal) {
if (newVal >= 0) {
this.form = this.fieldArr[newVal]
} else {
this.form = null
}
},
deep: true,
immediate: true
}
},
mounted() {
window.onresize = () => {
this.contentHeight = document.documentElement.clientHeight - 75
}
// 获取当前模块的自定义数据
this.getCustomInfo()
// 配置转移字段
if (this.canTransform) {
this.getTransformField()
}
},
methods: {
// 获取当前模块的自定义数据
getCustomInfo() {
this.loading = true
let request = customFieldListAPI
var params = {}
// params.label = this.$route.params.label
params.types = this.$route.params.type
if (this.$route.params.type === 'oa_examine') {
request = oaExamineFieldListAPI
params.types_id = this.$route.params.id
}
request(params)
.then(res => {
for (let index = 0; index < res.data.length; index++) {
const element = res.data[index]
if (
element.form_type == 'select' ||
element.form_type == 'checkbox'
) {
var temps = []
for (let i = 0; i < element.setting.length; i++) {
// 必须有属性 才能for绑定 所以处理了下数据
const item = element.setting[i]
temps.push({ value: item })
}
element.showSetting = temps // 放到showSeeting上
// 删除无效的多选默认值
if (element.form_type == 'checkbox') {
element.default_value = element.default_value.filter(item => {
return element.setting.indexOf(item) != -1
})
}
}
element.is_null = element.is_null == 1
element.is_unique = element.is_unique == 1
element.is_hidden = element.is_hidden == 1 // 隐藏字段
element.default_value = element.default_value
element.max_length = element.max_length
element.input_tips = element.input_tips
element.types_id = element.types_id
// element.is_null = element.is_null == 1
}
this.fieldArr = res.data
if (res.data.length > 0) {
this.selectedIndex = 0
this.form = this.fieldArr[0]
}
this.rejectHandle = false
this.loading = false
})
.catch(() => {
this.loading = false
})
},
// 删除一行自定义数据
handleDelete(item, index) {
this.$confirm('确定删除该自定义字段吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
this.fieldArr.splice(index, 1)
this.$nextTick(() => {
this.selectedIndex = -1
})
})
.catch(() => {})
},
// 主列表的选择
handleSelect(item, index) {
this.selectedIndex = index
if (this.selectedIndex === index) {
// 表自定义字段的刷新
if (index >= 0) {
this.form = this.fieldArr[index]
}
}
},
// 表的选择
handleChildSelect(data) {
this.form = data.data
},
// 预览表单
handlePreview() {
this.tablePreviewData = this.$route.params
this.showTablePreview = true
},
// 保存数据
handleSave() {
if (this.rejectHandle) return
var tempFieldArr = objDeepCopy(this.fieldArr)
const names = [] // 判断名称重复
const limitFields = 'select|update|union|and|or|delete|insert|trancate|char|substr|ascii|declare|exec|count|master|into|drop|execute'.split('|')
for (let index = 0; index < tempFieldArr.length; index++) {
const item = tempFieldArr[index]
item.is_null = item.is_null == true ? 1 : 0
item.is_unique = item.is_unique == true ? 1 : 0
item.is_hidden = item.is_hidden == true ? 1 : 0
if (item.name !== '' && item.name !== null && item.name !== undefined) {
item.name = item.name.trim()
if (limitFields.includes(item.name)) {
this.$message({
message: `[${item.name}]自定义字段标识名与系统字段重复,请使用其他字段!`,
type: 'error'
})
return
} else if (names.includes(item.name)) {
this.$message({
message: `第${(index + 1)}行[${item.name}]自定义字段标识名重复`,
type: 'error'
})
return
} else {
names.push(item.name)
}
}
if (!item.name) {
this.$message({
type: 'error',
message: `第${index + 1}行自定义字段,标识名不能为空`
})
return
} else if (item.form_type == 'select' || item.form_type == 'checkbox') {
var temps = []
for (let i = 0; i < item.showSetting.length; i++) {
const element = item.showSetting[i]
if (element.value) {
temps.push(element.value)
}
}
// item.options = temps.join(',')//java
item.setting = temps
if (item.form_type == 'checkbox') {
item.default_value = item.default_value.join(',')
}
} else if (item.form_type == 'mobile' && item.default_value) {
if (!regexIsCRMMobile(item.default_value)) {
this.$message({
message: `第${(index + 1)}行(${item.name})自定义字段输入的默认值手机格式有误`,
type: 'error'
})
return
}
} else if (item.form_type == 'email' && item.default_value) {
if (!regexIsCRMEmail(item.default_value)) {
this.$message({
message: `第${(index + 1)}行(${item.name})自定义字段输入的默认值邮箱格式有误`,
type: 'error'
})
return
}
}
item.type = this.getTypeFromForm_type(item.form_type)
}
this.loading = true
var params = {}
params.data = tempFieldArr
// params.label = this.$route.params.label
params.types = this.$route.params.type
if (this.$route.params.type === 'oa_examine') {
params.types_id = this.$route.params.id
params.types = this.$route.params.type
}
for (const item of params.data) {
for (const key in item) {
if (JSON.stringify(item[key]) == '{}') {
item[key] = null
}
}
}
// 请求
const request = this.$route.params.type === 'oa_examine' ? oaFieldHandleAPI : customFieldHandleAPI
request(params)
.then(res => {
this.$message({
type: 'success',
message: '操作成功'
})
this.loading = false
this.getCustomInfo()
})
.catch(() => {
this.loading = false
this.getCustomInfo()
})
},
getTypeFromForm_type(form_type) {
return (
{
text: 1,
textarea: 2,
select: 3,
date: 4,
number: 5,
floatnumber: 6,
mobile: 7,
file: 8,
checkbox: 9,
user: 10,
structure: 12,
datetime: 13,
email: 14,
customer: 15,
business: 16,
contacts: 17,
map_address: 18,
category: 19,
contract: 20,
receivables_plan: 21,
single_user: 28
}[form_type] || '0'
)
},
// 返回
handleCancel() {
this.$router.go(-1)
},
/** 拖拽操作部分 */
// 从左侧移动到右侧
handleEnd(e) {
if (!this.rejectHandle) {
const newField = new Field({
name: this.movedItem.name,
form_type: this.movedItem.form_type
})
// 如果当前选中的table 则加入到table中
if (
this.form &&
this.form.form_type === 'form' &&
this.movedItem.form_type !== 'form'
) {
this.form.formValue.push(newField)
} else {
this.fieldArr.push(newField)
this.selectedIndex = this.fieldArr.length - 1
}
}
},
// 从左侧移动到右侧 时候的数据对象
handleMove(obj) {
this.movedItem = obj
},
// 点击左侧进行添加
handleClick(obj) {
this.movedItem = obj
this.handleEnd()
},
// list move
handleListMove(e) {
this.selectedIndex = e.newIndex
},
/** 拖拽操作部分 */
/** 左上角title */
getTitle() {
if (this.$route.params.type == 'crm_leads') {
return '线索'
} else if (this.$route.params.type == 'crm_customer') {
return '客户'
} else if (this.$route.params.type == 'crm_contacts') {
return '联系人'
} else if (this.$route.params.type == 'crm_business') {
return '商机'
} else if (this.$route.params.type == 'crm_contract') {
return '合同'
} else if (this.$route.params.type == 'crm_product') {
return '产品'
} else if (this.$route.params.type == 'crm_receivables') {
return '回款'
} else if (this.$route.params.type == 'crm_visit') {
return '客户回访'
} else {
return ''
}
},
/**
* 获取添加字段
*/
getTransformField() {
filedGetFieldAPI({
types: crmTypeModel['customer'],
module: 'crm',
action: 'save',
controller: 'customer'
})
.then(res => {
const data = {
text: [],
textarea: [],
select: [],
checkbox: [],
number: [],
floatnumber: [],
mobile: [],
email: [],
date: [],
datetime: [],
user: [],
structure: []
}
for (let index = 0; index < res.data.length; index++) {
const element = res.data[index]
const array = data[element.form_type]
if (array) {
array.push({
label: element.name,
value: element.field
})
}
}
this.transformData = data
})
.catch(() => {})
}
}
}
</script>
<style scoped lang="scss">
@import '@/styles/mixin.scss';
.main {
padding: 0px 15px 0;
}
.el-form-item {
margin: 0;
padding-bottom: 16px;
border-bottom: 1px solid $xr-border-line-color;
.desc {
color: #999;
font-size: 12px;
}
&:last-child {
margin-top: 15px;
}
}
.title {
padding: 0 30px;
height: 60px;
line-height: 60px;
font-size: 16px;
font-weight: 600;
color: #333;
}
.wrapper {
background-color: white;
border: 1px solid $xr-border-line-color;
border-radius: $xr-border-radius-base;
min-width: 1000px;
overflow: hidden;
flex: 1;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
.left {
min-width: 310px;
.mini-title {
font-size: 14px;
margin: 30px 0 20px 20px;
}
.list-wrapper {
padding: 0 20px;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.field-item {
width: 130px;
height: 30px;
font-size: 13px;
padding: 0 10px;
background: #ebf3ff;
margin-bottom: 10px;
border-radius: 3px;
cursor: pointer;
@include left;
.icon {
color: #74b2f2;
margin-right: 8px;
width: 20px;
height: 20px;
}
}
}
}
.content {
border-left: 1px solid $xr-border-line-color;
border-right: 1px solid $xr-border-line-color;
.el-header {
border-bottom: 1px solid $xr-border-line-color;
@include right;
}
.el-main {
padding: 0;
.selected {
border-left: 2px solid $xr-color-primary;
background: #f7f8fa;
}
.no-list {
margin: 200px 0;
color: #ccc;
@include center;
}
}
}
.right {
font-size: 14px;
.mini-title {
height: 60px;
border-bottom: 1px solid $xr-border-line-color;
padding-left: 20px;
@include left;
}
}
}
</style>