办学质量监测教学评价系统
康鲁杰
2 小时以前 38a626b58763f903f5580d49854a420681925092
创建公共模版
已重命名1个文件
已修改3个文件
已添加13个文件
1093 ■■■■■ 文件已修改
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue 404 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue 224 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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("删除成功");
    }
}
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
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;
}
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;
}
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;
}
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;
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);
}
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);
}
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
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;
    }
}
ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml
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>
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 });
}
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; // å…³è”的页面设计ID
  createTime?: string;           // åˆ›å»ºæ—¶é—´
  updateTime?: string;           // æ›´æ–°æ—¶é—´
  pageDesign?: {                 // å…³è”的页面设计信息
    id: string | number;
    name: string;
    formJson?: string;
    showColumn?: string;
    actionsFunc?: string;
  } | null;
}
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: '正常', 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: '正常', value: '1' },
        { label: '停用', value: '0' },
      ],
    },
    rules: 'selectRequired',
  },
  {
    component: 'Input',
    fieldName: 'remark',
    label: '备注',
    componentProps: {
      type: 'textarea',
      rows: 2,
    },
  },
];
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); // åŠ è½½ä¸­
// åŠ¨æ€columns
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('解析 actionsFunc å¤±è´¥:', error);
    return true;
  }
}
// èŽ·å– pageId,兼容 meta、params、query
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) => {
    // åªæœ‰å½“值真正变化时才处理
    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('解析后的 formData:', formData);
                // åˆ é™¤åŽŸå§‹çš„ formData å­—段,因为我们已经展开它的内容
                const { formData: _, ...restRow } = row;
                // è¿”回展开后的数据
                return {
                  ...restRow,
                  ...formData
                };
              }
            } catch (e) {
              console.error('解析 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;
  }
  // åŠ¨æ€ä¼ é€’formJson,先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('解析 formJson å¤±è´¥:', error);
      params.formJson = undefined;
    }
  }
  templateModalRef.value.open(params);
}
function handleEdit(record) {
  // ç¼–辑时也传递formJson,先JSON.parse,保证是纯对象
  const params: any = {
    id: record.id,
    update: true,
    pageDesignId: pageId.value,  // ä¼ é€’页面设计ID
    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('解析 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>
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、body、columns、list、options、tabs ç­‰å®¹å™¨
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 || '';
    // è®¾ç½®åŠ¨æ€è¡¨å•å­—æ®µï¼Œå§‹ç»ˆç§»é™¤æ‰€æœ‰submit按钮
    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('解析后的表单数据:', 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('解析动态字段数据失败:', 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 åªè´Ÿè´£è§¦å‘表单 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>