Browse Source

自定义表单列表

v1
超级管理员 2 years ago
parent
commit
6e6edd9ad7
  1. 4
      index.html
  2. 31
      src/api/DesignForm/requestapi.ts
  3. 23
      src/api/DesignForm/type.ts
  4. 3
      src/api/DesignForm/types.ts
  5. 125
      src/components/DesignForm/formControlAttr.vue
  6. 1576
      src/components/DesignForm/formControlAttres.vue
  7. 16
      src/components/DesignForm/public/form/form.vue
  8. 2
      src/components/DesignForm/public/form/formGroup.vue
  9. 8
      src/components/DesignForm/public/headTools.vue
  10. 1
      src/utils/DesignForm/form.ts
  11. 562
      src/views/sysworkflow/codepage/createform.vue
  12. 554
      src/views/sysworkflow/codepage/index.vue

4
index.html

@ -15,8 +15,8 @@
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/docs/static/plugins/ace/ace.js"></script>
<script type="module" src="/docs/static/plugins/ace/ext-language_tools.js"></script>
<script src="/docs/static/plugins/tinymce/tinymce.min.js?v=6.1.2"></script>
<script src="/docs/static/plugins/echarts.min.js"></script>
<script type="module" src="/docs/static/plugins/tinymce/tinymce.min.js?v=6.1.2"></script>
<script type="module" src="/docs/static/plugins/echarts.min.js"></script>
</body>
</html>

31
src/api/DesignForm/requestapi.ts

@ -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
});
}

23
src/api/DesignForm/type.ts

@ -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;
}

3
src/api/DesignForm/types.ts

