From 38a626b58763f903f5580d49854a420681925092 Mon Sep 17 00:00:00 2001
From: 康鲁杰 <60095866+KangLujie@users.noreply.github.com>
Date: 星期二, 24 六月 2025 18:06:15 +0800
Subject: [PATCH] 创建公共模版

---
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java                        |    1 
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java |   87 ++++
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java                       |    3 
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java            |   20 +
 ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue                                                    |  224 +++++++++++
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java    |   70 +++
 ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml                                       |    0 
 ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml                               |   27 +
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java                |   19 +
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java                  |   28 +
 ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts                                                               |   14 
 ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts                                                                 |   45 ++
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java         |   16 
 ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx                                                               |   86 ++++
 ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue                                                              |  404 +++++++++++++++++++++
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java               |   22 +
 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java          |   27 +
 17 files changed, 1,081 insertions(+), 12 deletions(-)

diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java
new file mode 100644
index 0000000..5af3c15
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java
@@ -0,0 +1,70 @@
+package org.ruoyi.pageDesigner.controller;
+
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.ruoyi.common.core.domain.R;
+import org.ruoyi.common.web.core.BaseController;
+import org.ruoyi.core.page.PageQuery;
+import org.ruoyi.core.page.TableDataInfo;
+import org.ruoyi.pageDesigner.domain.*;
+import org.ruoyi.pageDesigner.service.PageDesignerTemplateService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 14:41:24
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/page-designer-template")
+public class PageDesignerTemplateController extends BaseController {
+
+    private final PageDesignerTemplateService service;
+
+    /**
+     * 鑾峰彇椤甸潰璁捐鍒楄〃
+     */
+    @GetMapping("/list")
+    public TableDataInfo<PageDesignerTemplateVo> list(PageDesignerTemplateDTO dto, PageQuery pageQuery) {
+        return service.selectPagelistAll(dto, pageQuery);
+    }
+
+    /**
+     * 鑾峰彇椤甸潰璁捐璇︽儏
+     */
+    @GetMapping("/{id}")
+    public R<PageDesignerTemplate> getInfo(@PathVariable Long id) {
+        return R.ok(service.getDetail(id));
+    }
+
+    /**
+     * 鏂板椤甸潰璁捐
+     */
+    @PostMapping
+    public R<Void> add(@Valid @RequestBody PageDesignerTemplateDTO dto) {
+        service.add(dto);
+        return R.ok("鏂板鎴愬姛");
+    }
+
+    /**
+     * 淇敼椤甸潰璁捐
+     */
+    @PutMapping
+    public R<Void> update(@Valid @RequestBody PageDesignerTemplateDTO dto) {
+        service.updatePage(dto);
+        return R.ok("淇敼鎴愬姛");
+    }
+
+    /**
+     * 鍒犻櫎椤甸潰璁捐
+     */
+    @DeleteMapping
+    public R<Void> remove(@RequestBody List<Long> ids) {
+        service.deleteByIds(ids);
+        return R.ok("鍒犻櫎鎴愬姛");
+    }
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java
index 977f6fb..7224b38 100644
--- a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java
@@ -5,9 +5,6 @@
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import org.ruoyi.core.domain.BaseEntity;
-import org.ruoyi.system.domain.SysUser;
-
-import java.util.List;
 
 /**
  * @author kanglujie
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java
new file mode 100644
index 0000000..338c97a
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java
@@ -0,0 +1,28 @@
+package org.ruoyi.pageDesigner.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.ruoyi.core.domain.BaseEntity;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:24:05
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("PAGE_DESIGNER_TEMPLATE")
+public class PageDesignerTemplate extends BaseEntity {
+    @TableId(value = "ID")
+    private Long id;
+    @TableField(value = "PAGE_ID")
+    private Long pageId;
+    @TableField("FORM_DATA")
+    private String formData;
+    @TableField(value = "DEL_FLAG")
+    @TableLogic
+    private String delFlag;
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java
new file mode 100644
index 0000000..f2be0b8
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java
@@ -0,0 +1,22 @@
+package org.ruoyi.pageDesigner.domain;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.ruoyi.core.domain.BaseEntity;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:23:35
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = PageDesignerTemplate.class, reverseConvertGenerate = false)
+public class PageDesignerTemplateDTO extends BaseEntity {
+    private Long id;
+    private Long pageId;
+    private String formData;
+    private String delFlag;
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java
new file mode 100644
index 0000000..9974206
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java
@@ -0,0 +1,19 @@
+package org.ruoyi.pageDesigner.domain;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:23:35
+ */
+@Data
+@AutoMapper(target = PageDesignerTemplate.class)
+public class PageDesignerTemplateVo implements Serializable {
+    private Long id;
+    private Long pageId;
+    private String formData;
+    private String delFlag;
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java
index 3b98968..54bb8fa 100644
--- a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java
@@ -2,7 +2,6 @@
 
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
-import org.ruoyi.core.domain.BaseEntity;
 import org.ruoyi.system.domain.vo.SysMenuVo;
 
 import java.io.Serializable;
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java
new file mode 100644
index 0000000..c0a54d1
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java
@@ -0,0 +1,20 @@
+package org.ruoyi.pageDesigner.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.ruoyi.pageDesigner.domain.PageDesignerTemplate;
+import org.ruoyi.pageDesigner.domain.PageDesignerTemplateVo;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:34:48
+ */
+@Mapper
+public interface PageDesignerTemplateMapper extends BaseMapper<PageDesignerTemplate> {
+    Page<PageDesignerTemplateVo> selectPagelistAll(@Param("page") Page<PageDesignerTemplate> page, @Param(Constants.WRAPPER) Wrapper<PageDesignerTemplate> queryWrapper);
+
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java
new file mode 100644
index 0000000..a0e2bdb
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java
@@ -0,0 +1,27 @@
+package org.ruoyi.pageDesigner.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.ruoyi.core.page.PageQuery;
+import org.ruoyi.core.page.TableDataInfo;
+import org.ruoyi.pageDesigner.domain.*;
+
+import java.util.List;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:35:56
+ */
+public interface PageDesignerTemplateService extends IService<PageDesignerTemplate> {
+
+    void add(PageDesignerTemplateDTO dto);
+
+    void updatePage(PageDesignerTemplateDTO dto);
+
+    List<PageDesignerTemplate> listAll(String keyword);
+
+    PageDesignerTemplate getDetail(Long id);
+
+    void deleteByIds(List<Long> ids);
+
+    TableDataInfo<PageDesignerTemplateVo> selectPagelistAll(PageDesignerTemplateDTO dto, PageQuery pageQuery);
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java
index b8e42d8..e42337c 100644
--- a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java
@@ -54,15 +54,15 @@
         return TableDataInfo.build(page);
     }
     private Wrapper<PageDesigner> buildQueryWrapper(PageDesignerDTO pageDesignerDTO) {
-        //Map<String, Object> params = pageDesignerDTO.getParams();
+        Map<String, Object> params = pageDesignerDTO.getParams();
         QueryWrapper<PageDesigner> wrapper = Wrappers.query();
-        //wrapper.eq("del_flag", UserConstants.USER_NORMAL)
-        //        .eq(ObjectUtil.isNotNull(pageDesignerDTO.getId()), "id", pageDesignerDTO.getId())
-        //        .like(StringUtils.isNotBlank(pageDesignerDTO.getName()), "name", pageDesignerDTO.getName())
-        //        .eq(StringUtils.isNotBlank(pageDesignerDTO.getStatus()), "status", pageDesignerDTO.getStatus())
-        //        .between(params.get("beginTime") != null && params.get("endTime") != null,
-        //                "create_time", params.get("beginTime"), params.get("endTime"))
-        //;
+        wrapper.eq("del_flag", UserConstants.USER_NORMAL)
+                .eq(ObjectUtil.isNotNull(pageDesignerDTO.getId()), "id", pageDesignerDTO.getId())
+                .like(StringUtils.isNotBlank(pageDesignerDTO.getName()), "name", pageDesignerDTO.getName())
+                .eq(StringUtils.isNotBlank(pageDesignerDTO.getStatus()), "status", pageDesignerDTO.getStatus())
+                .between(params.get("beginTime") != null && params.get("endTime") != null,
+                        "create_time", params.get("beginTime"), params.get("endTime"))
+        ;
         return wrapper;
     }
     @Override
diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java
new file mode 100644
index 0000000..4901a54
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java
@@ -0,0 +1,87 @@
+package org.ruoyi.pageDesigner.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import org.ruoyi.core.page.PageQuery;
+import org.ruoyi.core.page.TableDataInfo;
+import org.ruoyi.pageDesigner.domain.*;
+import org.ruoyi.pageDesigner.mapper.PageDesignerMapper;
+import org.ruoyi.pageDesigner.mapper.PageDesignerTemplateMapper;
+import org.ruoyi.pageDesigner.service.PageDesignerService;
+import org.ruoyi.pageDesigner.service.PageDesignerTemplateService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author kanglujie
+ * @date 2025-06-23 17:36:29
+ */
+@Service
+@RequiredArgsConstructor
+public class PageDesignerTemplateServiceImpl extends ServiceImpl<PageDesignerTemplateMapper, PageDesignerTemplate>
+        implements PageDesignerTemplateService {
+
+    private final ObjectMapper objectMapper;
+
+    @Override
+    public void add(PageDesignerTemplateDTO dto) {
+        PageDesignerTemplate entity = convertToEntity(dto);
+        this.save(entity);
+    }
+
+    @Override
+    public void updatePage(PageDesignerTemplateDTO dto) {
+        PageDesignerTemplate entity = convertToEntity(dto);
+        this.updateById(entity);
+    }
+
+    @Override
+    public TableDataInfo<PageDesignerTemplateVo> selectPagelistAll(PageDesignerTemplateDTO dto, PageQuery pageQuery) {
+        Page<PageDesignerTemplateVo> page = baseMapper.selectPagelistAll(pageQuery.build(), this.buildQueryWrapper(dto));
+        return TableDataInfo.build(page);
+    }
+    private Wrapper<PageDesignerTemplate> buildQueryWrapper(PageDesignerTemplateDTO dto) {
+        //Map<String, Object> params = pageDesignerDTO.getParams();
+        QueryWrapper<PageDesignerTemplate> wrapper = Wrappers.query();
+        //wrapper.eq("del_flag", UserConstants.USER_NORMAL)
+        //        .eq(ObjectUtil.isNotNull(pageDesignerDTO.getId()), "id", pageDesignerDTO.getId())
+        //        .like(StringUtils.isNotBlank(pageDesignerDTO.getName()), "name", pageDesignerDTO.getName())
+        //        .eq(StringUtils.isNotBlank(pageDesignerDTO.getStatus()), "status", pageDesignerDTO.getStatus())
+        //        .between(params.get("beginTime") != null && params.get("endTime") != null,
+        //                "create_time", params.get("beginTime"), params.get("endTime"))
+        //;
+        return wrapper;
+    }
+    @Override
+    public List<PageDesignerTemplate> listAll(String keyword) {
+        LambdaQueryWrapper<PageDesignerTemplate> wrapper = new LambdaQueryWrapper<>();
+        wrapper.like(keyword != null, PageDesignerTemplate::getPageId, keyword);
+        return this.list(wrapper);
+    }
+
+    @Override
+    public PageDesignerTemplate getDetail(Long id) {
+        return this.getById(id);
+    }
+
+    @Override
+    public void deleteByIds(List<Long> ids) {
+        this.removeByIds(ids);
+    }
+
+    private PageDesignerTemplate convertToEntity(PageDesignerTemplateDTO dto) {
+        PageDesignerTemplate entity = new PageDesignerTemplate();
+        entity.setId(dto.getId());
+        entity.setFormData(dto.getFormData());
+        entity.setDelFlag(dto.getDelFlag());
+        entity.setPageId(dto.getPageId());
+        return entity;
+    }
+}
diff --git a/ruoyi-modules/sc-page-designer/src/main/resources/mapper/SysUserMapper.xml b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml
similarity index 100%
rename from ruoyi-modules/sc-page-designer/src/main/resources/mapper/SysUserMapper.xml
rename to ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml
diff --git a/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml
new file mode 100644
index 0000000..8c23389
--- /dev/null
+++ b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.ruoyi.pageDesigner.mapper.PageDesignerTemplateMapper">
+
+    <!-- 缁撴灉鏄犲皠 -->
+    <resultMap type="org.ruoyi.pageDesigner.domain.PageDesignerTemplateVo" id="PageDesignerTemplateResult">
+        <id property="id" column="id"/>
+        <result property="pageId" column="page_id"/>
+        <result property="formData" column="form_data"/>
+        <result property="delFlag" column="del_flag"/>
+    </resultMap>
+
+    <select id="selectPagelistAll" resultMap="PageDesignerTemplateResult">
+        SELECT
+        id,
+        page_id,
+        form_data,
+        del_flag
+        FROM page_designer_template
+        <where>
+            ${ew.sqlSegment}
+        </where>
+    </select>
+
+</mapper>
diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts b/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts
new file mode 100644
index 0000000..0b91788
--- /dev/null
+++ b/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts
@@ -0,0 +1,45 @@
+import { requestClient } from '#/api/request';
+import type { Template } from './model';
+
+enum Api {
+  templateAdd = '/page-designer-template',
+  templateUpdate = '/page-designer-template',
+  templateList = '/page-designer-template/list',
+  templateInfo = '/page-designer-template',
+  templateRemove = '/page-designer-template',
+}
+
+/**
+ * 鏂板椤甸潰璁捐
+ */
+export function templateAdd(data: any) {
+  return requestClient.post(Api.templateAdd, data);
+}
+
+/**
+ * 淇敼椤甸潰璁捐
+ */
+export function templateUpdate(data: any) {
+  return requestClient.put(Api.templateUpdate, data);
+}
+
+/**
+ * 鑾峰彇椤甸潰璁捐鍒楄〃
+ */
+export function templateList(params?: any) {
+  return requestClient.get(Api.templateList, { params });
+}
+
+/**
+ * 鑾峰彇椤甸潰璁捐璇︽儏
+ */
+export function templateInfo(id: string | number) {
+  return requestClient.get(`${Api.templateInfo}/${id}`);
+}
+
+/**
+ * 鍒犻櫎椤甸潰璁捐
+ */
+export function templateRemove(ids: string[] | number[]) {
+  return requestClient.delete(Api.templateRemove, { data: ids });
+} 
\ No newline at end of file
diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts b/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts
new file mode 100644
index 0000000..ab9d827
--- /dev/null
+++ b/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts
@@ -0,0 +1,14 @@
+export interface Template {
+  id?: string | number;          // 涓婚敭
+  formData: string;                  // 妯$増鍚嶇О
+  pageDesignId: string | number; // 鍏宠仈鐨勯〉闈㈣璁D
+  createTime?: string;           // 鍒涘缓鏃堕棿
+  updateTime?: string;           // 鏇存柊鏃堕棿
+  pageDesign?: {                 // 鍏宠仈鐨勯〉闈㈣璁′俊鎭�
+    id: string | number;
+    name: string;
+    formJson?: string;
+    showColumn?: string;
+    actionsFunc?: string;
+  } | null;
+} 
\ No newline at end of file
diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx b/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx
new file mode 100644
index 0000000..62d35c1
--- /dev/null
+++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx
@@ -0,0 +1,86 @@
+import type { FormSchemaGetter } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'name',
+    label: '妯$増鍚嶇О',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '姝e父', value: '1' },
+        { label: '鍋滅敤', value: '0' },
+      ],
+    },
+    fieldName: 'status',
+    label: '妯$増鐘舵��',
+  },
+];
+
+export const columns = [
+  {
+    title: '濮撳悕',
+    dataIndex: 'name',
+    auth: 'test', // 鏍规嵁鏉冮檺鎺у埗鏄惁鏄剧ず: 鏃犳潈闄愶紝涓嶆樉绀�
+  }
+];
+
+export const drawerSchema = () => [
+  {
+    component: 'Input',
+    fieldName: 'name',
+    label: '妯$増鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Select',
+    fieldName: 'pageDesignId',
+    label: '椤甸潰璁捐',
+    componentProps: {
+      allowClear: true,
+      showSearch: true,
+      filterOption: (input: string, option: any) => {
+        return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
+      },
+    },
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    fieldName: 'templateType',
+    label: '妯$増绫诲瀷',
+    componentProps: {
+      options: [
+        { label: '鍒楄〃椤�', value: 'list' },
+        { label: '琛ㄥ崟椤�', value: 'form' },
+        { label: '璇︽儏椤�', value: 'detail' },
+        { label: '浠〃鏉�', value: 'dashboard' },
+      ],
+    },
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    fieldName: 'status',
+    label: '鐘舵��',
+    componentProps: {
+      options: [
+        { label: '姝e父', value: '1' },
+        { label: '鍋滅敤', value: '0' },
+      ],
+    },
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Input',
+    fieldName: 'remark',
+    label: '澶囨敞',
+    componentProps: {
+      type: 'textarea',
+      rows: 2,
+    },
+  },
+]; 
\ No newline at end of file
diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue b/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue
new file mode 100644
index 0000000..d198eaa
--- /dev/null
+++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue
@@ -0,0 +1,404 @@
+<template>
+  <Page v-if="isAdmin" :auto-content-height="true">
+    <BasicTable 
+      :key="tableKey"
+      :table-title="pageDesignDetail?.name || '妯℃澘鍒楄〃'"
+      :grid-options="gridOptions"
+    >
+      <template #toolbar-tools>
+        <Space>
+          <a-button v-if="showAction('add')" type="primary" @click="handleAdd">鏂板</a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button v-if="showAction('edit')" @click="handleEdit(row)">缂栬緫</ghost-button>
+          <Popconfirm v-if="showAction('delete')" :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+            <ghost-button danger @click.stop="">鍒犻櫎</ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <TemplateDrawer ref="templateModalRef" @reload="tableApi.query()" />
+  </Page>
+  <Fallback v-else description="鎮ㄦ病鏈夐〉闈㈢殑璁块棶鏉冮檺" status="403" />
+</template>
+
+<script setup lang="ts">
+import type { VbenFormProps } from '@vben/common-ui';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+import { computed, ref, onMounted, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { useAccess } from '@vben/access';
+import { Fallback, Page } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+import { Popconfirm, Space, Spin as ASpin } from 'ant-design-vue';
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { columns as baseColumns, querySchema } from './data';
+import TemplateDrawer from './template-drawer.vue';
+import { templateList, templateRemove } from '#/api/tool/template';
+import { pageInfo } from '#/api/tool/page-designer';
+
+const route = useRoute();
+const router = useRouter();
+const pageId = ref<string | number>('');
+const pageDesignDetail = ref<any>(null); // 椤甸潰璁捐璇︽儏
+const loading = ref(true); // 鍔犺浇涓�
+
+// 鍔ㄦ�乧olumns
+const dynamicColumns = ref([
+  { field: 'id', title: 'ID', width: 100 },
+  { field: 'formData', title: '琛ㄥ崟鏁版嵁', minWidth: 160 },
+  { field: 'action', title: '鎿嶄綔', width: 160, slots: { default: 'action' } }
+]);
+
+// 鐢ㄤ簬琛ㄦ牸閲嶆柊娓叉煋鐨� key
+const tableKey = ref(0);
+
+// 鏇存柊鍔ㄦ�佸垪鐨勫嚱鏁�
+function updateDynamicColumns() {
+  if (!pageDesignDetail.value || !pageDesignDetail.value.showColumn || !pageDesignDetail.value.formJson) {
+    console.log('浣跨敤榛樿鍒�');
+    return;
+  }
+
+  try {
+    const showFields = JSON.parse(pageDesignDetail.value.showColumn);
+    const formFields = JSON.parse(pageDesignDetail.value.formJson);
+    const cols = showFields.map(field => {
+      const fieldDef = formFields.find(f => f.field === field);
+      return {
+        field: field,
+        title: fieldDef ? fieldDef.title : field,
+        minWidth: 120,
+        align: 'center',
+      };
+    });
+
+    cols.push({
+      field: 'action',
+      title: '鎿嶄綔',
+      width: 160,
+      slots: { default: 'action' },
+    });
+
+    dynamicColumns.value = cols;
+    gridOptions.value = { ...gridOptions.value, columns: cols };
+    tableKey.value++;
+  } catch (error) {
+    const fallbackCols = [
+      { field: 'id', title: 'ID', width: 100 },
+      { field: 'formData', title: '琛ㄥ崟鏁版嵁', minWidth: 160 },
+      { field: 'action', title: '鎿嶄綔', width: 160, slots: { default: 'action' } }
+    ];
+    dynamicColumns.value = fallbackCols;
+    gridOptions.value = { ...gridOptions.value, columns: fallbackCols };
+    tableKey.value++;
+  }
+}
+
+
+// 鍔ㄦ�佹寜閽�
+function showAction(action: string) {
+  if (!pageDesignDetail.value || !pageDesignDetail.value.actionsFunc) {
+    return true;
+  }
+  
+  try {
+    const actions = JSON.parse(pageDesignDetail.value.actionsFunc);
+    if (!Array.isArray(actions)) {
+      console.warn('actionsFunc 涓嶆槸鏁扮粍鏍煎紡:', pageDesignDetail.value.actionsFunc);
+      return true;
+    }
+    
+    return actions.includes(action);
+  } catch (error) {
+    console.error('瑙f瀽 actionsFunc 澶辫触:', error);
+    return true;
+  }
+}
+
+// 鑾峰彇 pageId锛屽吋瀹� meta銆乸arams銆乹uery
+function getPageId() {
+  const pageId = (
+    (route.meta && (route.meta as any).pageId) ||
+    route.params.pageId ||
+    route.query.pageId ||
+    ''
+  );
+  
+  // 纭繚杩斿洖鐨勬槸瀛楃涓叉垨鏁板瓧
+  return pageId ? String(pageId) : '';
+}
+
+onMounted(() => {
+  const initialPageId = getPageId();
+  console.log('鑾峰彇鍒扮殑 pageId:', initialPageId);
+  
+  if (initialPageId) {
+    pageId.value = initialPageId;
+    handlePageIdChange();
+  } else {
+    loading.value = false;
+  }
+});
+
+// 鐩戝惉璺敱鍙樺寲锛岃嚜鍔ㄦ洿鏂� pageId
+watch(
+  () => [route.meta.pageId, route.params.pageId, route.query.pageId],
+  (newValues, oldValues) => {
+    // 鍙湁褰撳�肩湡姝e彉鍖栨椂鎵嶅鐞�
+    if (JSON.stringify(newValues) !== JSON.stringify(oldValues)) {
+      const newPageId = getPageId();
+      console.log('璺敱鍙樺寲鍚� pageId:', newPageId);
+      
+      // 鍙湁褰� pageId 鐪熸鍙樺寲鏃舵墠鏇存柊
+      if (newPageId !== pageId.value) {
+        pageId.value = newPageId;
+        handlePageIdChange();
+        tableApi.query();
+      }
+    }
+  },
+  { deep: true }
+);
+
+// pageId鍙樺寲鏃惰嚜鍔ㄨ幏鍙栭〉闈㈣璁¤鎯�
+async function handlePageIdChange() {
+  loading.value = true;
+  console.log(`[handlePageIdChange] 寮�濮嬪鐞� pageId: ${pageId.value}`);
+  try {
+    if (pageId.value) {
+      const detail = await pageInfo(pageId.value);
+      console.log('[handlePageIdChange] 鑾峰彇鍒扮殑椤甸潰璁捐璇︽儏 (detail):', JSON.parse(JSON.stringify(detail)));
+      
+      // 澶勭悊鏁版嵁锛岄伩鍏嶅惊鐜紩鐢�
+      const safeDetail = {
+        id: detail.id,
+        name: detail.name,
+        menuId: detail.menuId,
+        status: detail.status,
+        remark: detail.remark,
+        formJson: detail.formJson,
+        showColumn: detail.showColumn,
+        actionsFunc: detail.actionsFunc,
+        createTime: detail.createTime,
+        updateTime: detail.updateTime,
+        createBy: detail.createBy,
+        updateBy: detail.updateBy,
+        createDept: detail.createDept
+      };
+      
+      pageDesignDetail.value = safeDetail;
+      console.log('[handlePageIdChange] 璁剧疆鐨� pageDesignDetail.value:', JSON.parse(JSON.stringify(pageDesignDetail.value)));
+      updateDynamicColumns();
+    } else {
+      pageDesignDetail.value = null;
+      updateDynamicColumns();
+    }
+  } catch (error) {
+    console.error('[handlePageIdChange] 鑾峰彇椤甸潰璁捐璇︽儏澶辫触:', error);
+    pageDesignDetail.value = null;
+    updateDynamicColumns();
+  } finally {
+    loading.value = false;
+  }
+}
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions = ref<VxeGridProps>({
+  columns: dynamicColumns.value,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: true,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        try {
+          console.log('鏌ヨ鍙傛暟:', { page, formValues });
+          const queryParams = {
+            pageNum: page.currentPage,
+            pageSize: page.pageSize,
+            ...formValues,
+          };
+          if (pageId.value) {
+            queryParams.pageDesignId = pageId.value;
+          }
+          const resp = await templateList(queryParams);
+          // 澶勭悊姣忔潯 row 鐨� formData
+          const rows = (resp.rows || []).map(row => {
+            let formData = {};
+            try {
+              if (row.formData) {
+                formData = JSON.parse(row.formData);
+                console.log('瑙f瀽鍚庣殑 formData:', formData);
+                // 鍒犻櫎鍘熷鐨� formData 瀛楁锛屽洜涓烘垜浠凡缁忓睍寮�瀹冪殑鍐呭
+                const { formData: _, ...restRow } = row;
+                // 杩斿洖灞曞紑鍚庣殑鏁版嵁
+                return {
+                  ...restRow,
+                  ...formData
+                };
+              }
+            } catch (e) {
+              console.error('瑙f瀽 formData 澶辫触:', e);
+            }
+            return row;
+          });
+          console.log('澶勭悊鍚庣殑 rows:', rows);
+          return {
+            rows,
+            total: resp.total || 0,
+          };
+        } catch (error) {
+          console.error('鏌ヨ妯℃澘鍒楄〃澶辫触:', error);
+          return {
+            rows: [],
+            total: 0,
+          };
+        }
+      },
+    },
+  },
+  rowConfig: {
+    keyField: 'id',
+  },
+  id: 'tool-template-index',
+  columnConfig: { resizable: true },
+});
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions: computed(() => ({
+    ...gridOptions.value,
+    columns: dynamicColumns.value
+  })),
+});
+
+const templateModalRef = ref();
+const generateModalRef = ref();
+
+function handleAdd() {
+  // 濡傛灉鏈� pageId锛屼紶閫掔粰鏂板
+  const params: any = { update: false };
+  if (pageId.value) {
+    params.pageDesignId = pageId.value;
+  }
+  // 鍔ㄦ�佷紶閫抐ormJson锛屽厛JSON.parse锛屼繚璇佹槸绾璞�
+  if (pageDesignDetail.value && pageDesignDetail.value.formJson) {
+    try {
+      const formJson = JSON.parse(pageDesignDetail.value.formJson);
+      params.formJson = formJson;
+      console.log('浼犻�掑姩鎬佽〃鍗曞瓧娈�:', formJson);
+    } catch (error) {
+      console.error('瑙f瀽 formJson 澶辫触:', error);
+      params.formJson = undefined;
+    }
+  }
+  templateModalRef.value.open(params);
+}
+
+function handleEdit(record) {
+  // 缂栬緫鏃朵篃浼犻�抐ormJson锛屽厛JSON.parse锛屼繚璇佹槸绾璞�
+  const params: any = { 
+    id: record.id, 
+    update: true,
+    pageDesignId: pageId.value,  // 浼犻�掗〉闈㈣璁D
+    record: record  // 浼犻�掑畬鏁寸殑璁板綍鏁版嵁
+  };
+  
+  if (pageDesignDetail.value && pageDesignDetail.value.formJson) {
+    try {
+      const formJson = JSON.parse(pageDesignDetail.value.formJson);
+      params.formJson = formJson;
+      console.log('缂栬緫鏃朵紶閫掓暟鎹�:', { record, formJson, pageDesignId: pageId.value });
+    } catch (error) {
+      console.error('瑙f瀽 formJson 澶辫触:', error);
+      params.formJson = undefined;
+    }
+  }
+  templateModalRef.value.open(params);
+}
+
+async function handleDelete(row: any) {
+  try {
+    await templateRemove([row.id]);
+    await tableApi.query();
+  } catch (error) {
+    console.error('鍒犻櫎妯℃澘澶辫触:', error);
+  }
+}
+
+function handleGenerate(row) {
+  try {
+    generateModalRef.value.open(row);
+  } catch (error) {
+    console.error('鎵撳紑鐢熸垚椤甸潰澶辫触:', error);
+  }
+}
+
+function handlePreview(row) {
+  try {
+    // 鎵撳紑棰勮绐楀彛
+    const url = `/tool/template/preview/${row.id}`;
+    window.open(url, '_blank');
+  } catch (error) {
+    console.error('鎵撳紑棰勮澶辫触:', error);
+  }
+}
+
+const { hasAccessByRoles } = useAccess();
+const isAdmin = computed(() => {
+  try {
+    return hasAccessByRoles(['admin', 'superadmin']);
+  } catch (error) {
+    console.error('妫�鏌ユ潈闄愬け璐�:', error);
+    return false;
+  }
+});
+
+const isReady = computed(() => {
+  try {
+    // 绠�鍖栧垽鏂�昏緫锛屽噺灏戜笉蹇呰鐨勮绠�
+    return !!(pageDesignDetail.value && !loading.value);
+  } catch (error) {
+    console.error('妫�鏌ラ〉闈㈠噯澶囩姸鎬佸け璐�:', error);
+    return false;
+  }
+});
+</script>
+
+<style scoped>
+.template-page {
+  background: #f5f6fa;
+  padding: 16px;
+  min-height: 100vh;
+  height: 100vh;
+  overflow: hidden;
+}
+
+/* 纭繚琛ㄦ牸瀹瑰櫒楂樺害绋冲畾 */
+:deep(.vxe-table--main-wrapper) {
+  height: 600px !important;
+}
+
+/* 纭繚鍒嗛〉鍣ㄤ綅缃浐瀹� */
+:deep(.vxe-pager) {
+  position: sticky;
+  bottom: 0;
+  background: white;
+  z-index: 10;
+}
+</style> 
\ No newline at end of file
diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue b/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue
new file mode 100644
index 0000000..da11342
--- /dev/null
+++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue
@@ -0,0 +1,224 @@
+<script setup lang="ts">
+import { computed, ref, watch, nextTick } from 'vue';
+import { Modal, message, FormItem } from 'ant-design-vue';
+import { $t } from '@vben/locales';
+import { templateAdd, templateUpdate, templateInfo } from '#/api/tool/template';
+import { pageList } from '#/api/tool/page-designer';
+import formCreate from '@form-create/element-ui';
+
+interface ModalProps {
+  id?: number | string;
+  update: boolean;
+  pageDesignId?: string | number;
+  formJson?: any;
+}
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const modalVisible = ref(false);
+const modalLoading = ref(false);
+const currentEditId = ref<string | number>('');
+const dynamicFormRef = ref();
+const dynamicFormRule = ref([]);
+const dynamicFormOption = ref({
+  submitBtn: false,
+  resetBtn: false
+});
+const showOkBtn = ref(true);
+const currentPageId = ref('');
+const formApi = ref();
+
+// 鍒ゆ柇鏄惁鏈夋彁浜ゆ寜閽�
+type RuleItem = { type?: string };
+const hasSubmitBtn = (rules: any[] = []) => {
+  return rules.some((item: RuleItem) => item.type === 'submit');
+};
+// 鏇村交搴曠殑閫掑綊绉婚櫎鎵�鏈� submit 鎸夐挳锛屾敮鎸� children銆乥ody銆乧olumns銆乴ist銆乷ptions銆乼abs 绛夊鍣�
+function removeSubmitBtn(rules = []) {
+  return rules
+    .filter(item => item.type !== 'submit')
+    .map(item => {
+      if (item.children) item.children = removeSubmitBtn(item.children);
+      if (item.body) item.body = removeSubmitBtn(item.body);
+      if (item.columns) item.columns = item.columns.map(col => ({
+        ...col,
+        list: removeSubmitBtn(col.list || [])
+      }));
+      if (item.list) item.list = removeSubmitBtn(item.list);
+      if (item.options && Array.isArray(item.options)) item.options = removeSubmitBtn(item.options);
+      if (item.tabs) item.tabs = item.tabs.map(tab => ({
+        ...tab,
+        list: removeSubmitBtn(tab.list || [])
+      }));
+      return item;
+    });
+}
+
+// 鎵撳紑寮圭獥
+const open = async (params: ModalProps = { update: false }) => {
+  try {
+    console.log('鎵撳紑寮圭獥锛屽弬鏁�:', params);
+    modalVisible.value = true;
+    modalLoading.value = true;
+    isUpdate.value = params.update;
+    currentEditId.value = params.id || '';
+    currentPageId.value = params.pageId || params.pageDesignId || '';
+    
+    // 璁剧疆鍔ㄦ�佽〃鍗曞瓧娈碉紝濮嬬粓绉婚櫎鎵�鏈塻ubmit鎸夐挳
+    if (params.formJson) {
+      console.log('璁剧疆鍔ㄦ�佽〃鍗曡鍒�:', params.formJson);
+      dynamicFormRule.value = removeSubmitBtn(params.formJson);
+      showOkBtn.value = true; // 濮嬬粓鏄剧ず纭畾鎸夐挳
+    } else {
+      dynamicFormRule.value = [];
+      showOkBtn.value = true;
+    }
+
+    // 缂栬緫妯″紡
+    if (params.id && params.update) {
+      console.log('缂栬緫妯″紡锛岃幏鍙栬鎯呮暟鎹�');
+      try {
+        // 鑾峰彇璇︽儏鏁版嵁
+        const record = await templateInfo(params.id);
+        console.log('鑾峰彇鍒扮殑璁板綍鏁版嵁:', record);
+        
+        // 璁剧疆鍔ㄦ�佽〃鍗曟暟鎹�
+        if (record.formData) {
+          try {
+            const dynamicData = JSON.parse(record.formData);
+            console.log('瑙f瀽鍚庣殑琛ㄥ崟鏁版嵁:', dynamicData);
+            
+            await nextTick();
+            if (formApi.value) {
+              console.log('鍑嗗璁剧疆琛ㄥ崟鏁版嵁鍒扮粍浠�');
+              // 浣跨敤 form-create 鐨� API 璁剧疆鍊�
+              Object.keys(dynamicData).forEach(key => {
+                formApi.value.setValue(key, dynamicData[key]);
+              });
+              console.log('琛ㄥ崟鏁版嵁璁剧疆瀹屾垚');
+            } else {
+              console.warn('琛ㄥ崟API鏈氨缁�');
+              message.error('琛ㄥ崟鏈氨缁紝璇烽噸璇�');
+            }
+          } catch (error) {
+            console.error('瑙f瀽鍔ㄦ�佸瓧娈垫暟鎹け璐�:', error);
+            message.error('鍔犺浇琛ㄥ崟鏁版嵁澶辫触');
+          }
+        } else {
+          console.log('璁板綍涓病鏈� formData 鏁版嵁');
+        }
+      } catch (error) {
+        console.error('澶勭悊琛ㄥ崟鏁版嵁澶辫触:', error);
+        message.error('鍔犺浇琛ㄥ崟鏁版嵁澶辫触锛岃閲嶈瘯');
+      }
+    } else {
+      // 鏂板鏃堕噸缃暟鎹�
+      console.log('鏂板妯″紡锛岄噸缃〃鍗�');
+      await nextTick();
+      if (formApi.value) {
+        formApi.value.resetFields && formApi.value.resetFields();
+      }
+    }
+  } catch (error) {
+    console.error('鎵撳紑寮圭獥澶辫触:', error);
+    message.error('鍔犺浇鏁版嵁澶辫触');
+  } finally {
+    modalLoading.value = false;
+  }
+};
+
+const close = () => {
+  modalVisible.value = false;
+};
+
+defineExpose({ open, close });
+
+function onFormMounted(api) {
+  formApi.value = api;
+}
+
+// handleOk 鍙礋璐hЕ鍙戣〃鍗� submit
+async function handleOk() {
+  await nextTick();
+  console.log('handleOk formApi:', formApi.value);
+  if (!dynamicFormRule.value || dynamicFormRule.value.length === 0) {
+    message.error('琛ㄥ崟瑙勫垯鏈姞杞斤紝鏃犳硶鎻愪氦');
+    return;
+  }
+  if (!formApi.value) {
+    message.error('琛ㄥ崟鏈覆鏌撳畬鎴愶紝璇风◢鍚庨噸璇�');
+    return;
+  }
+  try {
+    modalLoading.value = true;
+    const valid = await formApi.value.validate();
+    if (!valid) {
+      modalLoading.value = false;
+      return;
+    }
+    const formData = formApi.value.formData();
+    await onFormSubmit(formData);
+  } catch (error) {
+    console.error('淇濆瓨澶辫触:', error);
+    message.error('淇濆瓨澶辫触');
+    modalLoading.value = false;
+  }
+}
+
+// form-create 鐨� submit 浜嬩欢澶勭悊
+async function onFormSubmit(dynamicData: any) {
+  try {
+    modalLoading.value = true;
+    // 鏋勫缓淇濆瓨鏁版嵁
+    const finalData = {
+      pageId: currentPageId.value,
+      formData: Object.keys(dynamicData).length > 0 ? JSON.stringify(dynamicData) : undefined
+    };
+    if (isUpdate.value) {
+      finalData.id = currentEditId.value;
+    }
+    console.log(finalData)
+    await (isUpdate.value ? templateUpdate(finalData) : templateAdd(finalData));
+    emit('reload');
+    close();
+    message.success('淇濆瓨鎴愬姛');
+  } catch (error) {
+    console.error('淇濆瓨澶辫触:', error);
+    message.error('淇濆瓨澶辫触');
+  } finally {
+    modalLoading.value = false;
+  }
+}
+
+function handleCancel() {
+  close();
+}
+</script>
+
+<template>
+  <a-modal
+    v-model:open="modalVisible"
+    :title="title"
+    :width="'80vw'"
+    :confirm-loading="modalLoading"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    :bodyStyle="{ padding: '24px', minHeight: '60vh' }"
+    destroyOnClose
+    :ok-button-props="{ style: showOkBtn ? {} : { display: 'none' } }"
+  > 
+    <!-- 鍔ㄦ�佽〃鍗曞尯鍩� -->
+    <form-create 
+      ref="dynamicFormRef"
+      :rule="dynamicFormRule"
+      :option="dynamicFormOption"
+      @submit="onFormSubmit"
+      @mounted="onFormMounted"
+    />
+  </a-modal>
+</template> 
\ No newline at end of file

--
Gitblit v1.9.3