12 changed files with 3442 additions and 1477 deletions
@ -0,0 +1,31 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
import { |
||||
|
customerFormCont, |
||||
|
CustomerFormPageResult, |
||||
|
SearchForm, |
||||
|
customerFormConfig |
||||
|
} from './type'; |
||||
|
//自定义表单列表
|
||||
|
export function getCustomerFormList(queryParams: SearchForm): AxiosPromise<CustomerFormPageResult> { |
||||
|
return request({ |
||||
|
url: '/systemapi/customer_form/customer_form_list', |
||||
|
method: 'post', |
||||
|
params: queryParams |
||||
|
}); |
||||
|
} |
||||
|
//生成表单基本信息
|
||||
|
export function getProductionMarkForm(): AxiosPromise<customerFormConfig> { |
||||
|
return request({ |
||||
|
url: '/systemapi/customer_form/production_mark_form', |
||||
|
method: 'post', |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
export function saveProductionForm(data: any) { |
||||
|
return request({ |
||||
|
url: '/systemapi/customer_form/save_customer_form', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}); |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
//搜索表单
|
||||
|
export interface SearchForm extends PageQuery{ |
||||
|
keywords?: string; |
||||
|
classify?:number; |
||||
|
} |
||||
|
//自定义表单列表内容
|
||||
|
export interface customerFormCont{ |
||||
|
id:string; |
||||
|
name:string; |
||||
|
tablename:string; |
||||
|
states:number; |
||||
|
classify:number; |
||||
|
creatername:string; |
||||
|
creatertime:string; |
||||
|
} |
||||
|
|
||||
|
export type CustomerFormPageResult = PageResult<customerFormCont[]>; |
||||
|
|
||||
|
//初始化表单基本信息
|
||||
|
export interface customerFormConfig{ |
||||
|
formname:string; |
||||
|
formlogo:string; |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,562 @@ |
|||||
|
<!-- |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2023-05-26 10:35:30 |
||||
|
@ 备注: |
||||
|
--> |
||||
|
<script lang='ts' setup> |
||||
|
import '@/assets/scss/element-var.scss' |
||||
|
import '@/assets/scss/index.scss' |
||||
|
import '@/assets/iconfont/iconfont.css' |
||||
|
import 'element-plus/dist/index.css' |
||||
|
import { useDesignFormStore } from '@/store/DesignForm/designForm' |
||||
|
import { useRoute, useRouter } from 'vue-router' |
||||
|
import { |
||||
|
json2string, |
||||
|
objToStringify, |
||||
|
string2json, |
||||
|
stringToObj |
||||
|
} from '@/utils/DesignForm/form' |
||||
|
|
||||
|
import { getRequest } from '@/api/DesignForm' |
||||
|
import { afterResponse, beforeRequest, onChange } from '@/api/DesignForm/utils' |
||||
|
|
||||
|
//引入页面 |
||||
|
import DragControl from '@/components/DesignForm/dragControl.vue'; |
||||
|
import HeadTools from '@/components/DesignForm/public/headTools.vue'; |
||||
|
import FormDesign from '@/components/DesignForm/public/form/form.vue' |
||||
|
import FormControlAttr from '@/components/DesignForm/formControlAttr.vue'; |
||||
|
import VueFile from '@/components/DesignForm/vueFile.vue' |
||||
|
import AceDrawer from '@/components/DesignForm/aceDrawer.vue' |
||||
|
|
||||
|
import { ref, reactive, provide, onMounted } from 'vue' |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import { useLayoutStore } from '@/store/DesignForm/layout' |
||||
|
import { FormData,formStruct,DrawerStruct } from '@/api/DesignForm/types' |
||||
|
|
||||
|
import { saveProductionForm } from '@/api/DesignForm/requestapi' |
||||
|
|
||||
|
const isSave = ref(false) |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
draweropenclose:{ |
||||
|
type:Boolean, |
||||
|
default:true |
||||
|
}, |
||||
|
formconfigcont:{ |
||||
|
type:Object, |
||||
|
default(){ |
||||
|
return {} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
const emits = defineEmits(["update:draweropenclose","handlequery"]); |
||||
|
|
||||
|
/** |
||||
|
* 弹窗显示控制 |
||||
|
*/ |
||||
|
const openShow = computed({ |
||||
|
get: () => props.draweropenclose, |
||||
|
set: (val) => { |
||||
|
emits("update:draweropenclose", val); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
const layoutStore = useLayoutStore() |
||||
|
layoutStore.changeBreadcrumb([{ label: '系统工具' }, { label: '表单设计' }]) |
||||
|
|
||||
|
const store = useDesignFormStore() |
||||
|
const router = useRouter() |
||||
|
const route: any = useRoute().query || {} |
||||
|
const state = reactive<formStruct>({ |
||||
|
formData: { |
||||
|
list: [], |
||||
|
form: { |
||||
|
size: 'default', |
||||
|
name:'', |
||||
|
formName: props.formconfigcont.formName |
||||
|
}, |
||||
|
config: {} |
||||
|
}, |
||||
|
editor: {}, |
||||
|
loading: false, |
||||
|
formDataPreview: {}, |
||||
|
previewVisible: false, // 预览窗口 |
||||
|
designType: route.type, // 当前页面设计类型,有效值search |
||||
|
formDict: {}, |
||||
|
formOtherData: { |
||||
|
source: route.source || '', |
||||
|
formName: props.formconfigcont.formName |
||||
|
} |
||||
|
}) |
||||
|
const drawer = reactive<DrawerStruct>({ |
||||
|
visible: false, |
||||
|
type: '', |
||||
|
title: '', |
||||
|
codeType: '', |
||||
|
direction: undefined, //弹出方向rtl / ltr |
||||
|
callback: '' |
||||
|
}) |
||||
|
const vueFileEl = ref() |
||||
|
const formControlAttrEl = ref() |
||||
|
// 当前表单设计类型,供各子组件调用以展示不同页面,统一方式不需要每个组件都从路由中取 |
||||
|
provide('formDesignType', state.designType) |
||||
|
const getInitData = () => { |
||||
|
const id = route.id // 当前记录保存的id |
||||
|
if (id) { |
||||
|
// 获取初始表单数据 |
||||
|
state.loading = true |
||||
|
getRequest('designById', { id: id }) |
||||
|
.then(res => { |
||||
|
const result = res.data |
||||
|
// 初始设计搜索时res.data='' |
||||
|
if (result.data) { |
||||
|
state.formData = stringToObj(result.data) |
||||
|
} |
||||
|
state.formDict = string2json(result.dict) |
||||
|
// 恢复表单名称 |
||||
|
state.formOtherData.source = result.source |
||||
|
state.formOtherData.formName = result.name |
||||
|
if (result.source && state.designType !== 'search') { |
||||
|
// 加载属性侧边栏的字段标识,搜索时不需要请求 |
||||
|
formControlAttrEl.value.getFormFieldBySource(result.source) |
||||
|
} |
||||
|
state.loading = false |
||||
|
}) |
||||
|
.catch((res: any) => { |
||||
|
// console.log(res) |
||||
|
ElMessage.error(res.message || '加载异常') |
||||
|
state.loading = false |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
const headToolClick = (type: string) => { |
||||
|
switch (type) { |
||||
|
case 'del': |
||||
|
state.formData.list = [] |
||||
|
store.setActiveKey('') |
||||
|
store.setControlAttr({}) |
||||
|
break |
||||
|
case 'eye': |
||||
|
// 打开预览窗口 |
||||
|
store.setActiveKey('') |
||||
|
store.setControlAttr({}) |
||||
|
state.previewVisible = true |
||||
|
// eslint-disable-next-line no-case-declarations |
||||
|
let stringPreview = objToStringify(state.formData) // 防止预览窗口数据修改影响 |
||||
|
// eslint-disable-next-line no-case-declarations |
||||
|
const formName = state.formData.form.name |
||||
|
// eslint-disable-next-line no-case-declarations |
||||
|
const reg = new RegExp(`get${formName}ControlByName`, 'g') |
||||
|
stringPreview = stringPreview.replace( |
||||
|
reg, |
||||
|
`getPreview${formName}ControlByName` |
||||
|
) |
||||
|
state.formDataPreview = stringToObj(stringPreview) |
||||
|
state.formDataPreview.form.name = `Preview${formName}` // 修改下表单名 |
||||
|
break |
||||
|
case 'json': |
||||
|
// 生成脚本预览 |
||||
|
openAceEditDrawer({ |
||||
|
direction: 'rtl', |
||||
|
content: state.formData, |
||||
|
title: '可编辑修改或将已生成的脚本粘贴进来' |
||||
|
}) |
||||
|
break |
||||
|
case 'save': |
||||
|
// saveData(); |
||||
|
saveDataNew(); |
||||
|
break |
||||
|
case 'vue': |
||||
|
vueFileEl.value.open(state.formData) |
||||
|
emits("update:draweropenclose", false); |
||||
|
break |
||||
|
case 'close': |
||||
|
console.log("关闭") |
||||
|
if(isSave.value){ |
||||
|
emits("update:draweropenclose", false); |
||||
|
}else{ |
||||
|
ElMessageBox.confirm( |
||||
|
'表单已做设计或修改!请问是否保存?', |
||||
|
'温馨提示!', |
||||
|
{ |
||||
|
confirmButtonText: '保存', |
||||
|
cancelButtonText: '不保存', |
||||
|
type: 'warning', |
||||
|
draggable: true, |
||||
|
}) |
||||
|
.then(() => { |
||||
|
saveDataNew(); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
emits("update:draweropenclose", false); |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
// 弹窗确认 |
||||
|
const dialogConfirm = (editVal: string) => { |
||||
|
// 生成脚本预览和导入json,都是将编辑器内容更新至state.formData |
||||
|
try { |
||||
|
if (typeof drawer.callback === 'function') { |
||||
|
// callback |
||||
|
const newObj = |
||||
|
drawer.codeType === 'json' |
||||
|
? string2json(editVal) |
||||
|
: stringToObj(editVal) |
||||
|
drawer.callback(newObj) |
||||
|
} else { |
||||
|
switch (drawer.type) { |
||||
|
case 'css': |
||||
|
// 表单属性-编辑表单样式 |
||||
|
if (!state.formData.config) { |
||||
|
state.formData.config = {} |
||||
|
} |
||||
|
state.formData.config.style = editVal |
||||
|
break |
||||
|
case 'dict': |
||||
|
state.formDict = string2json(editVal) |
||||
|
break |
||||
|
case 'beforeRequest': |
||||
|
case 'beforeSubmit': |
||||
|
case 'afterResponse': |
||||
|
case 'afterSubmit': |
||||
|
case 'change': |
||||
|
if (!state.formData.events) { |
||||
|
state.formData.events = {} |
||||
|
} |
||||
|
state.formData.events[drawer.type] = stringToObj(editVal) |
||||
|
break |
||||
|
default: |
||||
|
state.formData = stringToObj(editVal) |
||||
|
} |
||||
|
} |
||||
|
dialogCancel() |
||||
|
} catch (res) { |
||||
|
// console.log(res.message) |
||||
|
//ElMessage.error(res.message) |
||||
|
} |
||||
|
} |
||||
|
//讲数据保存到服务端(新版) |
||||
|
const saveDataNew = () => { |
||||
|
isSave.value = true |
||||
|
let params: any = { |
||||
|
jsondata:JSON.stringify(state.formData), |
||||
|
data: objToStringify(state.formData), |
||||
|
source: state.formOtherData.source, // 数据源允许在表单属性设置里修改的 |
||||
|
name: state.formOtherData.formName, // 表单名称,用于在显示所有已创建的表单列表里显示 |
||||
|
type: 1, // 1表单 2列表 |
||||
|
dict: json2string(state.formDict) |
||||
|
} |
||||
|
let apiKey = 'designSave' |
||||
|
if (route.id) { |
||||
|
// 编辑状态 当前记录id |
||||
|
Object.assign(params, { id: route.id }) |
||||
|
apiKey = 'designEdit' |
||||
|
} |
||||
|
// 列表搜索模式下只有修改 |
||||
|
if (state.designType === 'search') { |
||||
|
params = { |
||||
|
data: objToStringify(state.formData), |
||||
|
dict: json2string(state.formDict), |
||||
|
id: route.id |
||||
|
} |
||||
|
} |
||||
|
state.loading = true |
||||
|
|
||||
|
saveProductionForm(params) |
||||
|
.then((res: any) => { |
||||
|
console.log("数据保存", res) |
||||
|
if(res.code == 0){ |
||||
|
ElMessage({ |
||||
|
message: res.message || '保存成功!', |
||||
|
type: 'success' |
||||
|
}) |
||||
|
emits("handlequery"); |
||||
|
emits("update:draweropenclose", false); |
||||
|
// 清空右侧栏信息 |
||||
|
store.setActiveKey('') |
||||
|
store.setControlAttr({}) |
||||
|
}else{ |
||||
|
ElMessage({ |
||||
|
message: res.msg || '保存失败!', |
||||
|
type: 'error' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
}) |
||||
|
.finally(() => { |
||||
|
state.loading=false; |
||||
|
}) |
||||
|
.catch((res: any) => { |
||||
|
ElMessage.error(res.message || '保存异常') |
||||
|
state.loading = false |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
// 将数据保存在服务端 |
||||
|
const saveData = () => { |
||||
|
// 添加校验,没有选择数据源时则必须要配置接口url |
||||
|
const { addUrl, editUrl, requestUrl } = state.formData.config |
||||
|
if ( |
||||
|
!state.formOtherData.source && |
||||
|
(!addUrl || !editUrl || !requestUrl) && |
||||
|
state.designType !== 'search' |
||||
|
) { |
||||
|
ElMessage.error('请选择数据源或配置接口url地址,否则表单无法提交保存') |
||||
|
return |
||||
|
} |
||||
|
let params: any = { |
||||
|
jsondata:JSON.stringify(state.formData), |
||||
|
data: objToStringify(state.formData), |
||||
|
source: state.formOtherData.source, // 数据源允许在表单属性设置里修改的 |
||||
|
name: state.formOtherData.formName, // 表单名称,用于在显示所有已创建的表单列表里显示 |
||||
|
type: 1, // 1表单 2列表 |
||||
|
dict: json2string(state.formDict) |
||||
|
} |
||||
|
let apiKey = 'designSave' |
||||
|
if (route.id) { |
||||
|
// 编辑状态 当前记录id |
||||
|
Object.assign(params, { id: route.id }) |
||||
|
apiKey = 'designEdit' |
||||
|
} |
||||
|
// 列表搜索模式下只有修改 |
||||
|
if (state.designType === 'search') { |
||||
|
params = { |
||||
|
data: objToStringify(state.formData), |
||||
|
dict: json2string(state.formDict), |
||||
|
id: route.id |
||||
|
} |
||||
|
} |
||||
|
state.loading = true |
||||
|
getRequest(apiKey, params) |
||||
|
.then((res: any) => { |
||||
|
ElMessage({ |
||||
|
message: res.message || '保存成功!', |
||||
|
type: 'success' |
||||
|
}) |
||||
|
// 根据不同情况跳转到不同地址 |
||||
|
const path = route.redirect || '/design/form/list' |
||||
|
const query: any = {} |
||||
|
if (route.redirect && route.redirect.indexOf('?') !== -1) { |
||||
|
// 带有问号参数时,放在path传是有问题的,将id=1转为{id:1} |
||||
|
const p = route.redirect.split('?')[1] |
||||
|
const pSplit = p.split('&') |
||||
|
pSplit.forEach((item: string) => { |
||||
|
const splitItem = item.split('=') |
||||
|
query[splitItem[0]] = splitItem[1] |
||||
|
}) |
||||
|
} |
||||
|
router.push({ path: path, query: query }) |
||||
|
state.loading = false |
||||
|
}) |
||||
|
.catch((res: any) => { |
||||
|
ElMessage.error(res.message || '保存异常') |
||||
|
state.loading = false |
||||
|
}) |
||||
|
// 清空右侧内容管理菜单存在session的内容,刷新时可重新加载新菜单 |
||||
|
if (!route.id) { |
||||
|
// 新增时 |
||||
|
window.sessionStorage.removeItem('formMenuList') |
||||
|
} |
||||
|
// 清空右侧栏信息 |
||||
|
store.setActiveKey('') |
||||
|
store.setControlAttr({}) |
||||
|
} |
||||
|
const openAceEditDrawer = (params: any) => { |
||||
|
const { type, direction, codeType, title, callback, content } = params |
||||
|
drawer.direction = direction // 窗口位置ltr/rtl |
||||
|
drawer.type = type // 作为窗口唯一标识,在窗口关闭时可根据type作不同处理 |
||||
|
drawer.codeType = codeType || '' // 显示代码类型 |
||||
|
drawer.title = title ? `提示:${title}` : '' |
||||
|
drawer.visible = true |
||||
|
drawer.callback = callback |
||||
|
let editData = |
||||
|
codeType === 'json' |
||||
|
? json2string(content, true) |
||||
|
: objToStringify(content, true) |
||||
|
switch (type) { |
||||
|
case 'css': |
||||
|
editData = state.formData.config?.style || '' |
||||
|
break |
||||
|
case 'dict': |
||||
|
// 格式化一下 |
||||
|
editData = json2string(state.formDict, true) |
||||
|
break |
||||
|
case 'beforeRequest': |
||||
|
case 'beforeSubmit': |
||||
|
case 'afterResponse': |
||||
|
case 'afterSubmit': |
||||
|
case 'change': |
||||
|
// eslint-disable-next-line no-case-declarations |
||||
|
const beforeData = state.formData.events || {} |
||||
|
if (beforeData[type]) { |
||||
|
editData = objToStringify(beforeData[type], true) |
||||
|
} else { |
||||
|
if (['afterResponse', 'afterSubmit'].includes(type)) { |
||||
|
editData = afterResponse |
||||
|
} else if (type === 'change') { |
||||
|
editData = onChange |
||||
|
} else { |
||||
|
editData = beforeRequest |
||||
|
} |
||||
|
} |
||||
|
break |
||||
|
// case 'afterResponse': |
||||
|
// case 'afterSubmit': |
||||
|
// const newData = state.formData.events || {} |
||||
|
// if (newData[type]) { |
||||
|
// editData = objToStringify(newData[type], true) |
||||
|
// } else { |
||||
|
// editData = afterResponse |
||||
|
// } |
||||
|
// break |
||||
|
|
||||
|
case 'optionsParams': |
||||
|
if (!content) { |
||||
|
editData = beforeRequest |
||||
|
} |
||||
|
break |
||||
|
case 'optionsResult': |
||||
|
if (!content) { |
||||
|
editData = afterResponse |
||||
|
} |
||||
|
break |
||||
|
} |
||||
|
drawer.content = editData |
||||
|
} |
||||
|
const drawerBeforeClose = () => { |
||||
|
dialogCancel() |
||||
|
} |
||||
|
const dialogCancel = () => { |
||||
|
drawer.visible = false |
||||
|
drawer.type = '' |
||||
|
drawer.title = '' |
||||
|
drawer.codeType = '' |
||||
|
drawer.callback = '' |
||||
|
drawer.content = '' |
||||
|
} |
||||
|
// 预览窗口提交测试 |
||||
|
const previewForm = ref() |
||||
|
const previewSubmit = () => { |
||||
|
previewForm.value.validate((valid: boolean, fields: any) => { |
||||
|
if (valid) { |
||||
|
// alert('校验通过') |
||||
|
ElMessage.success('校验通过') |
||||
|
console.log(fields) |
||||
|
} else { |
||||
|
// alert('校验不通过') |
||||
|
// console.log('error submit!', fields) |
||||
|
ElMessage.error('校验不通过') |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
// 选择模板 |
||||
|
const selectTemplate = (data: FormData) => { |
||||
|
|
||||
|
state.formData = stringToObj(objToStringify(data)) |
||||
|
} |
||||
|
// 搜索设计时左侧快速添加字段 |
||||
|
const searchCheckField = (data: FormData) => { |
||||
|
state.formData.list.push(data) |
||||
|
} |
||||
|
getInitData() |
||||
|
// 从数据源点创建表单过来时,带有参数source |
||||
|
onMounted(() => { |
||||
|
if (route.source) { |
||||
|
formControlAttrEl.value.getFormFieldBySource(route.source) |
||||
|
} |
||||
|
}) |
||||
|
onMounted(() => { |
||||
|
console.log("监听数据",route.type,props.formconfigcont.formname,props.formconfigcont.formlogo,state) |
||||
|
state.formOtherData.formName = props.formconfigcont.formname |
||||
|
state.formData.form.name = props.formconfigcont.formlogo |
||||
|
state.formData.form.formName = props.formconfigcont.formname |
||||
|
}) |
||||
|
/** |
||||
|
* 监听数据 |
||||
|
*/ |
||||
|
watch(() => props.draweropenclose,() => { |
||||
|
console.log("监听数据",props.draweropenclose,state) |
||||
|
if(props.draweropenclose){ |
||||
|
state.formOtherData.formName = props.formconfigcont.formName |
||||
|
state.formData.form.name = props.formconfigcont.formlogo |
||||
|
state.formData.form.formName = props.formconfigcont.formName |
||||
|
}else{ |
||||
|
state.formOtherData.formName = "未命名表单" |
||||
|
state.formData.form.name = props.formconfigcont.formlogo |
||||
|
state.formData.form.formName = "未命名表单" |
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
</script> |
||||
|
<template> |
||||
|
<div class="design-container"> |
||||
|
<DragControl |
||||
|
:formid="state.formOtherData.source" |
||||
|
@click-check="searchCheckField" |
||||
|
@click="selectTemplate" |
||||
|
/> |
||||
|
<div class="main-body"> |
||||
|
|
||||
|
<HeadTools @click="headToolClick" /> |
||||
|
<div v-loading="state.loading" class="main-form"> |
||||
|
<div v-if="state.formData.list.length === 0" class="empty-tips"> |
||||
|
从左侧拖拽来添加组件 |
||||
|
</div> |
||||
|
<FormDesign |
||||
|
v-model:issave="isSave" |
||||
|
:type="5" |
||||
|
:form-data="state.formData" |
||||
|
:dict="state.formDict" |
||||
|
|
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!--面版右侧--> |
||||
|
<form-control-attr |
||||
|
ref="formControlAttrEl" |
||||
|
v-model:formOtherData="state.formOtherData" |
||||
|
:form-data="state.formData.form" |
||||
|
:form-config="state.formData.config" |
||||
|
@open-dialog="openAceEditDrawer" |
||||
|
/> |
||||
|
<ace-drawer |
||||
|
v-model="drawer.visible" |
||||
|
:title="drawer.title" |
||||
|
:direction="drawer.direction" |
||||
|
:content="drawer.content" |
||||
|
:code-type="drawer.codeType" |
||||
|
@before-close="drawerBeforeClose" |
||||
|
@confirm="dialogConfirm" |
||||
|
/> |
||||
|
<vue-file v-if="!['search'].includes(state.designType)" ref="vueFileEl" /> |
||||
|
<el-dialog v-model="state.previewVisible" title="预览" :fullscreen="true"> |
||||
|
<form-design |
||||
|
v-if="state.previewVisible" |
||||
|
ref="previewForm" |
||||
|
:form-data="state.formDataPreview" |
||||
|
:dict="state.formDict" |
||||
|
:type="1" |
||||
|
/> |
||||
|
<template #footer> |
||||
|
<div class="dialog-footer"> |
||||
|
<el-button size="small" type="primary" @click="previewSubmit"> |
||||
|
提交 |
||||
|
</el-button> |
||||
|
<el-button size="small" @click="state.previewVisible = false"> |
||||
|
取消 |
||||
|
</el-button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
<style lang='scss' scoped> |
||||
|
.design-container{ |
||||
|
padding: 0; |
||||
|
} |
||||
|
</style> |
||||
@ -1,423 +1,185 @@ |
|||||
<!-- |
<!-- |
||||
@ 作者: 秦东 |
@ 作者: 秦东 |
||||
@ 时间: 2023-05-26 10:35:30 |
@ 时间: 2023-08-28 14:47:07 |
||||
@ 备注: |
@ 备注: 表单设计 |
||||
--> |
--> |
||||
<script lang='ts' setup> |
<script lang='ts' setup> |
||||
import '@/assets/scss/element-var.scss' |
import { SearchForm,customerFormCont,customerFormConfig } from "@/api/DesignForm/type"; |
||||
import '@/assets/scss/index.scss' |
import { getCustomerFormList,getProductionMarkForm } from '@/api/DesignForm/requestapi' |
||||
import '@/assets/iconfont/iconfont.css' |
|
||||
import 'element-plus/dist/index.css' |
|
||||
import { useDesignFormStore } from '@/store/DesignForm/designForm' |
|
||||
import { useRoute, useRouter } from 'vue-router' |
|
||||
import { |
|
||||
json2string, |
|
||||
objToStringify, |
|
||||
string2json, |
|
||||
stringToObj |
|
||||
} from '@/utils/DesignForm/form' |
|
||||
|
|
||||
import { getRequest } from '@/api/DesignForm' |
|
||||
import { afterResponse, beforeRequest, onChange } from '@/api/DesignForm/utils' |
|
||||
|
|
||||
//引入页面 |
//引入页面 |
||||
import DragControl from '@/components/DesignForm/dragControl.vue'; |
import CreateForm from '@/views/sysworkflow/codepage/createform.vue' |
||||
import HeadTools from '@/components/DesignForm/public/headTools.vue'; |
|
||||
import FormDesign from '@/components/DesignForm/public/form/form.vue' |
|
||||
import FormControlAttr from '@/components/DesignForm/formControlAttr.vue'; |
|
||||
import VueFile from '@/components/DesignForm/vueFile.vue' |
|
||||
import AceDrawer from '@/components/DesignForm/aceDrawer.vue' |
|
||||
|
|
||||
import { ref, reactive, provide, onMounted } from 'vue' |
|
||||
import { ElMessage } from 'element-plus' |
|
||||
import { useLayoutStore } from '@/store/DesignForm/layout' |
|
||||
import { FormData,formStruct,DrawerStruct } from '@/api/DesignForm/types' |
|
||||
|
|
||||
const layoutStore = useLayoutStore() |
const queryParams = reactive<SearchForm>({ |
||||
layoutStore.changeBreadcrumb([{ label: '系统工具' }, { label: '表单设计' }]) |
page: 1, |
||||
|
pagesize:15 |
||||
const store = useDesignFormStore() |
}); |
||||
const router = useRouter() |
const ids = ref<number[]>([]); //记录总数 |
||||
const route: any = useRoute().query || {} |
const loading =ref(false); //加载表单 |
||||
const state = reactive<formStruct>({ |
const drawerOpenOrClose = ref(false); |
||||
formData: { |
const total = ref(0); //记录总数 |
||||
list: [], |
const contList = ref<customerFormCont[]>() |
||||
form: { |
const drawerWith = ref<number>(0); |
||||
size: 'default', |
const formConfigCont = reactive<customerFormConfig>({ |
||||
name:'' |
formname:"", |
||||
}, |
formlogo:"" |
||||
config: {} |
|
||||
}, |
|
||||
editor: {}, |
|
||||
loading: false, |
|
||||
formDataPreview: {}, |
|
||||
previewVisible: false, // 预览窗口 |
|
||||
designType: route.type, // 当前页面设计类型,有效值search |
|
||||
formDict: {}, |
|
||||
formOtherData: { |
|
||||
source: route.source || '', |
|
||||
formName: '未命名表单' |
|
||||
} |
|
||||
}) |
}) |
||||
const drawer = reactive<DrawerStruct>({ |
//搜索表单 |
||||
visible: false, |
function handleQuery(){ |
||||
type: '', |
getCustomerFormList(queryParams) |
||||
title: '', |
.then(({ data }) => { |
||||
codeType: '', |
console.log("搜索表单-->",data); |
||||
direction: undefined, //弹出方向rtl / ltr |
total.value = data.total |
||||
callback: '' |
contList.value = data.list |
||||
}) |
|
||||
const vueFileEl = ref() |
|
||||
const formControlAttrEl = ref() |
|
||||
// 当前表单设计类型,供各子组件调用以展示不同页面,统一方式不需要每个组件都从路由中取 |
|
||||
provide('formDesignType', state.designType) |
|
||||
const getInitData = () => { |
|
||||
const id = route.id // 当前记录保存的id |
|
||||
if (id) { |
|
||||
// 获取初始表单数据 |
|
||||
state.loading = true |
|
||||
getRequest('designById', { id: id }) |
|
||||
.then(res => { |
|
||||
const result = res.data |
|
||||
// 初始设计搜索时res.data='' |
|
||||
if (result.data) { |
|
||||
state.formData = stringToObj(result.data) |
|
||||
} |
|
||||
state.formDict = string2json(result.dict) |
|
||||
// 恢复表单名称 |
|
||||
state.formOtherData.source = result.source |
|
||||
state.formOtherData.formName = result.name |
|
||||
if (result.source && state.designType !== 'search') { |
|
||||
// 加载属性侧边栏的字段标识,搜索时不需要请求 |
|
||||
formControlAttrEl.value.getFormFieldBySource(result.source) |
|
||||
} |
|
||||
state.loading = false |
|
||||
}) |
}) |
||||
.catch((res: any) => { |
.finally(() => {}) |
||||
// console.log(res) |
} |
||||
ElMessage.error(res.message || '加载异常') |
//重置搜索条件 |
||||
state.loading = false |
function resetQuery(){} |
||||
|
//新增表单 |
||||
|
function openDialog(){ |
||||
|
getProductionMarkForm() |
||||
|
.then(({data})=>{ |
||||
|
formConfigCont.formlogo = data.formlogo |
||||
|
formConfigCont.formname = data.formname |
||||
|
console.log("新增表单",formConfigCont) |
||||
}) |
}) |
||||
} |
.finally(()=>{ |
||||
} |
drawerOpenOrClose.value = true; |
||||
const headToolClick = (type: string) => { |
|
||||
switch (type) { |
|
||||
case 'del': |
|
||||
state.formData.list = [] |
|
||||
store.setActiveKey('') |
|
||||
store.setControlAttr({}) |
|
||||
break |
|
||||
case 'eye': |
|
||||
// 打开预览窗口 |
|
||||
store.setActiveKey('') |
|
||||
store.setControlAttr({}) |
|
||||
state.previewVisible = true |
|
||||
// eslint-disable-next-line no-case-declarations |
|
||||
let stringPreview = objToStringify(state.formData) // 防止预览窗口数据修改影响 |
|
||||
// eslint-disable-next-line no-case-declarations |
|
||||
const formName = state.formData.form.name |
|
||||
// eslint-disable-next-line no-case-declarations |
|
||||
const reg = new RegExp(`get${formName}ControlByName`, 'g') |
|
||||
stringPreview = stringPreview.replace( |
|
||||
reg, |
|
||||
`getPreview${formName}ControlByName` |
|
||||
) |
|
||||
state.formDataPreview = stringToObj(stringPreview) |
|
||||
state.formDataPreview.form.name = `Preview${formName}` // 修改下表单名 |
|
||||
break |
|
||||
case 'json': |
|
||||
// 生成脚本预览 |
|
||||
openAceEditDrawer({ |
|
||||
direction: 'rtl', |
|
||||
content: state.formData, |
|
||||
title: '可编辑修改或将已生成的脚本粘贴进来' |
|
||||
}) |
}) |
||||
break |
|
||||
case 'save': |
|
||||
saveData() |
|
||||
break |
|
||||
case 'vue': |
|
||||
vueFileEl.value.open(state.formData) |
|
||||
break |
|
||||
} |
|
||||
} |
|
||||
// 弹窗确认 |
|
||||
const dialogConfirm = (editVal: string) => { |
|
||||
// 生成脚本预览和导入json,都是将编辑器内容更新至state.formData |
|
||||
try { |
|
||||
if (typeof drawer.callback === 'function') { |
|
||||
// callback |
|
||||
const newObj = |
|
||||
drawer.codeType === 'json' |
|
||||
? string2json(editVal) |
|
||||
: stringToObj(editVal) |
|
||||
drawer.callback(newObj) |
|
||||
} else { |
|
||||
switch (drawer.type) { |
|
||||
case 'css': |
|
||||
// 表单属性-编辑表单样式 |
|
||||
if (!state.formData.config) { |
|
||||
state.formData.config = {} |
|
||||
} |
|
||||
state.formData.config.style = editVal |
|
||||
break |
|
||||
case 'dict': |
|
||||
state.formDict = string2json(editVal) |
|
||||
break |
|
||||
case 'beforeRequest': |
|
||||
case 'beforeSubmit': |
|
||||
case 'afterResponse': |
|
||||
case 'afterSubmit': |
|
||||
case 'change': |
|
||||
if (!state.formData.events) { |
|
||||
state.formData.events = {} |
|
||||
} |
|
||||
state.formData.events[drawer.type] = stringToObj(editVal) |
|
||||
break |
|
||||
default: |
|
||||
state.formData = stringToObj(editVal) |
|
||||
} |
|
||||
} |
|
||||
dialogCancel() |
|
||||
} catch (res) { |
|
||||
// console.log(res.message) |
|
||||
//ElMessage.error(res.message) |
|
||||
} |
|
||||
} |
|
||||
// 将数据保存在服务端 |
|
||||
const saveData = () => { |
|
||||
// 添加校验,没有选择数据源时则必须要配置接口url |
|
||||
const { addUrl, editUrl, requestUrl } = state.formData.config |
|
||||
if ( |
|
||||
!state.formOtherData.source && |
|
||||
(!addUrl || !editUrl || !requestUrl) && |
|
||||
state.designType !== 'search' |
|
||||
) { |
|
||||
ElMessage.error('请选择数据源或配置接口url地址,否则表单无法提交保存') |
|
||||
return |
|
||||
} |
|
||||
let params: any = { |
|
||||
data: objToStringify(state.formData), |
|
||||
source: state.formOtherData.source, // 数据源允许在表单属性设置里修改的 |
|
||||
name: state.formOtherData.formName, // 表单名称,用于在显示所有已创建的表单列表里显示 |
|
||||
type: 1, // 1表单 2列表 |
|
||||
dict: json2string(state.formDict) |
|
||||
} |
|
||||
let apiKey = 'designSave' |
|
||||
if (route.id) { |
|
||||
// 编辑状态 当前记录id |
|
||||
Object.assign(params, { id: route.id }) |
|
||||
apiKey = 'designEdit' |
|
||||
} |
|
||||
// 列表搜索模式下只有修改 |
|
||||
if (state.designType === 'search') { |
|
||||
params = { |
|
||||
data: objToStringify(state.formData), |
|
||||
dict: json2string(state.formDict), |
|
||||
id: route.id |
|
||||
} |
|
||||
} |
|
||||
state.loading = true |
|
||||
getRequest(apiKey, params) |
|
||||
.then((res: any) => { |
|
||||
ElMessage({ |
|
||||
message: res.message || '保存成功!', |
|
||||
type: 'success' |
|
||||
}) |
|
||||
// 根据不同情况跳转到不同地址 |
|
||||
const path = route.redirect || '/design/form/list' |
|
||||
const query: any = {} |
|
||||
if (route.redirect && route.redirect.indexOf('?') !== -1) { |
|
||||
// 带有问号参数时,放在path传是有问题的,将id=1转为{id:1} |
|
||||
const p = route.redirect.split('?')[1] |
|
||||
const pSplit = p.split('&') |
|
||||
pSplit.forEach((item: string) => { |
|
||||
const splitItem = item.split('=') |
|
||||
query[splitItem[0]] = splitItem[1] |
|
||||
}) |
|
||||
} |
|
||||
router.push({ path: path, query: query }) |
|
||||
state.loading = false |
|
||||
}) |
|
||||
.catch((res: any) => { |
|
||||
ElMessage.error(res.message || '保存异常') |
|
||||
state.loading = false |
|
||||
}) |
|
||||
// 清空右侧内容管理菜单存在session的内容,刷新时可重新加载新菜单 |
|
||||
if (!route.id) { |
|
||||
// 新增时 |
|
||||
window.sessionStorage.removeItem('formMenuList') |
|
||||
} |
|
||||
// 清空右侧栏信息 |
|
||||
store.setActiveKey('') |
|
||||
store.setControlAttr({}) |
|
||||
} |
|
||||
const openAceEditDrawer = (params: any) => { |
|
||||
const { type, direction, codeType, title, callback, content } = params |
|
||||
drawer.direction = direction // 窗口位置ltr/rtl |
|
||||
drawer.type = type // 作为窗口唯一标识,在窗口关闭时可根据type作不同处理 |
|
||||
drawer.codeType = codeType || '' // 显示代码类型 |
|
||||
drawer.title = title ? `提示:${title}` : '' |
|
||||
drawer.visible = true |
|
||||
drawer.callback = callback |
|
||||
let editData = |
|
||||
codeType === 'json' |
|
||||
? json2string(content, true) |
|
||||
: objToStringify(content, true) |
|
||||
switch (type) { |
|
||||
case 'css': |
|
||||
editData = state.formData.config?.style || '' |
|
||||
break |
|
||||
case 'dict': |
|
||||
// 格式化一下 |
|
||||
editData = json2string(state.formDict, true) |
|
||||
break |
|
||||
case 'beforeRequest': |
|
||||
case 'beforeSubmit': |
|
||||
case 'afterResponse': |
|
||||
case 'afterSubmit': |
|
||||
case 'change': |
|
||||
// eslint-disable-next-line no-case-declarations |
|
||||
const beforeData = state.formData.events || {} |
|
||||
if (beforeData[type]) { |
|
||||
editData = objToStringify(beforeData[type], true) |
|
||||
} else { |
|
||||
if (['afterResponse', 'afterSubmit'].includes(type)) { |
|
||||
editData = afterResponse |
|
||||
} else if (type === 'change') { |
|
||||
editData = onChange |
|
||||
} else { |
|
||||
editData = beforeRequest |
|
||||
} |
|
||||
} |
|
||||
break |
|
||||
// case 'afterResponse': |
|
||||
// case 'afterSubmit': |
|
||||
// const newData = state.formData.events || {} |
|
||||
// if (newData[type]) { |
|
||||
// editData = objToStringify(newData[type], true) |
|
||||
// } else { |
|
||||
// editData = afterResponse |
|
||||
// } |
|
||||
// break |
|
||||
|
|
||||
case 'optionsParams': |
} |
||||
if (!content) { |
//删除表单 |
||||
editData = beforeRequest |
function handleDelete(){} |
||||
} |
/** |
||||
break |
* 行checkbox change事件 |
||||
case 'optionsResult': |
*/ |
||||
if (!content) { |
function handleSelectionChange(selection: any) { |
||||
editData = afterResponse |
ids.value = selection.map((item: any) => item.id); |
||||
} |
} |
||||
break |
//设置自定义表单 |
||||
} |
function setupCustomerForm(cont:customerFormCont){ |
||||
drawer.content = editData |
|
||||
} |
} |
||||
const drawerBeforeClose = () => { |
onMounted(()=>{ |
||||
dialogCancel() |
handleQuery(); |
||||
} |
drawerWith.value = window.innerWidth - 220 |
||||
const dialogCancel = () => { |
}); |
||||
drawer.visible = false |
window.addEventListener("resize", function(){ |
||||
drawer.type = '' |
drawerWith.value = window.innerWidth -220 |
||||
drawer.title = '' |
console.log("搜索表单-->",window.innerWidth); |
||||
drawer.codeType = '' |
}) |
||||
drawer.callback = '' |
//监听屏幕宽度变化 |
||||
drawer.content = '' |
|
||||
} |
|
||||
// 预览窗口提交测试 |
|
||||
const previewForm = ref() |
|
||||
const previewSubmit = () => { |
|
||||
previewForm.value.validate((valid: boolean, fields: any) => { |
|
||||
if (valid) { |
|
||||
// alert('校验通过') |
|
||||
ElMessage.success('校验通过') |
|
||||
console.log(fields) |
|
||||
} else { |
|
||||
// alert('校验不通过') |
|
||||
// console.log('error submit!', fields) |
|
||||
ElMessage.error('校验不通过') |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
// 选择模板 |
|
||||
const selectTemplate = (data: FormData) => { |
|
||||
|
|
||||
state.formData = stringToObj(objToStringify(data)) |
|
||||
} |
|
||||
// 搜索设计时左侧快速添加字段 |
|
||||
const searchCheckField = (data: FormData) => { |
|
||||
state.formData.list.push(data) |
|
||||
} |
|
||||
getInitData() |
|
||||
// 从数据源点创建表单过来时,带有参数source |
|
||||
onMounted(() => { |
|
||||
if (route.source) { |
|
||||
formControlAttrEl.value.getFormFieldBySource(route.source) |
|
||||
} |
|
||||
}) |
|
||||
</script> |
</script> |
||||
<template> |
<template> |
||||
<div class="design-container"> |
<div class="app-container"> |
||||
<DragControl |
<div class="search"> |
||||
:formid="state.formOtherData.source" |
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> |
||||
@click-check="searchCheckField" |
<el-form-item label="关键字" prop="keywords"> |
||||
@click="selectTemplate" |
<el-input |
||||
/> |
v-model="queryParams.keywords" |
||||
<div class="main-body"> |
placeholder="表单名称" |
||||
|
clearable |
||||
<HeadTools @click="headToolClick" /> |
@keyup.enter="handleQuery" |
||||
<div v-loading="state.loading" class="main-form"> |
|
||||
<div v-if="state.formData.list.length === 0" class="empty-tips"> |
|
||||
从左侧拖拽来添加组件 |
|
||||
</div> |
|
||||
<FormDesign |
|
||||
:type="5" |
|
||||
:form-data="state.formData" |
|
||||
:dict="state.formDict" |
|
||||
/> |
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" @click="handleQuery" |
||||
|
><template #icon><i-ep-search /></template>搜索</el-button |
||||
|
> |
||||
|
<el-button @click="resetQuery"> |
||||
|
<template #icon><i-ep-refresh /></template> |
||||
|
重置</el-button |
||||
|
> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
</div> |
</div> |
||||
</div> |
<el-card shadow="never"> |
||||
<!--面版右侧--> |
<template #header> |
||||
<form-control-attr |
<el-button type="success" @click="openDialog()"><i-ep-plus />新增表单</el-button> |
||||
ref="formControlAttrEl" |
<el-button |
||||
v-model:formOtherData="state.formOtherData" |
type="danger" |
||||
:form-data="state.formData.form" |
:disabled="ids.length === 0" |
||||
:form-config="state.formData.config" |
@click="handleDelete()" |
||||
@open-dialog="openAceEditDrawer" |
> |
||||
/> |
<i-ep-delete />删除表单 |
||||
<ace-drawer |
|
||||
v-model="drawer.visible" |
|
||||
:title="drawer.title" |
|
||||
:direction="drawer.direction" |
|
||||
:content="drawer.content" |
|
||||
:code-type="drawer.codeType" |
|
||||
@before-close="drawerBeforeClose" |
|
||||
@confirm="dialogConfirm" |
|
||||
/> |
|
||||
<vue-file v-if="!['search'].includes(state.designType)" ref="vueFileEl" /> |
|
||||
<el-dialog v-model="state.previewVisible" title="预览" :fullscreen="true"> |
|
||||
<form-design |
|
||||
v-if="state.previewVisible" |
|
||||
ref="previewForm" |
|
||||
:form-data="state.formDataPreview" |
|
||||
:dict="state.formDict" |
|
||||
:type="1" |
|
||||
/> |
|
||||
<template #footer> |
|
||||
<div class="dialog-footer"> |
|
||||
<el-button size="small" type="primary" @click="previewSubmit"> |
|
||||
提交 |
|
||||
</el-button> |
</el-button> |
||||
<el-button size="small" @click="state.previewVisible = false"> |
|
||||
取消 |
|
||||
</el-button> |
|
||||
</div> |
|
||||
</template> |
</template> |
||||
</el-dialog> |
<el-table |
||||
|
v-loading="loading" |
||||
|
highlight-current-row |
||||
|
:data="contList" |
||||
|
border |
||||
|
@selection-change="handleSelectionChange" |
||||
|
> |
||||
|
<el-table-column fixed type="selection" width="55" align="center" /> |
||||
|
<el-table-column fixed label="表单名称" prop="name" /> |
||||
|
<el-table-column label="分类" align="center" width="150"> |
||||
|
<template #default="scope"> |
||||
|
<el-tag v-if="scope.row.classify === 1" effect="plain">表单</el-tag> |
||||
|
<el-tag v-else effect="plain">流程表单</el-tag> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="状态" align="center" width="100"> |
||||
|
<template #default="scope"> |
||||
|
<el-tag v-if="scope.row.states === 1" type="success">启用</el-tag> |
||||
|
<el-tag v-else type="info">禁用</el-tag> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="创建人" prop="creatername" width="140" /> |
||||
|
<el-table-column label="创建时间" prop="creatertime" /> |
||||
|
<el-table-column fixed="right" label="操作" align="center" width="280"> |
||||
|
<template #default="scope"> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
link |
||||
|
size="small" |
||||
|
@click.stop="setupCustomerForm(scope.row)" |
||||
|
><i-ep-Setting />设置</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
link |
||||
|
size="small" |
||||
|
@click.stop="setupCustomerForm(scope.row)" |
||||
|
><i-ep-MessageBox />数据结构</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
|
||||
|
type="primary" |
||||
|
link |
||||
|
size="small" |
||||
|
|
||||
|
><i-ep-edit />编辑</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
|
||||
|
type="danger" |
||||
|
link |
||||
|
size="small" |
||||
|
|
||||
|
><i-ep-delete />删除</el-button |
||||
|
> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
<pagination |
||||
|
v-if="total > 0" |
||||
|
v-model:total="total" |
||||
|
v-model:page="queryParams.page" |
||||
|
v-model:limit="queryParams.pagesize" |
||||
|
@pagination="handleQuery" |
||||
|
/> |
||||
|
</el-card> |
||||
</div> |
</div> |
||||
|
<el-drawer v-model="drawerOpenOrClose" title="I am the title" :with-header="false" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :size="drawerWith" class="drawerClass"> |
||||
|
<CreateForm v-model:draweropenclose="drawerOpenOrClose" :formconfigcont="formConfigCont" @handlequery="handleQuery" /> |
||||
|
</el-drawer> |
||||
</template> |
</template> |
||||
<style lang='scss' scoped> |
<style lang='scss' scoped> |
||||
|
.drawerClass{ |
||||
|
.el-drawer__body{ |
||||
|
padding: 0; |
||||
|
} |
||||
|
} |
||||
</style> |
</style> |
||||
|
|||||
Loading…
Reference in new issue