@ -92,7 +92,8 @@ export interface formData{
list: any[];
form: {
size: any;
name:any
name:any,
formName:any
};
config: any;
events?:any

125
src/components/DesignForm/formControlAttr.vue

@ -1,7 +1,7 @@
<!--
@ 作者: 秦东
@ 时间: 2023-07-17 11:51:07
@ 备注: 右侧属性
@ 时间: 2023-08-28 08:31:58
@ 备注:
-->
<script lang='ts' setup>
import { reactive, computed, toRefs, ref, watch, inject } from 'vue'
@ -9,13 +9,10 @@ import { getRequest } from '@/api/DesignForm'
import { useDesignFormStore } from '@/store/DesignForm/designForm'
import validate from './validate'
import { ElMessage } from 'element-plus'
import {
formatNumber
} from '@/api/DesignForm/utils'
import { formatNumber } from '@/api/DesignForm/utils'
import { PublicAtrr } from '@/api/DesignForm/types'
const props = withDefaults(
const props = withDefaults( //
defineProps<{
formData: any
formConfig: any
@ -31,20 +28,44 @@ const props = withDefaults(
}
}
)
//
const emits = defineEmits<{
(e: 'openDialog', data: any): void
(e: 'update:formOtherData', data: any): void
//(e: 'update:formData', data: any): void
//(e: 'update:formConfig', data: any): void
}>()
// eslint-disable-next-line vue/no-dupe-keys
const { formConfig, formData } = toRefs(props)
const store = useDesignFormStore() as any
//const route = useRoute()
const controlData = computed(() => {
return store.controlAttr
})
const dataSourceOption = ref([])
const designType = inject('formDesignType')
const state = reactive({
dataSourceList: [],
customRulesList: [
...validate,
{
type: 'rules',
label: '自定义正则'
},
{
type: 'methods',
label: '自定义方法'
}
], //
isSearch: designType === 'search',
tooltip: {
css: '当前表单应用页的样式,类似于.vue文件中的style scoped中的样式',
dict: '数据字典,用于匹配多选组、下拉选择等,提供动态获取Options接口字典数据,一般不设置,从接口dict获取。json格式:"sex":{"0":"男","1":"女"}',
rules:
"可参考UI组件表单校验,<a href='https://element-plus.gitee.io/zh-CN/component/form.html#%E8%A1%A8%E5%8D%95%E6%A0%A1%E9%AA%8C' target='_blank' style='color:red'>详情点击</a>",
props: '可添加当前组件所有prop属性及事件方法'
},
tabsName: 'second'
})
const formAttr = computed(() => {
const isSearch = state.isSearch
return [
@ -693,11 +714,10 @@ const attrList = computed(() => {
path: 'config.style',
placeholder: '显示风格(预览查看效果)',
type: 'select',
dict: { default: 'default', simple: 'simple', label:'', name:'' },
vShow: ['tinymce'],
dict: { default: 'default', simple: 'simple' },
vShow: ['tinymce']
}
]
)
])
//
return temp.filter((item: any) => {
let hasFilter = true
@ -717,30 +737,7 @@ const attrList = computed(() => {
return []
}
})
const designType = inject('formDesignType')
const state = reactive({
dataSourceList: [],
customRulesList: [
...validate,
{
type: 'rules',
label: '自定义正则'
},
{
type: 'methods',
label: '自定义方法'
}
], //
isSearch: designType === 'search',
tooltip: {
css: '当前表单应用页的样式,类似于.vue文件中的style scoped中的样式',
dict: '数据字典,用于匹配多选组、下拉选择等,提供动态获取Options接口字典数据,一般不设置,从接口dict获取。json格式:"sex":{"0":"男","1":"女"}',
rules:
"可参考UI组件表单校验,<a href='https://element-plus.gitee.io/zh-CN/component/form.html#%E8%A1%A8%E5%8D%95%E6%A0%A1%E9%AA%8C' target='_blank' style='color:red'>详情点击</a>",
props: '可添加当前组件所有prop属性及事件方法'
},
tabsName: 'second'
})
watch(
() => store.activeKey,
(val: string) => {
@ -990,7 +987,8 @@ const addRulesFast = () => {
}
//
const delAddRules = (index: number) => {
controlData.value.customRules &&controlData.value.customRules.splice(index, 1)
controlData.value.customRules &&
controlData.value.customRules.splice(index, 1)
}
//
const editFormStyle = (tooltip: string) => {
@ -1035,15 +1033,15 @@ const getFormFieldBySource = (id?: string) => {
const getDataSource = () => {
//
if (!state.isSearch) {
getRequest('sourceList').then((res: any) => {
dataSourceOption.value = res.data.list
//dataSourceOption.value.unshift({ name: '', id: '' })
// console.log("res.data---->",res.data)
})
// getRequest('sourceList').then((res: any) => {
// dataSourceOption.value = res.data.list
// //dataSourceOption.value.unshift({ name: '', id: '' })
// })
}
}
//
const formAttrChange = (obj: any, val?: any) => {
console.log("表单属性修改--->",obj,val,{ [obj.key]: obj.value })
if (obj.key === 'source') {
getFormFieldBySource(obj.value) //
//
@ -1055,6 +1053,7 @@ const formAttrChange = (obj: any, val?: any) => {
'update:formOtherData',
Object.assign(props.formOtherData, { [obj.key]: obj.value })
)
formData.value[obj.key] = obj.value
return
}
if (obj.path === 'config') {
@ -1095,14 +1094,13 @@ defineExpose({ getFormFieldBySource })
<el-tabs v-model="state.tabsName">
<el-tab-pane label="字段配置" name="first">
<el-form size="small" class="form">
<div class="h3"><h3>通用属性</h3></div>
<div class=""><h3>通用属性</h3></div>
<template v-for="(item, index) in attrList" :key="index">
<el-form-item :label="item.label">
<el-select
v-if="item.type === 'select'"
v-model="item.value"
:placeholder="item.placeholder"
v-model="item.value"
:filterable="item.path === 'name'"
:allow-create="item.path === 'name'"
:clearable="item.clearable"
@ -1124,9 +1122,8 @@ defineExpose({ getFormFieldBySource })
/>
<el-input
v-else
v-model="item.value"
:type="item.inputStyle"
v-model="item.value"
:placeholder="item.placeholder"
@input="controlChange(item, $event)"
/>
@ -1171,7 +1168,6 @@ defineExpose({ getFormFieldBySource })
label="联动结果"
>
<el-radio-group
v-model="controlData.config.linkResult"
class="option-radio"
>
@ -1254,9 +1250,7 @@ defineExpose({ getFormFieldBySource })
</el-form-item>
</div>
<el-form-item>
<el-button @click="addSelectOption"
>{{ controlData.type === 'cascader' ? '编辑' : '新增' }}
</el-button>
<el-button @click="addSelectOption">{{ controlData.type === 'cascader' ? '编辑' : '新增' }}</el-button>
</el-form-item>
</template>
<template v-else>
@ -1303,8 +1297,7 @@ defineExpose({ getFormFieldBySource })
'请求前处理事件,参数(data,route,form) data请求参数,route页面路由,form表单值'
)
"
>beforeRequest
</el-button>
>beforeRequest</el-button>
<el-button
@click="
optionsEvent(
@ -1312,8 +1305,7 @@ defineExpose({ getFormFieldBySource })
'请求返回结束处理;,也可为字符串,如opt=formatTest'
)
"
>afterResponse
</el-button>
>afterResponse</el-button>
</el-form-item>
</template>
<el-form-item label="尝试转换value值为">
@ -1434,8 +1426,8 @@ defineExpose({ getFormFieldBySource })
<el-form size="small" class="form">
<el-form-item
v-for="(item, index) in formAttr.filter(item => !item.hide)"
:key="index"
:label="item.label"
:key="index"
>
<el-select
v-if="item.type === 'select'"
@ -1447,10 +1439,11 @@ defineExpose({ getFormFieldBySource })
@change="formAttrChange(item)"
>
<el-option
v-for="opts in item.options"
:key="opts.label || opts.name"
:label="opts.label || opts.name"
:value="formatNumber(opts.value ?? opts.id)"
v-for="opt in item.options"
:key="opt.label || opt.name"
:label="opt.label || opt.name"
:value="formatNumber(opt.value ?? opt.id)"
/>
</el-select>
<el-switch
@ -1467,7 +1460,8 @@ defineExpose({ getFormFieldBySource })
</el-form-item>
<el-form-item v-if="!state.isSearch">
<template #label
>添加时获取请求
>
添加时获取请求
<el-tooltip
content="新增表单数据时,从接口获取新增初始数据"
placement="top"
@ -1486,7 +1480,8 @@ defineExpose({ getFormFieldBySource })
</el-form-item>
<el-form-item>
<el-button @click="editFormStyle(state.tooltip.css)"
>编辑表单样式
>
编辑表单样式
<el-tooltip :content="state.tooltip.css" placement="top">
<el-icon>
<QuestionFilled />
@ -1494,7 +1489,8 @@ defineExpose({ getFormFieldBySource })
</el-tooltip>
</el-button>
<el-button @click="editFormDict(state.tooltip.dict)"
>设置数据字典
>
设置数据字典
<el-tooltip :content="state.tooltip.dict" placement="top">
<el-icon>
<QuestionFilled />
@ -1508,7 +1504,6 @@ defineExpose({ getFormFieldBySource })
<el-input
v-model="formConfig.addUrl"
placeholder="表单提交的url,非特殊不需要设置"
/>
</el-form-item>
<el-form-item label="修改数据保存url">

1576
src/components/DesignForm/formControlAttres.vue

File diff suppressed because it is too large

16
src/components/DesignForm/public/form/form.vue

@ -53,14 +53,18 @@ const props = withDefaults(
dict: () => {
return {}
},
isSearch: false
isSearch: false,
issave:{
type:Boolean,
default:true
},
}
)
const emits = defineEmits<{
(e: 'btnClick', type: string): void
(e: 'change', val: any): void //
(e: 'update:issave', type: boolean): void
}>()
const route = useRoute()
const router = useRouter()
@ -93,6 +97,14 @@ const setWindowEvent = (bool?: boolean) => {
}
}
}
watch(
() => props.formData,
() => {
console.log("监听数据----->1",props.formData)
emits('update:issave', false)
},
{ deep: true }
)
watch(
() => props.formData.config,
() => {

2
src/components/DesignForm/public/form/formGroup.vue

@ -423,7 +423,7 @@ const dataList = ref<any>(props.data)
</div>
<div class="drag-move icon-move"></div>
</div>
<div class="tooltip">{{ element.name }}</div>
<div class="tooltip" style="display: none;">{{ element.name }}</div>
</template>

8
src/components/DesignForm/public/headTools.vue

@ -31,8 +31,9 @@ const btnList = computed(() => {
{ icon: 'del', label: '清空', key: 1 },
{ icon: 'eye', label: '预览', key: 2 },
{ icon: 'json', label: '生成脚本预览', key: 3 },
{ icon: 'vue', label: '导出vue文件', key: 4 },
{ icon: 'save', label: '保存', key: 5 }
// { icon: 'vue', label: 'vue', key: 4 },
{ icon: 'save', label: '保存', key: 5 },
{ icon: 'close', label: '关闭', key: 6 }
]
if (props.showKey?.length) {
// key
@ -54,10 +55,11 @@ const btnList = computed(() => {
<slot></slot>
<el-button
link
type="primary"
@click="btnClick(item.icon)"
v-for="item in btnList"
:key="item.icon"
:type="item.key==6?'danger':item.key==5?'success':'primary'"
>
<i :class="['icon-' + item.icon]"></i>{{ item.label }}
</el-button>

1
src/utils/DesignForm/form.ts

@ -57,6 +57,7 @@ export function obj2string(o: any) {
}
export function objToStringify(obj: any, isBeautify?: boolean) {
// console.log("EDITTYPE--->",EDITTYPE,isBeautify)
if (EDITTYPE === 'javascript') {
if (isBeautify) {
return jsBeautify('opt=' + obj2string(obj), {

562
src/views/sysworkflow/codepage/createform.vue

@ -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) => {
// jsonstate.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) {
// pathid=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>

554
src/views/sysworkflow/codepage/index.vue

@ -1,423 +1,185 @@
<!--
@ 作者: 秦东
@ 时间: 2023-05-26 10:35:30
@ 备注:
@ 时间: 2023-08-28 14:47:07
@ 备注: 表单设计
-->
<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 { SearchForm,customerFormCont,customerFormConfig } from "@/api/DesignForm/type";
import { getCustomerFormList,getProductionMarkForm } from '@/api/DesignForm/requestapi'
//
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'
const layoutStore = useLayoutStore()
layoutStore.changeBreadcrumb([{ label: '系统工具' }, { label: '表单设计' }])
import CreateForm from '@/views/sysworkflow/codepage/createform.vue'
const store = useDesignFormStore()
const router = useRouter()
const route: any = useRoute().query || {}
const state = reactive<formStruct>({
formData: {
list: [],
form: {
size: 'default',
name:''
},
config: {}
},
editor: {},
loading: false,
formDataPreview: {},
previewVisible: false, //
designType: route.type, // search
formDict: {},
formOtherData: {
source: route.source || '',
formName: '未命名表单'
}
})
const drawer = reactive<DrawerStruct>({
visible: false,
type: '',
title: '',
codeType: '',
direction: undefined, //rtl / ltr
callback: ''
const queryParams = reactive<SearchForm>({
page: 1,
pagesize:15
});
const ids = ref<number[]>([]); //
const loading =ref(false); //
const drawerOpenOrClose = ref(false);
const total = ref(0); //
const contList = ref<customerFormCont[]>()
const drawerWith = ref<number>(0);
const formConfigCont = reactive<customerFormConfig>({
formname:"",
formlogo:""
})
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
//
function handleQuery(){
getCustomerFormList(queryParams)
.then(({ data }) => {
console.log("搜索表单-->",data);
total.value = data.total
contList.value = data.list
})
.catch((res: any) => {
// console.log(res)
ElMessage.error(res.message || '加载异常')
state.loading = false
.finally(() => {})
}
//
function resetQuery(){}
//
function openDialog(){
getProductionMarkForm()
.then(({data})=>{
formConfigCont.formlogo = data.formlogo
formConfigCont.formname = data.formname
console.log("新增表单",formConfigCont)
})
}
}
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: '可编辑修改或将已生成的脚本粘贴进来'
.finally(()=>{
drawerOpenOrClose.value = true;
})
break
case 'save':
saveData()
break
case 'vue':
vueFileEl.value.open(state.formData)
break
}
}
//
const dialogConfirm = (editVal: string) => {
// jsonstate.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) {
// pathid=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
}
})
//
function handleDelete(){}
/**
* 行checkbox change事件
*/
function handleSelectionChange(selection: any) {
ids.value = selection.map((item: any) => item.id);
}
//
const selectTemplate = (data: FormData) => {
//
function setupCustomerForm(cont:customerFormCont){
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)
}
handleQuery();
drawerWith.value = window.innerWidth - 220
});
window.addEventListener("resize", function(){
drawerWith.value = window.innerWidth -220
console.log("搜索表单-->",window.innerWidth);
})
//
</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
:type="5"
:form-data="state.formData"
:dict="state.formDict"
<div class="app-container">
<div class="search">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="keywords">
<el-input
v-model="queryParams.keywords"
placeholder="表单名称"
clearable
@keyup.enter="handleQuery"
/>
</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>
<!--面版右侧-->
<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-card shadow="never">
<template #header>
<el-button type="success" @click="openDialog()"><i-ep-plus />新增表单</el-button>
<el-button
type="danger"
:disabled="ids.length === 0"
@click="handleDelete()"
>
<i-ep-delete />删除表单
</el-button>
<el-button size="small" @click="state.previewVisible = false">
取消
</el-button>
</div>
</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>
<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>
<style lang='scss' scoped>
.drawerClass{
.el-drawer__body{
padding: 0;
}
}
</style>

Loading…
Cancel
Save