|
@@ -0,0 +1,645 @@
|
|
|
+<template>
|
|
|
+ <div class="layout">
|
|
|
+ <h1 style="margin-top: 10px;margin-bottom: 10px;">弹窗配置</h1>
|
|
|
+ <div style="color: #505050;margin-bottom: 20px;">配置弹窗的表单项和功能</div>
|
|
|
+
|
|
|
+ <!-- 接口选择部分 -->
|
|
|
+ <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
|
|
|
+ <div>
|
|
|
+ <el-form :inline="true" @submit.stop.prevent>
|
|
|
+ <el-form-item label="接口地址" style="width: 60%;">
|
|
|
+ <el-input v-model="state.filter.name" placeholder="请输入接口地址" @keyup.enter="onQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="ele-Search" @click="onQuery"> 查询 </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-form :inline="true" @submit.stop.prevent>
|
|
|
+ <el-form-item label="弹窗接口来源" style="width: 70%;">
|
|
|
+ <el-select v-model="state.filter.api" placeholder="请选择弹窗接口来源" @change="onChange(state.filter.api)">
|
|
|
+ <el-option v-for="(value, key) in state.api" :key="key" :label="value.api+' '+value.summary" :value="value.api" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 弹窗功能配置 -->
|
|
|
+ <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
|
|
|
+ <div>
|
|
|
+ <el-form :inline="true" @submit.stop.prevent>
|
|
|
+ <el-form-item label="弹窗功能配置" style="width: 100%;"></el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-checkbox v-model="state.dialogConfig.hasTitle">显示标题</el-checkbox>
|
|
|
+ <el-checkbox v-model="state.dialogConfig.hasFooter">显示底部按钮</el-checkbox>
|
|
|
+ <el-checkbox v-model="state.dialogConfig.hasCancelBtn">显示取消按钮</el-checkbox>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-form :inline="true" @submit.stop.prevent>
|
|
|
+ <el-form-item label="弹窗宽度" style="width: 30%;">
|
|
|
+ <el-input v-model="state.dialogConfig.width" placeholder="例如: 500px"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="标题变量名" style="width: 30%;">
|
|
|
+ <el-input v-model="state.dialogConfig.titleVar" placeholder="例如: dialogTitle"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="显示变量名" style="width: 30%;">
|
|
|
+ <el-input v-model="state.dialogConfig.visibleVar" placeholder="例如: dialogVisible"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 表单项配置 -->
|
|
|
+ <el-card class="mt8" shadow="never" :body-style="{ paddingBottom: '0' }">
|
|
|
+ <div>
|
|
|
+ <el-form :inline="true" @submit.stop.prevent>
|
|
|
+ <el-form-item label="表单项配置" style="width: 100%;"></el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-table :data="state.formItems" style="width: 100%">
|
|
|
+ <el-table-column prop="name" label="字段名" width="120"></el-table-column>
|
|
|
+ <el-table-column prop="description" label="描述" width="180"></el-table-column>
|
|
|
+ <el-table-column label="是否包含" width="100">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-switch v-model="row.include" @change="changeItem(row)"></el-switch>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="表单类型" width="150">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-select v-model="row.type" placeholder="选择类型" @change="changeItemType(row)">
|
|
|
+ <el-option label="输入框" value="input"></el-option>
|
|
|
+ <el-option label="数字输入框" value="number"></el-option>
|
|
|
+ <el-option label="下拉框" value="select"></el-option>
|
|
|
+ <el-option label="日期选择器" value="date"></el-option>
|
|
|
+ <el-option label="日期时间选择器" value="datetime"></el-option>
|
|
|
+ <el-option label="日期范围" value="daterange"></el-option>
|
|
|
+ <el-option label="开关" value="switch"></el-option>
|
|
|
+ <el-option label="多选框" value="checkbox"></el-option>
|
|
|
+ <el-option label="单选框" value="radio"></el-option>
|
|
|
+ <el-option label="文本域" value="textarea"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="是否必填" width="100">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-switch v-model="row.required" @change="changeItem(row)"></el-switch>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="验证规则" width="150">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-select v-model="row.rule" placeholder="选择规则" @change="changeItemRule(row)">
|
|
|
+ <el-option label="无" value=""></el-option>
|
|
|
+ <el-option label="必填" value="required"></el-option>
|
|
|
+ <el-option label="邮箱" value="email"></el-option>
|
|
|
+ <el-option label="手机号" value="phone"></el-option>
|
|
|
+ <el-option label="数字" value="number"></el-option>
|
|
|
+ <el-option label="自定义" value="custom"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button size="small" @click="editItemOptions(row)">选项配置</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 生成按钮 -->
|
|
|
+ <div style="display: flex;justify-content: center;align-items: center;">
|
|
|
+ <el-button style="margin-top: 20px;width: 264px;height: 42px;" type="primary" @click="generateDialogCode">生成弹窗代码</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 代码预览弹窗 -->
|
|
|
+ <el-dialog v-model="state.codePreviewVisible" title="弹窗代码预览" width="70%" top="5vh">
|
|
|
+ <el-tabs type="border-card">
|
|
|
+ <el-tab-pane label="弹窗模板">
|
|
|
+ <pre>{{ state.generatedCode.template }}</pre>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="脚本部分">
|
|
|
+ <pre>{{ state.generatedCode.script }}</pre>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane label="样式部分">
|
|
|
+ <pre>{{ state.generatedCode.style }}</pre>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="state.codePreviewVisible = false">关闭</el-button>
|
|
|
+ <el-button type="primary" @click="downloadCode">下载代码</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 选项配置弹窗 -->
|
|
|
+ <el-dialog v-model="state.optionsDialogVisible" title="选项配置">
|
|
|
+ <el-form>
|
|
|
+ <el-form-item label="字段名">
|
|
|
+ <el-input v-model="state.currentItem.name" disabled></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="选项列表">
|
|
|
+ <el-button type="primary" @click="addOption">添加选项</el-button>
|
|
|
+ <div v-for="(option, index) in state.currentItem.options" :key="index" style="margin-top: 10px;">
|
|
|
+ <el-input v-model="option.label" placeholder="选项标签" style="width: 200px; margin-right: 10px;"></el-input>
|
|
|
+ <el-input v-model="option.value" placeholder="选项值" style="width: 200px; margin-right: 10px;"></el-input>
|
|
|
+ <el-button type="danger" @click="removeOption(index)">删除</el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="state.optionsDialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="saveOptions">保存</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { reactive, onMounted } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+
|
|
|
+interface ApiItem {
|
|
|
+ api: string
|
|
|
+ summary: string
|
|
|
+ method: string
|
|
|
+ requestBody?: {
|
|
|
+ content?: {
|
|
|
+ 'application/json'?: {
|
|
|
+ schema?: {
|
|
|
+ $ref?: string
|
|
|
+ properties?: Record<string, any>
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+interface FormItem {
|
|
|
+ name: string
|
|
|
+ description: string
|
|
|
+ type: string
|
|
|
+ format?: string
|
|
|
+ include: boolean
|
|
|
+ required: boolean
|
|
|
+ rule: string
|
|
|
+ options?: Array<{ label: string, value: string }>
|
|
|
+}
|
|
|
+
|
|
|
+const state = reactive({
|
|
|
+ loading: false,
|
|
|
+ filter: {
|
|
|
+ name: 'http://dev.hsfuel.com:8070/app/swagger/app/swagger.json',
|
|
|
+ api: ''
|
|
|
+ },
|
|
|
+ api: [] as ApiItem[],
|
|
|
+ swaggerData: null as any,
|
|
|
+ dialogConfig: {
|
|
|
+ hasTitle: true,
|
|
|
+ hasFooter: true,
|
|
|
+ hasCancelBtn: true,
|
|
|
+ width: '500px',
|
|
|
+ titleVar: 'dialogTitle',
|
|
|
+ visibleVar: 'dialogVisible'
|
|
|
+ },
|
|
|
+ formItems: [] as FormItem[],
|
|
|
+ codePreviewVisible: false,
|
|
|
+ generatedCode: {
|
|
|
+ template: '',
|
|
|
+ script: '',
|
|
|
+ style: ''
|
|
|
+ },
|
|
|
+ optionsDialogVisible: false,
|
|
|
+ currentItem: {
|
|
|
+ name: '',
|
|
|
+ description: '',
|
|
|
+ type: '',
|
|
|
+ options: [] as Array<{ label: string, value: string }>
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 从接口获取数据
|
|
|
+const onQuery = async () => {
|
|
|
+ try {
|
|
|
+ state.loading = true
|
|
|
+ const response = await fetch(state.filter.name)
|
|
|
+ const swaggerJson = await response.json()
|
|
|
+ state.swaggerData = swaggerJson
|
|
|
+ state.api = []
|
|
|
+ const { paths } = swaggerJson
|
|
|
+
|
|
|
+ for (const path in paths) {
|
|
|
+ if ('post' in paths[path] || 'put' in paths[path]) {
|
|
|
+ const method = paths[path].post ? 'post' : 'put'
|
|
|
+ const operation = paths[path][method]
|
|
|
+
|
|
|
+ state.api.push({
|
|
|
+ api: path,
|
|
|
+ summary: operation.summary || '',
|
|
|
+ method: method.toUpperCase(),
|
|
|
+ requestBody: operation.requestBody
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessage.success('接口加载成功')
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取接口失败:', error)
|
|
|
+ ElMessage.error('获取接口失败')
|
|
|
+ } finally {
|
|
|
+ state.loading = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 根据$ref获取schema定义
|
|
|
+const getSchemaByRef = (ref: string) => {
|
|
|
+ if (!state.swaggerData || !ref) return null
|
|
|
+ const refPath = ref.replace('#/', '').split('/')
|
|
|
+ let current = state.swaggerData
|
|
|
+ for (const path of refPath) {
|
|
|
+ current = current[path]
|
|
|
+ if (!current) return null
|
|
|
+ }
|
|
|
+ return current
|
|
|
+}
|
|
|
+
|
|
|
+// 解析请求体属性
|
|
|
+const parseRequestBodyProperties = (apiItem: ApiItem) => {
|
|
|
+ if (!apiItem.requestBody?.content?.['application/json']?.schema) return []
|
|
|
+
|
|
|
+ const schema = apiItem.requestBody.content['application/json'].schema
|
|
|
+ let properties = {}
|
|
|
+ let requiredFields: string[] = []
|
|
|
+
|
|
|
+ if (schema.$ref) {
|
|
|
+ const refSchema = getSchemaByRef(schema.$ref)
|
|
|
+ if (refSchema?.properties) {
|
|
|
+ properties = refSchema.properties
|
|
|
+ requiredFields = refSchema.required || []
|
|
|
+ }
|
|
|
+ } else if (schema.properties) {
|
|
|
+ properties = schema.properties
|
|
|
+ requiredFields = schema.required || []
|
|
|
+ }
|
|
|
+
|
|
|
+ return Object.entries(properties).map(([name, prop]: [string, any]) => {
|
|
|
+ const formItem: FormItem = {
|
|
|
+ name,
|
|
|
+ description: prop.description || name,
|
|
|
+ type: prop.type || 'string',
|
|
|
+ format: prop.format,
|
|
|
+ include: true,
|
|
|
+ required: requiredFields.includes(name),
|
|
|
+ rule: requiredFields.includes(name) ? 'required' : ''
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据类型和format设置默认的表单组件类型
|
|
|
+ if (formItem.type === 'string') {
|
|
|
+ if (formItem.format === 'date-time') {
|
|
|
+ formItem.type = 'datetime'
|
|
|
+ } else if (formItem.format === 'date') {
|
|
|
+ formItem.type = 'date'
|
|
|
+ } else if (prop.enum) {
|
|
|
+ formItem.type = 'select'
|
|
|
+ formItem.options = prop.enum.map((value: string) => ({
|
|
|
+ label: value,
|
|
|
+ value
|
|
|
+ }))
|
|
|
+ } else if (prop.maxLength > 100) {
|
|
|
+ formItem.type = 'textarea'
|
|
|
+ }
|
|
|
+ } else if (formItem.type === 'integer' || formItem.type === 'number') {
|
|
|
+ formItem.type = 'number'
|
|
|
+ } else if (formItem.type === 'boolean') {
|
|
|
+ formItem.type = 'switch'
|
|
|
+ }
|
|
|
+
|
|
|
+ return formItem
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 选择接口后解析请求体
|
|
|
+const onChange = (apiPath: string) => {
|
|
|
+ if (!apiPath) {
|
|
|
+ state.formItems = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const selectedApi = state.api.find(item => item.api === apiPath)
|
|
|
+ if (!selectedApi) return
|
|
|
+
|
|
|
+ state.formItems = parseRequestBodyProperties(selectedApi)
|
|
|
+}
|
|
|
+
|
|
|
+const changeItem = (item: FormItem) => {
|
|
|
+ console.log('表单项变更:', item)
|
|
|
+}
|
|
|
+
|
|
|
+const changeItemType = (item: FormItem) => {
|
|
|
+ console.log('表单项类型变更:', item)
|
|
|
+ // 如果是选择类型,添加默认选项
|
|
|
+ if ((item.type === 'select' || item.type === 'radio' || item.type === 'checkbox') && !item.options) {
|
|
|
+ item.options = [{ label: '选项1', value: '1' }, { label: '选项2', value: '2' }]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const changeItemRule = (item: FormItem) => {
|
|
|
+ console.log('验证规则变更:', item)
|
|
|
+}
|
|
|
+
|
|
|
+// 编辑选项配置
|
|
|
+const editItemOptions = (item: FormItem) => {
|
|
|
+ if (!['select', 'radio', 'checkbox'].includes(item.type)) {
|
|
|
+ ElMessage.warning('当前字段类型不支持选项配置')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ state.currentItem = {
|
|
|
+ name: item.name,
|
|
|
+ description: item.description,
|
|
|
+ type: item.type,
|
|
|
+ options: item.options ? [...item.options] : []
|
|
|
+ }
|
|
|
+ state.optionsDialogVisible = true
|
|
|
+}
|
|
|
+
|
|
|
+// 添加选项
|
|
|
+const addOption = () => {
|
|
|
+ state.currentItem.options.push({
|
|
|
+ label: '',
|
|
|
+ value: ''
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 删除选项
|
|
|
+const removeOption = (index: number) => {
|
|
|
+ state.currentItem.options.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
+// 保存选项
|
|
|
+const saveOptions = () => {
|
|
|
+ const item = state.formItems.find(item => item.name === state.currentItem.name)
|
|
|
+ if (item) {
|
|
|
+ item.options = state.currentItem.options.filter(opt => opt.label && opt.value)
|
|
|
+ }
|
|
|
+ state.optionsDialogVisible = false
|
|
|
+ ElMessage.success('选项配置已保存')
|
|
|
+}
|
|
|
+
|
|
|
+// 生成弹窗代码
|
|
|
+const generateDialogCode = () => {
|
|
|
+ if (!state.filter.api) {
|
|
|
+ ElMessage.error('请选择弹窗接口来源')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const selectedItems = state.formItems.filter(item => item.include)
|
|
|
+ if (selectedItems.length === 0) {
|
|
|
+ ElMessage.error('请至少选择一个表单项')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成模板代码
|
|
|
+ let templateCode = `<el-dialog
|
|
|
+ v-model="${state.dialogConfig.visibleVar}"
|
|
|
+ :title="${state.dialogConfig.titleVar}"
|
|
|
+ width="${state.dialogConfig.width}"
|
|
|
+ :before-close="handleDialogClose"
|
|
|
+>
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="100px"
|
|
|
+ >\n`
|
|
|
+
|
|
|
+ // 添加表单项
|
|
|
+ selectedItems.forEach(item => {
|
|
|
+ templateCode += ` <el-form-item label="${item.description}" prop="${item.name}">\n`
|
|
|
+
|
|
|
+ switch (item.type) {
|
|
|
+ case 'input':
|
|
|
+ templateCode += ` <el-input v-model="formData.${item.name}" placeholder="请输入${item.description}"></el-input>\n`
|
|
|
+ break
|
|
|
+ case 'number':
|
|
|
+ templateCode += ` <el-input-number v-model="formData.${item.name}" placeholder="请输入${item.description}"></el-input-number>\n`
|
|
|
+ break
|
|
|
+ case 'select':
|
|
|
+ templateCode += ` <el-select v-model="formData.${item.name}" placeholder="请选择${item.description}" clearable>\n`
|
|
|
+ if (item.options) {
|
|
|
+ item.options.forEach(opt => {
|
|
|
+ templateCode += ` <el-option label="${opt.label}" value="${opt.value}"></el-option>\n`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ templateCode += ` </el-select>\n`
|
|
|
+ break
|
|
|
+ case 'date':
|
|
|
+ templateCode += ` <el-date-picker
|
|
|
+ v-model="formData.${item.name}"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择${item.description}"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ ></el-date-picker>\n`
|
|
|
+ break
|
|
|
+ case 'datetime':
|
|
|
+ templateCode += ` <el-date-picker
|
|
|
+ v-model="formData.${item.name}"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="请选择${item.description}"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ ></el-date-picker>\n`
|
|
|
+ break
|
|
|
+ case 'switch':
|
|
|
+ templateCode += ` <el-switch v-model="formData.${item.name}"></el-switch>\n`
|
|
|
+ break
|
|
|
+ case 'textarea':
|
|
|
+ templateCode += ` <el-input v-model="formData.${item.name}" type="textarea" :rows="3" placeholder="请输入${item.description}"></el-input>\n`
|
|
|
+ break
|
|
|
+ case 'radio':
|
|
|
+ templateCode += ` <el-radio-group v-model="formData.${item.name}">\n`
|
|
|
+ if (item.options) {
|
|
|
+ item.options.forEach(opt => {
|
|
|
+ templateCode += ` <el-radio label="${opt.value}">${opt.label}</el-radio>\n`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ templateCode += ` </el-radio-group>\n`
|
|
|
+ break
|
|
|
+ case 'checkbox':
|
|
|
+ templateCode += ` <el-checkbox-group v-model="formData.${item.name}">\n`
|
|
|
+ if (item.options) {
|
|
|
+ item.options.forEach(opt => {
|
|
|
+ templateCode += ` <el-checkbox label="${opt.value}">${opt.label}</el-checkbox>\n`
|
|
|
+ })
|
|
|
+ }
|
|
|
+ templateCode += ` </el-checkbox-group>\n`
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ templateCode += ` <el-input v-model="formData.${item.name}" placeholder="请输入${item.description}"></el-input>\n`
|
|
|
+ }
|
|
|
+
|
|
|
+ templateCode += ` </el-form-item>\n\n`
|
|
|
+ })
|
|
|
+
|
|
|
+ // 添加底部按钮
|
|
|
+ if (state.dialogConfig.hasFooter) {
|
|
|
+ templateCode += ` </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">\n`
|
|
|
+
|
|
|
+ if (state.dialogConfig.hasCancelBtn) {
|
|
|
+ templateCode += ` <el-button @click="handleDialogClose">取消</el-button>\n`
|
|
|
+ }
|
|
|
+
|
|
|
+ templateCode += ` <el-button type="primary" @click="handleSubmit">确定</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+</el-dialog>`
|
|
|
+ } else {
|
|
|
+ templateCode += ` </el-form>
|
|
|
+</el-dialog>`
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成脚本代码
|
|
|
+ let scriptCode = `<script setup lang="ts">
|
|
|
+import { reactive, ref } from 'vue'
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
+
|
|
|
+const ${state.dialogConfig.visibleVar} = ref(false)
|
|
|
+const ${state.dialogConfig.titleVar} = ref('')
|
|
|
+const formRef = ref<FormInstance>()
|
|
|
+const formData = reactive({\n`
|
|
|
+
|
|
|
+ // 添加表单数据
|
|
|
+ selectedItems.forEach(item => {
|
|
|
+ if (item.type === 'checkbox') {
|
|
|
+ scriptCode += ` ${item.name}: [] as string[],\n`
|
|
|
+ } else {
|
|
|
+ scriptCode += ` ${item.name}: ${item.type === 'number' ? '0' : item.type === 'switch' ? 'false' : '""'},\n`
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ scriptCode += `})
|
|
|
+
|
|
|
+// 验证规则
|
|
|
+const rules = reactive<FormRules>({\n`
|
|
|
+
|
|
|
+ // 添加验证规则
|
|
|
+ selectedItems.forEach(item => {
|
|
|
+ if (item.required || item.rule) {
|
|
|
+ scriptCode += ` ${item.name}: [\n`
|
|
|
+
|
|
|
+ if (item.required) {
|
|
|
+ scriptCode += ` { required: true, message: '${item.type === 'select' || item.type === 'radio' || item.type === 'checkbox' ? '请选择' : '请输入'}${item.description}', trigger: '${item.type === 'select' || item.type === 'radio' || item.type === 'checkbox' ? 'change' : 'blur'}' },\n`
|
|
|
+ }
|
|
|
+
|
|
|
+ if (item.rule === 'email') {
|
|
|
+ scriptCode += ` { type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' },\n`
|
|
|
+ } else if (item.rule === 'phone') {
|
|
|
+ scriptCode += ` { pattern: /^1[3-9]\\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },\n`
|
|
|
+ } else if (item.rule === 'number') {
|
|
|
+ scriptCode += ` { type: 'number', message: '请输入数字', trigger: 'blur' },\n`
|
|
|
+ }
|
|
|
+
|
|
|
+ scriptCode += ` ],\n`
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ scriptCode += `})
|
|
|
+
|
|
|
+// 打开弹窗
|
|
|
+const openDialog = (title: string, data?: any) => {
|
|
|
+ ${state.dialogConfig.titleVar}.value = title
|
|
|
+ if (data) {
|
|
|
+ Object.assign(formData, data)
|
|
|
+ }
|
|
|
+ ${state.dialogConfig.visibleVar}.value = true
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭弹窗
|
|
|
+const handleDialogClose = () => {
|
|
|
+ formRef.value?.resetFields()
|
|
|
+ ${state.dialogConfig.visibleVar}.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 提交表单
|
|
|
+const handleSubmit = () => {
|
|
|
+ formRef.value?.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ // 提交逻辑
|
|
|
+ console.log('表单数据:', formData)
|
|
|
+ handleDialogClose()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+</` + `script>`
|
|
|
+
|
|
|
+ // 生成样式代码
|
|
|
+ const styleCode = `<style scoped>
|
|
|
+.dialog-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+</style>`
|
|
|
+
|
|
|
+ state.generatedCode = {
|
|
|
+ template: templateCode,
|
|
|
+ script: scriptCode,
|
|
|
+ style: styleCode
|
|
|
+ }
|
|
|
+
|
|
|
+ state.codePreviewVisible = true
|
|
|
+}
|
|
|
+
|
|
|
+// 下载代码
|
|
|
+const downloadCode = () => {
|
|
|
+ const content = `<template>
|
|
|
+${state.generatedCode.template}
|
|
|
+</template>
|
|
|
+
|
|
|
+${state.generatedCode.script}
|
|
|
+
|
|
|
+${state.generatedCode.style}`
|
|
|
+
|
|
|
+ const blob = new Blob([content], { type: 'text/plain' })
|
|
|
+ const url = URL.createObjectURL(blob)
|
|
|
+ const link = document.createElement('a')
|
|
|
+ link.href = url
|
|
|
+ link.download = 'DialogComponent.vue'
|
|
|
+ document.body.appendChild(link)
|
|
|
+ link.click()
|
|
|
+ document.body.removeChild(link)
|
|
|
+ URL.revokeObjectURL(url)
|
|
|
+
|
|
|
+ ElMessage.success('代码下载成功')
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ // 初始化加载一些示例数据
|
|
|
+ onChange('')
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.layout {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 0px 8px 8px 8px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+pre {
|
|
|
+ background: #f5f5f5;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: auto;
|
|
|
+ max-height: 60vh;
|
|
|
+}
|
|
|
+
|
|
|
+.mt8 {
|
|
|
+ margin-top: 8px;
|
|
|
+}
|
|
|
+</style>
|