办学质量监测教学评价系统
du
昨天 c37df8655fbf6b64dca5cf92c2e8f0504a164246
页面设计器
已修改3个文件
135 ■■■■ 文件已修改
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx
@@ -29,12 +29,8 @@
  },
  {
    title: '上级目录',
    field: 'parentName',
    slots: {
      default: ({ row }) => {
        return row.parent?.name || row.menu?.menuName || '-';
      },
    },
    field: 'menuParentName',
  },
  {
    title: '状态',
@@ -110,4 +106,4 @@
      rows: 2,
    },
  },
];
];
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue
@@ -9,14 +9,13 @@
      <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()" />
    <PageDrawer ref="pageModalRef" @reload="tableApi.query()" :menu-array="menuArray" />
  </Page>
  <Fallback v-else description="您没有页面生成器的访问权限" status="403" />
</template>
@@ -34,11 +33,50 @@
import PageDrawer from './page-drawer.vue';
import FcDesigner from '@form-create/designer';
import { pageList, pageRemove } from '#/api/tool/page-designer';
import { menuList } from '../../../api/system/menu';
import { listToTree} from '@vben/utils';
// 移除mock数据
// const pageList = async (params: any) => { ... };
// const pageRemove = async (ids: number[]) => {};
const menuArray = ref([]);
const processedMenuTree = ref([]);
onMounted(async () => {
  try {
    // 获取原始菜单数据
    const rawMenuData = await menuList();
    menuArray.value = rawMenuData;
    // 处理菜单数据
    processMenuData();
  } catch (error) {
    console.error('获取菜单数据失败:', error);
  }
});
// 处理菜单数据的函数
const processMenuData = () => {
  if (!menuArray.value || menuArray.value.length === 0) return;
  // 1. 过滤掉按钮类型(F)和菜单类型(C)
  const filteredList = menuArray.value.filter(item =>
    item.menuType !== 'F' && item.menuType !== 'C'
  );
  // 2. 转换为树形结构
  const treeData = listToTree(filteredList, {
    id: 'menuId',
    pid: 'parentId'
  });
  // 3. 添加根节点
  processedMenuTree.value = [
    {
      menuId: 0,
      parentId: 0,
      menuName: '根目录',
      children: treeData
    }
  ];
};
const formOptions: VbenFormProps = {
  commonConfig: {
    labelWidth: 80,
@@ -49,7 +87,26 @@
  schema: querySchema(),
  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const getFullMenuPath = (id: number) => {
  if (!processedMenuTree.value || processedMenuTree.value.length === 0) return '';
  // 递归查找菜单路径
  const findPath = (tree, currentId, path = []): string[] | null => {
    for (const item of tree) {
      if (item.menuId === currentId) {
        return [...path, item.menuName];
      }
      if (item.children && item.children.length > 0) {
        const found = findPath(item.children, currentId, [...path, item.menuName]);
        if (found) return found;
      }
    }
    return null;
  };
  const path = findPath(processedMenuTree.value, id);
  return path ? path.join(' / ') : '根目录';
};
const gridOptions: VxeGridProps = {
  columns,
  height: 'auto',
@@ -60,15 +117,21 @@
  proxyConfig: {
    ajax: {
      query: async ({ page }, formValues = {}) => {
        console.log('查询参数:', { page, formValues });
        const resp = await pageList({
          pageNum: page.currentPage,
          pageSize: page.pageSize,
          ...formValues,
        });
        console.log('接口返回数据:', resp);
        // 处理返回数据,添加menuParentName
        const processedRows = resp.rows.map(row => {
          return {
            ...row,
            menuParentName: getFullMenuPath(row.menuParentId) || '根目录'
          };
        });
        return {
          rows: resp.rows,
          rows: processedRows,  // 使用处理后的数据
          total: resp.total,
        };
      },
ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue
@@ -5,7 +5,7 @@
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';
@@ -13,6 +13,7 @@
  id?: number | string;
  update: boolean;
}
const emit = defineEmits<{ reload: [] }>();
@@ -41,22 +42,29 @@
const modalLoading = ref(false);
const currentEditId = ref<string | number>(''); // 当前编辑的ID
const fullMenuTree = ref([]);
const props=defineProps({
  menuArray: {
    type: Array,
    required: true,
    default: () => []
  }
});
// 打开弹窗
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('menuParentId', params.id);
      if (params.update) {
        // 获取详情数据
        const record = await pageInfo(params.id);
        // 设置基础表单数据
        const menuParentId = String(record.menuParentId || record.parentId || '');
        await formApi.setValues({
@@ -73,11 +81,11 @@
            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);
@@ -109,9 +117,15 @@
async function setupPageSelect() {
  // 获取菜单数据
  const menuArray = await menuList();
  if (!props.menuArray || props.menuArray.length === 0) {
    await nextTick(); // 等待可能的异步加载
    if (!props.menuArray || props.menuArray.length === 0) {
      console.warn('menuArray is empty');
      return;
    }
  }
  // 过滤掉按钮类型
  const filteredList = menuArray.filter(item => item.menuType !== 'F' && item.menuType !== 'C');
  const filteredList = props.menuArray.filter(item => item.menuType !== 'F' && item.menuType !== 'C');
  // 支持i18n
  filteredList.forEach(item => { item.menuName = $t(item.menuName); });
  // 转为树结构
@@ -165,7 +179,7 @@
const syncAllFields = () => {
  // 获取表单组件的规则描述
  const formDesc = designer.value?.getFormDescription?.();
  if (!formDesc || !Array.isArray(formDesc)) {
    message.warning('暂无设计数据');
    return;
@@ -178,8 +192,8 @@
      title: item.title,
      field: item.field
    }));
  if (allFields.length === 0) {
    message.warning('未找到可用字段');
    return;
@@ -237,12 +251,12 @@
      return;
    }
    const data = await formApi.getValues();
    // 如果是编辑模式,添加id字段
    if (isUpdate.value) {
      data.id = currentEditId.value;
    }
    // 获取表单设计 JSON
    data.formJson = designer.value.getJson();
    // 添加选中的字段
@@ -279,19 +293,19 @@
    :bodyStyle="{ padding: '24px', minHeight: '60vh' }"
    destroyOnClose
    wrapClassName="page-designer-modal"
  >
  >
    <template #closeIcon>
      <span></span>
    </template>
    <BasicForm />
    <div style="margin-top: 16px;">
      <FcDesigner
        ref="designer"
      <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">
@@ -320,4 +334,4 @@
}
</style>
</style>