| | |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-core</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.ruoyi</groupId> |
| | | <artifactId>ruoyi-system-api</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | </project> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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.PageDesigner; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerDTO; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerVo; |
| | | import org.ruoyi.pageDesigner.service.PageDesignerService; |
| | | 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") |
| | | public class PageDesignerController extends BaseController { |
| | | |
| | | private final PageDesignerService pageDesignerService; |
| | | |
| | | /** |
| | | * è·å页é¢è®¾è®¡å表 |
| | | */ |
| | | @GetMapping("/list") |
| | | public TableDataInfo<PageDesignerVo> list(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery) { |
| | | return pageDesignerService.selectPagelistAll(pageDesignerDTO, pageQuery); |
| | | } |
| | | |
| | | /** |
| | | * è·å页é¢è®¾è®¡è¯¦æ
|
| | | */ |
| | | @GetMapping("/{id}") |
| | | public R<PageDesigner> getInfo(@PathVariable Long id) { |
| | | return R.ok(pageDesignerService.getDetail(id)); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢é¡µé¢è®¾è®¡ |
| | | */ |
| | | @PostMapping |
| | | public R<Void> add(@Valid @RequestBody PageDesignerDTO dto) { |
| | | pageDesignerService.add(dto); |
| | | return R.ok("æ°å¢æå"); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹é¡µé¢è®¾è®¡ |
| | | */ |
| | | @PutMapping |
| | | public R<Void> update(@Valid @RequestBody PageDesignerDTO dto) { |
| | | pageDesignerService.updatePage(dto); |
| | | return R.ok("ä¿®æ¹æå"); |
| | | } |
| | | |
| | | /** |
| | | * å é¤é¡µé¢è®¾è®¡ |
| | | */ |
| | | @DeleteMapping |
| | | public R<Void> remove(@RequestBody List<Long> ids) { |
| | | pageDesignerService.deleteByIds(ids); |
| | | return R.ok("å 餿å"); |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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") |
| | | public class PageDesigner extends BaseEntity { |
| | | @TableId(value = "ID") |
| | | private Long id; |
| | | @TableField("NAME") |
| | | private String name; |
| | | @TableField("MENU_ID") |
| | | private String menuId; // å
³èçèåID |
| | | @TableField("STATUS") |
| | | private String status; |
| | | @TableField(value = "DEL_FLAG") |
| | | @TableLogic |
| | | private String delFlag; |
| | | @TableField("REMARK") |
| | | private String remark; |
| | | @TableField("FORM_JSON") |
| | | private String formJson; |
| | | @TableField("SHOW_COLUMN") |
| | | private String showColumn; // å¯ä»¥å° selectedFields åå¨ä¸º JSON å符串 |
| | | @TableField("ACTIONS_FUNC") |
| | | private String actionsFunc; // å¯ä»¥å° enableActions åå¨ä¸º JSON å符串 |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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; |
| | | import org.ruoyi.system.domain.SysUser; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author kanglujie |
| | | * @date 2025-06-23 17:23:35 |
| | | */ |
| | | @Data |
| | | @NoArgsConstructor |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @AutoMapper(target = PageDesigner.class, reverseConvertGenerate = false) |
| | | public class PageDesignerDTO extends BaseEntity { |
| | | private Long id; // ä¿®æ¹æ¶ä¼ å
¥ |
| | | private String name; // 页é¢åç§° |
| | | private String menuId; // å
³èèå ID |
| | | private String status; // å¯ç¨ç¶æ |
| | | private String remark; // 夿³¨ |
| | | private String formJson; // 表å设计 JSON å符串 |
| | | private String showColumn; // åæ®µæ¾ç¤ºé
ç½® |
| | | private String actionsFunc; // å¯ç¨çæä½é¡¹ï¼å¢å æ¹æ¥ï¼ |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.ruoyi.pageDesigner.domain; |
| | | |
| | | 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; |
| | | |
| | | /** |
| | | * @author kanglujie |
| | | * @date 2025-06-23 17:23:35 |
| | | */ |
| | | @Data |
| | | @AutoMapper(target = PageDesigner.class) |
| | | public class PageDesignerVo implements Serializable { |
| | | private Long id; // ä¿®æ¹æ¶ä¼ å
¥ |
| | | private String name; // 页é¢åç§° |
| | | private String menuId; // å
³èèå ID |
| | | private String parentId; // å
³èèå ID |
| | | private String status; // å¯ç¨ç¶æ |
| | | private String remark; // 夿³¨ |
| | | private String formJson; // 表å设计 JSON å符串 |
| | | private String showColumn; // åæ®µæ¾ç¤ºé
ç½® |
| | | private String actionsFunc; // å¯ç¨çæä½é¡¹ï¼å¢å æ¹æ¥ï¼ |
| | | private SysMenuVo menu; // åå»ºäººä¿¡æ¯ |
| | | private SysMenuVo parent; // åå»ºäººä¿¡æ¯ |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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.PageDesigner; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerVo; |
| | | |
| | | /** |
| | | * @author kanglujie |
| | | * @date 2025-06-23 17:34:48 |
| | | */ |
| | | @Mapper |
| | | public interface PageDesignerMapper extends BaseMapper<PageDesigner> { |
| | | Page<PageDesignerVo> selectPagelistAll(@Param("page") Page<PageDesigner> page, @Param(Constants.WRAPPER) Wrapper<PageDesigner> queryWrapper); |
| | | |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | 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.PageDesigner; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerDTO; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerVo; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author kanglujie |
| | | * @date 2025-06-23 17:35:56 |
| | | */ |
| | | public interface PageDesignerService extends IService<PageDesigner> { |
| | | |
| | | void add(PageDesignerDTO dto); |
| | | |
| | | void updatePage(PageDesignerDTO dto); |
| | | |
| | | List<PageDesigner> listAll(String keyword); |
| | | |
| | | PageDesigner getDetail(Long id); |
| | | |
| | | void deleteByIds(List<Long> ids); |
| | | |
| | | TableDataInfo<PageDesignerVo> selectPagelistAll(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.ruoyi.pageDesigner.service.impl; |
| | | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | 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.common.core.constant.UserConstants; |
| | | import org.ruoyi.common.core.utils.StreamUtils; |
| | | import org.ruoyi.common.core.utils.StringUtils; |
| | | import org.ruoyi.core.page.PageQuery; |
| | | import org.ruoyi.core.page.TableDataInfo; |
| | | import org.ruoyi.helper.DataBaseHelper; |
| | | import org.ruoyi.pageDesigner.domain.PageDesigner; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerDTO; |
| | | import org.ruoyi.pageDesigner.domain.PageDesignerVo; |
| | | import org.ruoyi.pageDesigner.mapper.PageDesignerMapper; |
| | | import org.ruoyi.pageDesigner.service.PageDesignerService; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author kanglujie |
| | | * @date 2025-06-23 17:36:29 |
| | | */ |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class PageDesignerServiceImpl extends ServiceImpl<PageDesignerMapper, PageDesigner> |
| | | implements PageDesignerService { |
| | | |
| | | private final ObjectMapper objectMapper; |
| | | |
| | | @Override |
| | | public void add(PageDesignerDTO dto) { |
| | | PageDesigner entity = convertToEntity(dto); |
| | | this.save(entity); |
| | | } |
| | | |
| | | @Override |
| | | public void updatePage(PageDesignerDTO dto) { |
| | | PageDesigner entity = convertToEntity(dto); |
| | | this.updateById(entity); |
| | | } |
| | | |
| | | @Override |
| | | public TableDataInfo<PageDesignerVo> selectPagelistAll(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery) { |
| | | Page<PageDesignerVo> page = baseMapper.selectPagelistAll(pageQuery.build(), this.buildQueryWrapper(pageDesignerDTO)); |
| | | return TableDataInfo.build(page); |
| | | } |
| | | private Wrapper<PageDesigner> buildQueryWrapper(PageDesignerDTO pageDesignerDTO) { |
| | | //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")) |
| | | //; |
| | | return wrapper; |
| | | } |
| | | @Override |
| | | public List<PageDesigner> listAll(String keyword) { |
| | | LambdaQueryWrapper<PageDesigner> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.like(keyword != null, PageDesigner::getName, keyword); |
| | | return this.list(wrapper); |
| | | } |
| | | |
| | | @Override |
| | | public PageDesigner getDetail(Long id) { |
| | | return this.getById(id); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteByIds(List<Long> ids) { |
| | | this.removeByIds(ids); |
| | | } |
| | | |
| | | private PageDesigner convertToEntity(PageDesignerDTO dto) { |
| | | PageDesigner entity = new PageDesigner(); |
| | | entity.setId(dto.getId()); |
| | | entity.setName(dto.getName()); |
| | | entity.setMenuId(dto.getMenuId()); |
| | | entity.setStatus(dto.getStatus()); |
| | | entity.setRemark(dto.getRemark()); |
| | | entity.setFormJson(dto.getFormJson()); |
| | | entity.setShowColumn(dto.getShowColumn()); |
| | | entity.setActionsFunc(dto.getActionsFunc()); |
| | | return entity; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <?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.PageDesignerMapper"> |
| | | |
| | | <!-- å¤ç»æåµå¥èªå¨æ å°é另䏿¯ä¸ªå®ä½ç主é®id å¦åæ å°ä¼å¤±è´¥ --> |
| | | <resultMap type="org.ruoyi.pageDesigner.domain.PageDesignerVo" id="PageDesignerResult"> |
| | | <id property="id" column="id"/> |
| | | <result property="name" column="name"/> |
| | | <result property="status" column="status"/> |
| | | </resultMap> |
| | | |
| | | |
| | | <select id="selectPagelistAll" resultMap="PageDesignerResult"> |
| | | select |
| | | id, |
| | | name, |
| | | status |
| | | from page_designer |
| | | ${ew.getCustomSqlSegment} |
| | | </select> |
| | | |
| | | |
| | | |
| | | |
| | | </mapper> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { requestClient } from '#/api/request'; |
| | | import type { |
| | | PageDesigner |
| | | } from './model'; |
| | | |
| | | enum Api { |
| | | pageAdd = '/page-designer', |
| | | pageUpdate = '/page-designer', |
| | | pageList = '/page-designer/list', |
| | | pageInfo = '/page-designer', |
| | | pageRemove = '/page-designer', |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢é¡µé¢è®¾è®¡ |
| | | */ |
| | | export function pageAdd(data: any) { |
| | | return requestClient.post(Api.pageAdd, data); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹é¡µé¢è®¾è®¡ |
| | | */ |
| | | export function pageUpdate(data: any) { |
| | | return requestClient.put(Api.pageUpdate, data); |
| | | } |
| | | |
| | | /** |
| | | * è·å页é¢è®¾è®¡å表 |
| | | */ |
| | | export function pageList(params?: any) { |
| | | return requestClient.get<{ |
| | | total: number; |
| | | rows: PageDesigner[]; |
| | | code: number; |
| | | msg: string; |
| | | }>(Api.pageList, { params }); |
| | | } |
| | | |
| | | /** |
| | | * è·å页é¢è®¾è®¡è¯¦æ
|
| | | */ |
| | | export function pageInfo(id: string | number) { |
| | | return requestClient.get<PageDesigner>(`${Api.pageInfo}/${id}`); |
| | | } |
| | | |
| | | /** |
| | | * å é¤é¡µé¢è®¾è®¡ |
| | | */ |
| | | export function pageRemove(ids: string[] | number[]) { |
| | | return requestClient.delete(Api.pageRemove, { data: ids }); |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface PageDesigner { |
| | | id?: string | number; // 主é®ï¼ç¼è¾æ¶ç¨ |
| | | name: string; // 页é¢åç§° |
| | | menuId: string | number | null; // ä¸çº§ç®å½ï¼èåIDï¼ |
| | | parentId: string | number | null; // ç¶çº§ID |
| | | status: string; // ç¶æ |
| | | remark?: string | null; // 夿³¨ |
| | | formJson?: string | null; // 表å设计JSON |
| | | showColumn?: string | null; // æ¾ç¤ºå段(JSONå符串) |
| | | actionsFunc?: string | null; // å¯ç¨åè½(JSONå符串) |
| | | createTime?: string; // å建æ¶é´ |
| | | updateTime?: string; // æ´æ°æ¶é´ |
| | | menu?: { // å
³èçèåä¿¡æ¯ |
| | | menuId: number; |
| | | menuName: string; |
| | | } | null; |
| | | parent?: { // å
³èçç¶çº§ä¿¡æ¯ |
| | | id: string | number; |
| | | name: string; |
| | | } | null; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { FormSchemaGetter } from '#/adapter/form'; |
| | | import type { VxeGridProps } from '#/adapter/vxe-table'; |
| | | import { h } from 'vue'; |
| | | import { FolderIcon, VbenIcon } from '@vben/icons'; |
| | | |
| | | 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: VxeGridProps['columns'] = [ |
| | | { |
| | | title: '页é¢åç§°', |
| | | field: 'name', |
| | | }, |
| | | { |
| | | title: 'ä¸çº§ç®å½', |
| | | field: 'parentName', |
| | | slots: { |
| | | default: ({ row }) => { |
| | | return row.parent?.name || row.menu?.menuName || '-'; |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'ç¶æ', |
| | | field: 'status', |
| | | slots: { |
| | | default: ({ row }) => { |
| | | return row.status === '1' ? 'æ£å¸¸' : 'åç¨'; |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | title: 'å建æ¶é´', |
| | | field: 'createTime', |
| | | }, |
| | | { |
| | | field: 'action', |
| | | fixed: 'right', |
| | | slots: { default: 'action' }, |
| | | title: 'æä½', |
| | | }, |
| | | ]; |
| | | |
| | | export const drawerSchema = () => [ |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'name', |
| | | label: '页é¢åç§°', |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | component: 'TreeSelect', |
| | | fieldName: 'menuId', |
| | | label: 'ä¸çº§ç®å½', |
| | | componentProps: { |
| | | allowClear: true, |
| | | showSearch: true, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | componentProps: { |
| | | options: [ |
| | | { label: 'æ£å¸¸', value: '1' }, |
| | | { label: 'åç¨', value: '0' }, |
| | | ], |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | component: 'CheckboxGroup', |
| | | fieldName: 'actionsFunc', |
| | | label: 'å¯ç¨åè½', |
| | | defaultValue: ['add', 'edit', 'delete', 'query'], |
| | | componentProps: { |
| | | options: [ |
| | | { label: 'æ°å¢', value: 'add' }, |
| | | { label: 'ç¼è¾', value: 'edit' }, |
| | | { label: 'å é¤', value: 'delete' }, |
| | | { label: 'æ¥è¯¢', value: 'query' }, |
| | | ], |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | component: 'Input', |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | componentProps: { |
| | | type: 'textarea', |
| | | rows: 2, |
| | | }, |
| | | }, |
| | | ]; |
| | |
| | | <template> |
| | | <div>111</div> |
| | | <Page v-if="isAdmin" :auto-content-height="true"> |
| | | <BasicTable table-title="页é¢è®¾è®¡å¨" > |
| | | <template #toolbar-tools> |
| | | <Space> |
| | | <a-button type="primary" @click="handleAdd">æ°å¢</a-button> |
| | | </Space> |
| | | </template> |
| | | <template #action="{ row }"> |
| | | <Space> |
| | | <ghost-button @click="handleEdit(row)">ç¼è¾</ghost-button> |
| | | <ghost-button class="btn-success" @click="handleSubAdd(row)">æ°å¢</ghost-button> |
| | | <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="确认å é¤ï¼" @confirm="handleDelete(row)"> |
| | | <ghost-button danger @click.stop="">å é¤</ghost-button> |
| | | </Popconfirm> |
| | | </Space> |
| | | </template> |
| | | </BasicTable> |
| | | <PageDrawer ref="pageModalRef" @reload="tableApi.query()" /> |
| | | </Page> |
| | | <Fallback v-else description="æ¨æ²¡æé¡µé¢çæå¨çè®¿é®æé" status="403" /> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "index" |
| | | <script setup lang="ts"> |
| | | import type { VbenFormProps } from '@vben/common-ui'; |
| | | import type { VxeGridProps } from '#/adapter/vxe-table'; |
| | | import { computed, ref, onMounted } from 'vue'; |
| | | import { useAccess } from '@vben/access'; |
| | | import { Fallback, Page, useVbenDrawer } from '@vben/common-ui'; |
| | | import { eachTree, getVxePopupContainer } from '@vben/utils'; |
| | | import { Popconfirm, Space } from 'ant-design-vue'; |
| | | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { columns, querySchema } from './data'; |
| | | import PageDrawer from './page-drawer.vue'; |
| | | import FcDesigner from '@form-create/designer'; |
| | | import { pageList, pageRemove } from '#/api/tool/page-designer'; |
| | | |
| | | // ç§»é¤mockæ°æ® |
| | | // const pageList = async (params: any) => { ... }; |
| | | // const pageRemove = async (ids: number[]) => {}; |
| | | |
| | | 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: VxeGridProps = { |
| | | columns, |
| | | height: 'auto', |
| | | keepSource: true, |
| | | pagerConfig: { |
| | | enabled: true, |
| | | }, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues = {}) => { |
| | | console.log('æ¥è¯¢åæ°:', { page, formValues }); |
| | | const resp = await pageList({ |
| | | pageNum: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }); |
| | | console.log('æ¥å£è¿åæ°æ®:', resp); |
| | | return { |
| | | rows: resp.rows, |
| | | total: resp.total, |
| | | }; |
| | | }, |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | }, |
| | | id: 'tool-page-designer-index', |
| | | columnConfig: { resizable: true }, |
| | | }; |
| | | |
| | | const [BasicTable, tableApi] = useVbenVxeGrid({ |
| | | formOptions, |
| | | gridOptions, |
| | | }); |
| | | |
| | | const designer = ref(); |
| | | const pageModalRef = ref(); |
| | | |
| | | function getFormJson() { |
| | | // è·åè®¾è®¡ç»æ |
| | | const json = designer.value.getRule(); |
| | | // ä½ å¯ä»¥å° json åå°å端 |
| | | } |
| | | |
| | | function setFormJson(json) { |
| | | // å 载已æè®¾è®¡ |
| | | designer.value.setRule(json); |
| | | } |
| | | |
| | | function handleAdd() { |
| | | pageModalRef.value.open({ update: false }); |
| | | } |
| | | |
| | | function handleEdit(record) { |
| | | pageModalRef.value.open({ id: record.id, update: true }); |
| | | } |
| | | |
| | | async function handleDelete(row: any) { |
| | | await pageRemove([row.id]); |
| | | await tableApi.query(); |
| | | } |
| | | |
| | | function handleSubAdd(row) { |
| | | pageModalRef.value.open({ id: row.id, update: false }); |
| | | } |
| | | |
| | | const { hasAccessByRoles } = useAccess(); |
| | | const isAdmin = computed(() => { |
| | | return hasAccessByRoles(['admin', 'superadmin']); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | .designer-page { |
| | | background: #f5f6fa; |
| | | padding: 16px; |
| | | min-height: 100vh; |
| | | } |
| | | .designer-query-form { |
| | | background: #fff; |
| | | padding: 16px 16px 0 16px; |
| | | border-radius: 6px; |
| | | margin-bottom: 12px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | } |
| | | .designer-toolbar { |
| | | background: #fff; |
| | | padding: 12px 16px; |
| | | border-radius: 6px; |
| | | margin-bottom: 12px; |
| | | display: flex; |
| | | gap: 8px; |
| | | } |
| | | .designer-table { |
| | | background: #fff; |
| | | border-radius: 6px; |
| | | padding: 0 0 16px 0; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <script setup lang="ts"> |
| | | import { computed, ref, watch, nextTick, onMounted } from 'vue'; |
| | | import { Modal, message, FormItem } from 'ant-design-vue'; |
| | | import { $t } from '@vben/locales'; |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { drawerSchema } from './data'; |
| | | import FcDesigner from '@form-create/designer'; |
| | | import { menuList } from '../../../api/system/menu'; |
| | | import { listToTree, addFullName, getPopupContainer } from '@vben/utils'; |
| | | import { pageAdd, pageUpdate, pageInfo } from '#/api/tool/page-designer'; |
| | | |
| | | interface ModalProps { |
| | | id?: number | string; |
| | | update: boolean; |
| | | } |
| | | |
| | | const emit = defineEmits<{ reload: [] }>(); |
| | | |
| | | const isUpdate = ref(false); |
| | | const title = computed(() => { |
| | | return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); |
| | | }); |
| | | |
| | | const [BasicForm, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { |
| | | class: 'w-full', |
| | | }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 90, |
| | | }, |
| | | schema: drawerSchema(), |
| | | showDefaultActions: false, |
| | | wrapperClass: 'grid-cols-5', |
| | | }); |
| | | |
| | | const designer = ref(); |
| | | const selectedFields = ref([]); // å¤éæ¡éä¸çåæ®µkey |
| | | const fieldOptions = ref([]); // è®¾è®¡åºææå段 |
| | | const modalVisible = ref(false); |
| | | const modalLoading = ref(false); |
| | | const currentEditId = ref<string | number>(''); // å½åç¼è¾çID |
| | | |
| | | // æå¼å¼¹çª |
| | | const open = async (params: ModalProps = { update: false }) => { |
| | | try { |
| | | modalVisible.value = true; |
| | | modalLoading.value = true; |
| | | isUpdate.value = params.update; |
| | | currentEditId.value = params.id || ''; // ä¿åå½åç¼è¾çID |
| | | await setupPageSelect(); |
| | | |
| | | if (params.id) { |
| | | await formApi.setFieldValue('menuId', params.id); |
| | | if (params.update) { |
| | | // è·å详æ
æ°æ® |
| | | const record = await pageInfo(params.id); |
| | | console.log('ç¼è¾æ°æ®:', record); |
| | | |
| | | // 设置åºç¡è¡¨åæ°æ® |
| | | await formApi.setValues({ |
| | | name: record.name, |
| | | menuId: record.menuId || record.parentId || params.id, // ä¼å
使ç¨menuIdï¼å
¶æ¬¡parentId |
| | | status: record.status, |
| | | remark: record.remark, |
| | | actionsFunc: record.actionsFunc ? JSON.parse(record.actionsFunc) : ['add', 'edit', 'delete', 'query'] |
| | | }); |
| | | |
| | | // å 载表åè®¾è®¡æ°æ® |
| | | if (record.formJson) { |
| | | try { |
| | | const formRule = JSON.parse(record.formJson); |
| | | console.log('设计å¨è§å:', formRule); |
| | | designer.value.setRule(formRule); |
| | | |
| | | // æ´æ°å段é项 |
| | | await nextTick(); |
| | | updateFieldOptions(); |
| | | |
| | | // æ¢å¤éä¸çåæ®µ |
| | | if (record.showColumn) { |
| | | selectedFields.value = JSON.parse(record.showColumn); |
| | | console.log('æ¢å¤éä¸å段:', selectedFields.value); |
| | | } |
| | | } catch (e) { |
| | | console.error('å 载表åè®¾è®¡æ°æ®å¤±è´¥:', e); |
| | | message.error('å 载表åè®¾è®¡æ°æ®å¤±è´¥'); |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | // æ°å¢æ¶éç½®æ°æ® |
| | | designer.value?.setRule([]); |
| | | selectedFields.value = []; |
| | | await formApi.resetForm(); |
| | | } |
| | | } catch (error) { |
| | | console.error('æå¼å¼¹çªå¤±è´¥:', error); |
| | | message.error('å è½½æ°æ®å¤±è´¥'); |
| | | } finally { |
| | | modalLoading.value = false; |
| | | } |
| | | }; |
| | | const close = () => { |
| | | modalVisible.value = false; |
| | | }; |
| | | |
| | | defineExpose({ open, close }); |
| | | |
| | | async function setupPageSelect() { |
| | | // è·åèåæ°æ® |
| | | const menuArray = await menuList(); |
| | | // è¿æ»¤ææé®ç±»å |
| | | const filteredList = menuArray.filter(item => item.menuType !== 'F' && item.menuType !== 'C'); |
| | | // æ¯æi18n |
| | | filteredList.forEach(item => { item.menuName = $t(item.menuName); }); |
| | | // 转为æ ç»æ |
| | | const menuTree = listToTree(filteredList, { id: 'menuId', pid: 'parentId' }); |
| | | // å æ ¹èç¹ |
| | | const fullMenuTree = [ |
| | | { |
| | | menuId: 0, |
| | | menuName: $t('menu.root'), |
| | | children: menuTree, |
| | | }, |
| | | ]; |
| | | // çæå
¨è·¯å¾å |
| | | addFullName(fullMenuTree, 'menuName', ' / '); |
| | | |
| | | formApi.updateSchema([ |
| | | { |
| | | componentProps: { |
| | | fieldNames: { |
| | | label: 'menuName', |
| | | value: 'menuId', |
| | | children: 'children' |
| | | }, |
| | | getPopupContainer, |
| | | listHeight: 300, |
| | | showSearch: true, |
| | | treeData: fullMenuTree, |
| | | treeDefaultExpandAll: false, |
| | | treeDefaultExpandedKeys: [0], |
| | | treeLine: { showLeafIcon: false }, |
| | | treeNodeFilterProp: 'menuName', |
| | | treeNodeLabelProp: 'fullName', |
| | | }, |
| | | fieldName: 'menuId', |
| | | }, |
| | | ]); |
| | | } |
| | | |
| | | |
| | | // 忥ææå段å°éä¸ç¶æ |
| | | const syncAllFields = () => { |
| | | // è·å表åç»ä»¶çè§åæè¿° |
| | | const formDesc = designer.value?.getFormDescription?.(); |
| | | console.log('表åç»ä»¶æè¿°:', formDesc); |
| | | |
| | | if (!formDesc || !Array.isArray(formDesc)) { |
| | | message.warning('ææ è®¾è®¡æ°æ®'); |
| | | return; |
| | | } |
| | | |
| | | // æååæ®µä¿¡æ¯ |
| | | const allFields = formDesc |
| | | .filter(item => item && item.field && item.title) |
| | | .map(item => ({ |
| | | title: item.title, |
| | | field: item.field |
| | | })); |
| | | |
| | | console.log('æåçåæ®µ:', allFields); |
| | | |
| | | if (allFields.length === 0) { |
| | | message.warning('æªæ¾å°å¯ç¨å段'); |
| | | return; |
| | | } |
| | | |
| | | // æ´æ°å段é项 |
| | | fieldOptions.value = allFields.map(item => ({ |
| | | label: item.title, |
| | | value: item.field |
| | | })); |
| | | |
| | | // é䏿æå段 |
| | | selectedFields.value = allFields.map(item => item.field); |
| | | message.success(`已忥 ${allFields.length} ä¸ªåæ®µ`); |
| | | }; |
| | | |
| | | // å¤ç设计å¨åå |
| | | const handleDesignerChange = () => { |
| | | console.log('设计å¨å
容åå'); |
| | | nextTick(() => { |
| | | updateFieldOptions(); |
| | | }); |
| | | }; |
| | | |
| | | // å½è®¾è®¡å¨å
容ååæ¶æ´æ°å段é项 |
| | | const updateFieldOptions = () => { |
| | | console.log('updateFieldOptions'); |
| | | console.log('designer.value', designer.value); |
| | | |
| | | // è·å表åç»ä»¶çè§åæè¿° |
| | | const formDesc = designer.value?.getFormDescription?.(); |
| | | if (!formDesc || !Array.isArray(formDesc)) return; |
| | | |
| | | const fields = formDesc |
| | | .filter(item => item && item.field && item.title) |
| | | .map(item => ({ |
| | | title: item.title, |
| | | field: item.field |
| | | })); |
| | | |
| | | fieldOptions.value = fields.map(item => ({ |
| | | label: item.title, |
| | | value: item.field |
| | | })); |
| | | |
| | | console.log('æ´æ°åçåæ®µé项:', fieldOptions.value); |
| | | }; |
| | | |
| | | // çå¬è®¾è®¡å¨å
容åå |
| | | watch(() => modalVisible.value, (val) => { |
| | | if (val) { |
| | | nextTick(() => updateFieldOptions()); |
| | | } |
| | | }); |
| | | |
| | | async function handleOk() { |
| | | try { |
| | | modalLoading.value = true; |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | const data = await formApi.getValues(); |
| | | |
| | | // 妿æ¯ç¼è¾æ¨¡å¼ï¼æ·»å idåæ®µ |
| | | if (isUpdate.value) { |
| | | data.id = currentEditId.value; |
| | | } |
| | | |
| | | // è·å表å设计 JSON |
| | | data.formJson = designer.value.getJson(); |
| | | // æ·»å éä¸çåæ®µ |
| | | data.showColumn = JSON.stringify(selectedFields.value); |
| | | // 转æ¢å¯ç¨åè½ä¸ºJSONå符串 |
| | | data.actionsFunc = JSON.stringify(data.actionsFunc); |
| | | |
| | | // 忥䏿¬¡å段å¤é |
| | | updateFieldOptions(); |
| | | await (isUpdate.value ? pageUpdate(data) : pageAdd(data)); |
| | | emit('reload'); |
| | | close(); |
| | | message.success('ä¿åæå'); |
| | | } catch (error) { |
| | | console.error(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 |
| | | wrapClassName="page-designer-modal" |
| | | > |
| | | <template #closeIcon> |
| | | <span></span> |
| | | </template> |
| | | <BasicForm /> |
| | | <div style="margin-top: 16px;"> |
| | | <FcDesigner |
| | | ref="designer" |
| | | @update="handleDesignerChange" |
| | | @change="handleDesignerChange" |
| | | @add-rule="handleDesignerChange" |
| | | @remove-rule="handleDesignerChange" |
| | | |
| | | /> |
| | | <div style="margin-top: 8px; display: flex; justify-content: flex-end;"> |
| | | <a-button type="primary" ghost @click="syncAllFields"> |
| | | åæ¥è®¾è®¡åæ®µå°è¡¨æ ¼ |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | <FormItem label="è¡¨æ ¼åæ®µ" style="margin-top: 24px;"> |
| | | <a-checkbox-group |
| | | v-model:value="selectedFields" |
| | | :options="fieldOptions" |
| | | style="width:100%;display:flex;flex-wrap:wrap;gap:8px" |
| | | /> |
| | | </FormItem> |
| | | <template #empty> |
| | | <div style="padding: 32px 0; color: #999; text-align: center;"> |
| | | ææ æ°æ® |
| | | </div> |
| | | </template> |
| | | </a-modal> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | .page-designer-modal .ant-modal { |
| | | max-width: 1200px; |
| | | } |
| | | |
| | | |
| | | </style> |