You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
9.5 KiB
352 lines
9.5 KiB
<!--
|
|
@ 作者: 秦东
|
|
@ 时间: 2023-07-19 08:33:29
|
|
@ 备注: 导出按钮
|
|
-->
|
|
<script lang='ts' setup>
|
|
import { ref, nextTick } from 'vue'
|
|
import Clipboard from 'clipboard'
|
|
import { ElMessage } from 'element-plus'
|
|
import { aceEdit } from '@/api/DesignForm/utils'
|
|
import { objToStringify } from '@/utils/DesignForm/form'
|
|
|
|
const visible = ref(false)
|
|
const editor = ref()
|
|
// 根据生成的json提取需要导入的组件,远程方法,检验方法
|
|
const getObjHtml = (obj: any) => {
|
|
let rulesMethods = ''
|
|
const sourceFun = ''
|
|
obj &&
|
|
obj.list.forEach((item: any) => {
|
|
if (item.customRules?.length) {
|
|
// 使用自定义校验方法
|
|
item.customRules.forEach((c: any) => {
|
|
if (c.type === 'methods' && c.methods) {
|
|
rulesMethods += `// todo 请完善${item.item.label}校验方法
|
|
provide("${c.methods}", (rule, value, callback) => {
|
|
if (value === '') {
|
|
callback(new Error('Please input the password again'))
|
|
} else if (value !== 'abc') {
|
|
callback(new Error("Two inputs don't match!"))
|
|
} else {
|
|
callback()
|
|
}
|
|
})`
|
|
}
|
|
})
|
|
}
|
|
/*if (item.config?.optionsType === 2 && item.config?.optionsFun) {
|
|
// 单选多选下拉等方法设值
|
|
// const optionsValue = ref([{label: "选项1", value: '1'}])
|
|
// provide("getCheckbox", optionsValue)
|
|
sourceFun += `// todo ${item.item.label}设置选项值\n`
|
|
sourceFun += ` const ${item.name}Option = ref([{label: "选项1", value: '1'}])\n`
|
|
sourceFun += ` provide("${item.config.optionsFun}", ${item.name}Option)\n`
|
|
}*/
|
|
})
|
|
return {
|
|
rulesMethods: rulesMethods,
|
|
sourceFun: sourceFun
|
|
}
|
|
}
|
|
const open = (obj: any) => {
|
|
visible.value = true
|
|
const getHtml = getObjHtml(obj)
|
|
const { addUrl, editUrl, requestUrl } = obj.config
|
|
if (requestUrl) {
|
|
// 从obj里删除使用props方式
|
|
delete obj.config.requestUrl
|
|
}
|
|
if (editUrl) {
|
|
// 从obj里删除使用props方式
|
|
delete obj.config.editUrl
|
|
}
|
|
if (addUrl) {
|
|
// 从obj里删除使用props方式
|
|
delete obj.config.addUrl
|
|
}
|
|
|
|
const html = `<template>
|
|
<div>
|
|
<ak-form
|
|
ref="formNameEl"
|
|
:type="formType"
|
|
:formData="formData"
|
|
requestUrl="${requestUrl}"
|
|
addUrl="${addUrl}"
|
|
editUrl="${editUrl}"
|
|
:beforeSubmit="beforeSubmit">
|
|
</ak-form>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { ref, computed, provide } from 'vue'
|
|
const formNameEl = ref()
|
|
const formData = ref(${objToStringify(obj)})
|
|
// todo 存在编辑时,可根据路由等参数设置当前表单模式 1新增 2编辑
|
|
const formType = computed(() => {
|
|
return 1
|
|
})
|
|
${getHtml.rulesMethods}
|
|
${getHtml.sourceFun}
|
|
// 表单提交时参数处理
|
|
const beforeSubmit = (params)=>{
|
|
// 如编辑时添加参数
|
|
// params.id='xxx'
|
|
return params
|
|
}
|
|
|
|
<\/script>`
|
|
nextTick(() => {
|
|
editor.value = aceEdit(html, 'editJsonCopy', 'html')
|
|
})
|
|
}
|
|
// 打开弹窗,导出表格数据
|
|
const openTable = (obj: any) => {
|
|
const openDialog = obj.config?.openType === 'dialog'
|
|
const dialogWidth = obj.config?.dialogWidth || '600px'
|
|
const requestUrl = obj.config?.requestUrl
|
|
if (requestUrl) {
|
|
// 从obj里删除使用props方式
|
|
delete obj.config.requestUrl
|
|
}
|
|
const deleteUrl = obj.config?.deleteUrl
|
|
if (deleteUrl) {
|
|
// 从obj里删除使用props方式
|
|
delete obj.config.deleteUrl
|
|
}
|
|
let formHtml = ''
|
|
let formContent = ''
|
|
let listBtn = ''
|
|
if (openDialog) {
|
|
// 弹窗打开
|
|
listBtn = `@btn-click="listBtnClick"`
|
|
formHtml = `<el-dialog
|
|
destroy-on-close
|
|
v-model="dialog.visible"
|
|
:title="dialog.title"
|
|
width="${dialogWidth}"
|
|
>
|
|
<ak-form
|
|
ref="formEl"
|
|
:formData="formData"
|
|
:dict="dialog.dict"
|
|
:type="dialog.formType"
|
|
requestUrl=""
|
|
addUrl=""
|
|
editUrl=""
|
|
:beforeSubmit="beforeSubmit"
|
|
:afterSubmit="afterSubmit"
|
|
@btn-click="dialogBtnClick"
|
|
></ak-form>
|
|
</el-dialog>`
|
|
formContent = `const formEl = ref()
|
|
// todo 表单数据可从设计表单导出vue文件或保存生成脚本
|
|
const formData = ref({list:[],form:{},config:{}})
|
|
const dialog = reactive({
|
|
visible: false,
|
|
title: '',
|
|
formType: 1,
|
|
dict: {},
|
|
editId: ''
|
|
})
|
|
const listBtnClick = (btn, row) => {
|
|
// 使用弹窗方式打开新增编辑
|
|
if (btn.key === 'add' || btn.key === 'edit') {
|
|
// 打开弹窗
|
|
dialog.visible = true
|
|
dialog.title = btn.key === 'add' ? '新增' : '编辑'
|
|
dialog.formType = btn.key === 'add' ? 1 : 2
|
|
dialog.editId = row && row.id
|
|
|
|
if (btn.key === 'add' && formData.value.config?.addLoad) {
|
|
// 添加时需要加载数据
|
|
nextTick(() => {
|
|
formEl.value.getData()
|
|
})
|
|
}
|
|
// 编辑,根据id加载
|
|
if (btn.key === 'edit') {
|
|
nextTick(() => {
|
|
// eslint-disable-next-line no-irregular-whitespace
|
|
// todo 当表单内容字段比较少,所需值从列表数据就可以获取
|
|
// formEl.value.setValue(row)
|
|
formEl.value.getData({ id: row.id })
|
|
})
|
|
}
|
|
}
|
|
}
|
|
// 提交表单前事件
|
|
const beforeSubmit = (params) => {
|
|
if(dialog.formType===2){ // 编辑模式下添加参数
|
|
params.id = dialog.editId
|
|
}
|
|
return params
|
|
}
|
|
// 提交表单后事件
|
|
const afterSubmit = (type) => {
|
|
if (type === 'success') {
|
|
// 添加成功,刷新列表数据
|
|
closeResetDialog()
|
|
tableListEl.value.getListData()
|
|
}
|
|
}
|
|
// 关闭弹窗并重置表单,否则下次打开会保留上次数据
|
|
const closeResetDialog = () => {
|
|
dialog.visible = false
|
|
dialog.editId = ''
|
|
// formEl.value.resetFields() // 重置表单
|
|
}
|
|
// 点击弹窗取消按钮时
|
|
const dialogBtnClick = (type) => {
|
|
if (type === 'reset') {
|
|
closeResetDialog()
|
|
}
|
|
}
|
|
`
|
|
}
|
|
visible.value = true
|
|
const html = `<template>
|
|
<div>
|
|
<ak-list
|
|
ref="tableListEl"
|
|
requestUrl="${requestUrl}"
|
|
deleteUrl="${deleteUrl}"
|
|
:searchData="searchData"
|
|
:tableData="tableData"
|
|
${listBtn}>
|
|
</ak-list>
|
|
${formHtml}
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
// import {useRoute, useRouter} from 'vue-router'
|
|
import { ref, nextTick,reactive } from 'vue'
|
|
// const route = useRoute()
|
|
// const router = useRouter()
|
|
const tableListEl = ref()
|
|
const searchData = ref({})
|
|
const tableData = ref(${objToStringify(obj)})
|
|
${formContent}
|
|
<\/script>`
|
|
nextTick(() => {
|
|
editor.value = aceEdit(html, 'editJsonCopy', 'html')
|
|
})
|
|
}
|
|
const openScreen = (obj: any) => {
|
|
visible.value = true
|
|
let styleCss = ''
|
|
let globalData = ''
|
|
let globalImport = ''
|
|
const style = obj.config.style
|
|
if (style) {
|
|
styleCss = `<style>
|
|
${style}
|
|
<\/style>`
|
|
}
|
|
if (obj.config.requestUrl) {
|
|
// 全局大屏数据
|
|
globalImport = `import { getGlobalData } from '@/views/design/dataScreen/getData'`
|
|
globalData = `const globalScreen = ref({})
|
|
provide('globalScreen', globalScreen)
|
|
const {requestUrl, afterResponse, beforeRequest, method} = screenData.value.config
|
|
getGlobalData(requestUrl, afterResponse, beforeRequest, method)
|
|
.then((res: any) => {
|
|
globalScreen.value = res
|
|
})`
|
|
}
|
|
const html = `<template>
|
|
<div :style="screenStyle" class="design-canvas">
|
|
<ak-screen
|
|
v-for="(element, index) in screenData.list"
|
|
:key="index"
|
|
:data="element"
|
|
></ak-screen>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, provide } from 'vue'
|
|
${globalImport}
|
|
const loading = ref(true)
|
|
const screenData = ref(${objToStringify(obj)})
|
|
const screenStyle = computed(() => {
|
|
const { width, height, background, primary } = screenData.value.config
|
|
return {
|
|
width: width,
|
|
height: height,
|
|
background: background,
|
|
color: primary,
|
|
position: 'relative'
|
|
}
|
|
})
|
|
${globalData}
|
|
<\/script>
|
|
${styleCss}`
|
|
nextTick(() => {
|
|
editor.value = aceEdit(html, 'editJsonCopy', 'html')
|
|
})
|
|
}
|
|
|
|
const copyData = (e: any) => {
|
|
nextTick(() => {
|
|
const clipboard: any = new Clipboard(e.target, {
|
|
text: () => {
|
|
return editor.value.getValue()
|
|
}
|
|
})
|
|
clipboard.on('success', function () {
|
|
ElMessage({
|
|
message: '复制成功!',
|
|
type: 'success'
|
|
})
|
|
clipboard.destroy()
|
|
})
|
|
clipboard.on('error', function () {
|
|
ElMessage.error('复制失败')
|
|
clipboard.destroy()
|
|
})
|
|
clipboard.onClick(e)
|
|
})
|
|
}
|
|
// 导出文件
|
|
const dialogExport = () => {
|
|
const content = 'data:text/csv;charset=utf-8,' + editor.value?.getValue()
|
|
const fileName = new Date().getTime() + '.vue'
|
|
const encodedUri = encodeURI(content)
|
|
const actions = document.createElement('a')
|
|
actions.setAttribute('href', encodedUri)
|
|
actions.setAttribute('download', fileName)
|
|
actions.click()
|
|
}
|
|
defineExpose({
|
|
open,
|
|
openTable,
|
|
openScreen
|
|
})
|
|
|
|
</script>
|
|
<template>
|
|
<el-dialog
|
|
v-model="visible"
|
|
title="导出vue文件"
|
|
class="export-dialog"
|
|
width="80%"
|
|
>
|
|
<div id="editJsonCopy"></div>
|
|
<template #footer>
|
|
<div class="dialog-footer">
|
|
<el-button size="small" type="primary" @click="copyData">
|
|
复制数据
|
|
</el-button>
|
|
<el-button type="primary" size="small" @click="dialogExport">
|
|
导出代码
|
|
</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
<style lang='scss' scoped>
|
|
|
|
</style>
|
|
|