NewLife/cube-front

V1页面
Yann authored at 2025-07-10 19:40:47
f302aa8
Tree
1 Parent(s) 6fcd229
Summary: 23 changed files with 4119 additions and 0 deletions.
Added +20 -0
Added +14 -0
Added +140 -0
Added +114 -0
Added +139 -0
Added +121 -0
Added +261 -0
Added +186 -0
Added +302 -0
Added +199 -0
Added +231 -0
Added +162 -0
Added +186 -0
Added +202 -0
Added +327 -0
Added +190 -0
Added +252 -0
Added +375 -0
Added +165 -0
Added +239 -0
Added +175 -0
Added +103 -0
Added +16 -0
Added +20 -0
diff --git a/apps/cube-v1/package.json b/apps/cube-v1/package.json
new file mode 100644
index 0000000..3859970
--- /dev/null
+++ b/apps/cube-v1/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "cube-v1",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vue-tsc && vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "vue": "^3.4.21"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^5.0.4",
+    "typescript": "^5.2.2",
+    "vite": "^5.2.0",
+    "vue-tsc": "^2.0.6"
+  }
+}
Added +14 -0
diff --git a/apps/cube-v1/src/main.ts b/apps/cube-v1/src/main.ts
new file mode 100644
index 0000000..6616298
--- /dev/null
+++ b/apps/cube-v1/src/main.ts
@@ -0,0 +1,14 @@
+import { createApp } from 'vue';
+import { createRouter, createWebHistory } from 'vue-router';
+import '@core/initApp';
+import App from '@core/App.vue';
+import routes from './routes/index';
+
+const router = createRouter({
+  history: createWebHistory(),
+  routes,
+});
+
+const app = createApp(App);
+app.use(router);
+app.mount('#app');
Added +140 -0
diff --git a/apps/cube-v1/src/pages/cube/apis/index.vue b/apps/cube-v1/src/pages/cube/apis/index.vue
new file mode 100644
index 0000000..39090b5
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/apis/index.vue
@@ -0,0 +1,140 @@
+<template>
+  <div class="cube-apis-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>Cube API列表</h3>
+          <el-button type="primary" @click="handleGetApis">获取API列表</el-button>
+        </div>
+      </template>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="API名称" min-width="150" />
+        <el-table-column prop="url" label="URL" min-width="200" />
+        <el-table-column prop="method" label="请求方法" width="100" />
+        <el-table-column prop="description" label="描述" min-width="200" />
+        <el-table-column prop="createTime" label="创建时间" width="160" />
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义数据类型
+interface ApiData {
+  id: number;
+  name: string;
+  url: string;
+  method: string;
+  description: string;
+  createTime: string;
+}
+
+// 表格数据
+const tableData = ref<ApiData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/Apis');
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: index + 1,
+        name: item.name || `API-${index + 1}`,
+        url: item.url || item.path || '',
+        method: item.method || 'GET',
+        description: item.description || item.summary || '',
+        createTime: new Date().toLocaleString(),
+      }));
+      total.value = response.length;
+    } else if (response && typeof response === 'object') {
+      // 如果返回的是对象,尝试解析为API列表
+      const apiList: ApiData[] = [];
+      Object.keys(response).forEach((key, index) => {
+        apiList.push({
+          id: index + 1,
+          name: key,
+          url: key,
+          method: 'GET',
+          description: `${key} API`,
+          createTime: new Date().toLocaleString(),
+        });
+      });
+      tableData.value = apiList;
+      total.value = apiList.length;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 获取API列表
+const handleGetApis = () => {
+  loadData();
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-apis-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +114 -0
diff --git a/apps/cube-v1/src/pages/cube/area-all-parents/index.vue b/apps/cube-v1/src/pages/cube/area-all-parents/index.vue
new file mode 100644
index 0000000..60e8a88
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/area-all-parents/index.vue
@@ -0,0 +1,114 @@
+<template>
+  <div class="cube-area-all-parents-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取区域所有父项</h3>
+          <el-button type="primary" @click="handleGetData">获取数据</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="区域ID">
+          <el-input-number v-model="searchForm.id" :min="0" placeholder="区域ID" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="区域名称" min-width="150" />
+        <el-table-column prop="fullName" label="全名" min-width="200" />
+        <el-table-column prop="level" label="级别" width="80" />
+        <el-table-column prop="code" label="代码" width="100" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+interface SearchForm {
+  id: number;
+}
+
+interface AreaData {
+  id: number;
+  name: string;
+  fullName: string;
+  level: number;
+  code: string;
+}
+
+const tableData = ref<AreaData[]>([]);
+const loading = ref(false);
+
+const searchForm = reactive<SearchForm>({
+  id: 0,
+});
+
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/AreaAllParents', {
+      params: {
+        id: searchForm.id || undefined,
+      },
+    });
+
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `区域${index + 1}`,
+        fullName: item.fullName || item.name || `区域${index + 1}`,
+        level: item.level || 0,
+        code: item.code || '',
+      }));
+    } else {
+      tableData.value = [];
+    }
+  } catch {
+    tableData.value = [];
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleGetData = () => {
+  loadData();
+};
+
+const handleSearch = () => {
+  loadData();
+};
+
+const resetSearch = () => {
+  searchForm.id = 0;
+  loadData();
+};
+
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-area-all-parents-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+</style>
Added +139 -0
diff --git a/apps/cube-v1/src/pages/cube/area-childs/index.vue b/apps/cube-v1/src/pages/cube/area-childs/index.vue
new file mode 100644
index 0000000..7a1719a
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/area-childs/index.vue
@@ -0,0 +1,139 @@
+<template>
+  <div class="cube-area-childs-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取区域子项</h3>
+          <el-button type="primary" @click="handleGetAreaChilds">获取子区域</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="区域ID">
+          <el-input-number v-model="searchForm.id" :min="0" placeholder="区域ID" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="区域名称" min-width="150" />
+        <el-table-column prop="fullName" label="全名" min-width="200" />
+        <el-table-column prop="parentId" label="上级区域ID" width="120" />
+        <el-table-column prop="level" label="级别" width="80" />
+        <el-table-column prop="code" label="代码" width="100" />
+        <el-table-column prop="pinyin" label="拼音" width="120" />
+        <el-table-column label="状态" width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.enable ? 'success' : 'danger'">
+              {{ scope.row.enable ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义搜索参数类型
+interface AreaParams {
+  id: number;
+}
+
+// 定义区域数据类型
+interface AreaData {
+  id: number;
+  name: string;
+  fullName: string;
+  parentId: number;
+  level: number;
+  code: string;
+  pinyin: string;
+  enable: boolean;
+}
+
+// 表格数据
+const tableData = ref<AreaData[]>([]);
+const loading = ref(false);
+
+// 查询表单
+const searchForm = reactive<AreaParams>({
+  id: 0,
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/AreaChilds', {
+      params: {
+        id: searchForm.id || undefined,
+      },
+    });
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `区域${index + 1}`,
+        fullName: item.fullName || item.name || `区域${index + 1}`,
+        parentId: item.parentId || item.parentID || 0,
+        level: item.level || 0,
+        code: item.code || '',
+        pinyin: item.pinyin || '',
+        enable: item.enable !== false,
+      }));
+    } else {
+      tableData.value = [];
+    }
+  } catch {
+    tableData.value = [];
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 获取区域子项
+const handleGetAreaChilds = () => {
+  loadData();
+};
+
+// 搜索
+const handleSearch = () => {
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.id = 0;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-area-childs-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+</style>
Added +121 -0
diff --git a/apps/cube-v1/src/pages/cube/area-parents/index.vue b/apps/cube-v1/src/pages/cube/area-parents/index.vue
new file mode 100644
index 0000000..9183e3a
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/area-parents/index.vue
@@ -0,0 +1,121 @@
+<template>
+  <div class="cube-area-parents-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取区域父项</h3>
+          <el-button type="primary" @click="handleGetData">获取数据</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="区域ID">
+          <el-input-number v-model="searchForm.id" :min="0" placeholder="区域ID" />
+        </el-form-item>
+        <el-form-item label="包含自身">
+          <el-switch v-model="searchForm.isContainSelf" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="区域名称" min-width="150" />
+        <el-table-column prop="fullName" label="全名" min-width="200" />
+        <el-table-column prop="level" label="级别" width="80" />
+        <el-table-column prop="code" label="代码" width="100" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+interface SearchForm {
+  id: number;
+  isContainSelf: boolean;
+}
+
+interface AreaData {
+  id: number;
+  name: string;
+  fullName: string;
+  level: number;
+  code: string;
+}
+
+const tableData = ref<AreaData[]>([]);
+const loading = ref(false);
+
+const searchForm = reactive<SearchForm>({
+  id: 0,
+  isContainSelf: false,
+});
+
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/AreaParents', {
+      params: {
+        id: searchForm.id || undefined,
+        isContainSelf: searchForm.isContainSelf,
+      },
+    });
+
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `区域${index + 1}`,
+        fullName: item.fullName || item.name || `区域${index + 1}`,
+        level: item.level || 0,
+        code: item.code || '',
+      }));
+    } else {
+      tableData.value = [];
+    }
+  } catch {
+    tableData.value = [];
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleGetData = () => {
+  loadData();
+};
+
+const handleSearch = () => {
+  loadData();
+};
+
+const resetSearch = () => {
+  searchForm.id = 0;
+  searchForm.isContainSelf = false;
+  loadData();
+};
+
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-area-parents-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+</style>
Added +261 -0
diff --git a/apps/cube-v1/src/pages/cube/avatar/index.vue b/apps/cube-v1/src/pages/cube/avatar/index.vue
new file mode 100644
index 0000000..52a0871
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/avatar/index.vue
@@ -0,0 +1,261 @@
+<template>
+  <div class="cube-avatar-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>头像管理</h3>
+          <el-button type="primary" @click="handleGetAvatar">获取头像</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="用户ID">
+          <el-input-number v-model="searchForm.id" placeholder="请输入用户ID" :min="0" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleGetAvatar">获取头像</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 头像展示区域 -->
+      <el-row :gutter="20" v-if="avatarList.length > 0">
+        <el-col :span="6" v-for="avatar in avatarList" :key="avatar.id">
+          <el-card class="avatar-card">
+            <div class="avatar-container">
+              <img
+                :src="avatar.url"
+                :alt="avatar.name"
+                class="avatar-image"
+                @error="handleImageError"
+              />
+            </div>
+            <div class="avatar-info">
+              <h4>{{ avatar.name }}</h4>
+              <p>ID: {{ avatar.id }}</p>
+              <p>更新时间: {{ avatar.updateTime }}</p>
+            </div>
+            <div class="avatar-actions">
+              <el-button type="primary" size="small" @click="viewAvatar(avatar)">查看</el-button>
+              <el-button type="success" size="small" @click="downloadAvatar(avatar)">下载</el-button>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+
+      <!-- 如果没有头像 -->
+      <el-empty v-else-if="searchForm.id && !loading" description="未找到头像" />
+
+      <!-- 加载状态 -->
+      <div v-loading="loading" class="loading-container" />
+    </el-card>
+
+    <!-- 头像查看对话框 -->
+    <el-dialog v-model="dialogVisible" title="头像查看" width="500px">
+      <div class="dialog-avatar-container" v-if="selectedAvatar">
+        <img
+          :src="selectedAvatar.url"
+          :alt="selectedAvatar.name"
+          class="dialog-avatar-image"
+        />
+        <el-descriptions :column="1" class="avatar-details">
+          <el-descriptions-item label="用户ID">{{ selectedAvatar.id }}</el-descriptions-item>
+          <el-descriptions-item label="用户名">{{ selectedAvatar.name }}</el-descriptions-item>
+          <el-descriptions-item label="头像URL">{{ selectedAvatar.url }}</el-descriptions-item>
+          <el-descriptions-item label="更新时间">{{ selectedAvatar.updateTime }}</el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <template #footer>
+        <el-button @click="dialogVisible = false">关闭</el-button>
+        <el-button type="primary" @click="downloadAvatar(selectedAvatar)">下载头像</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage } from 'element-plus';
+
+// 定义接口类型
+interface AvatarParams {
+  id?: number;
+}
+
+interface AvatarData {
+  id: number;
+  name: string;
+  url: string;
+  updateTime: string;
+}
+
+// 表单数据
+const searchForm = reactive<AvatarParams>({
+  id: undefined,
+});
+
+// 头像列表
+const avatarList = ref<AvatarData[]>([]);
+const loading = ref(false);
+const dialogVisible = ref(false);
+const selectedAvatar = ref<AvatarData | null>(null);
+
+// 获取头像
+const handleGetAvatar = async () => {
+  if (!searchForm.id) {
+    ElMessage.warning('请输入用户ID');
+    return;
+  }
+
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/Avatar', {
+      params: {
+        id: searchForm.id,
+      },
+      responseType: 'blob', // 头像通常是二进制数据
+    });
+
+    // 如果响应是blob,创建URL
+    if (response instanceof Blob) {
+      const url = URL.createObjectURL(response);
+      const avatarData: AvatarData = {
+        id: searchForm.id,
+        name: `用户${searchForm.id}`,
+        url,
+        updateTime: new Date().toLocaleString(),
+      };
+
+      avatarList.value = [avatarData];
+      ElMessage.success('头像获取成功');
+    } else {
+      // 如果返回的是URL字符串或其他格式
+      const avatarData: AvatarData = {
+        id: searchForm.id,
+        name: `用户${searchForm.id}`,
+        url: typeof response === 'string' ? response : `/Cube/Avatar?id=${searchForm.id}`,
+        updateTime: new Date().toLocaleString(),
+      };
+
+      avatarList.value = [avatarData];
+      ElMessage.success('头像获取成功');
+    }
+  } catch {
+    ElMessage.error('头像获取失败');
+    avatarList.value = [];
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.id = undefined;
+  avatarList.value = [];
+};
+
+// 查看头像
+const viewAvatar = (avatar: AvatarData) => {
+  selectedAvatar.value = avatar;
+  dialogVisible.value = true;
+};
+
+// 下载头像
+const downloadAvatar = (avatar: AvatarData | null) => {
+  if (!avatar) return;
+
+  const link = document.createElement('a');
+  link.href = avatar.url;
+  link.download = `avatar_${avatar.id}.png`;
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+
+  ElMessage.success('头像下载完成');
+};
+
+// 图片加载错误处理
+const handleImageError = (event: Event) => {
+  const target = event.target as HTMLImageElement;
+  target.src = '/path/to/default-avatar.png'; // 设置默认头像
+};
+</script>
+
+<style scoped>
+.cube-avatar-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.avatar-card {
+  margin-bottom: 20px;
+}
+
+.avatar-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 150px;
+  background-color: #f5f5f5;
+  border-radius: 8px;
+  margin-bottom: 15px;
+}
+
+.avatar-image {
+  max-width: 120px;
+  max-height: 120px;
+  border-radius: 50%;
+  object-fit: cover;
+}
+
+.avatar-info {
+  text-align: center;
+  margin-bottom: 15px;
+}
+
+.avatar-info h4 {
+  margin: 0 0 8px 0;
+  color: #333;
+}
+
+.avatar-info p {
+  margin: 4px 0;
+  color: #666;
+  font-size: 12px;
+}
+
+.avatar-actions {
+  display: flex;
+  justify-content: center;
+  gap: 10px;
+}
+
+.loading-container {
+  min-height: 200px;
+}
+
+.dialog-avatar-container {
+  text-align: center;
+}
+
+.dialog-avatar-image {
+  max-width: 200px;
+  max-height: 200px;
+  border-radius: 8px;
+  margin-bottom: 20px;
+}
+
+.avatar-details {
+  margin-top: 20px;
+}
+</style>
Added +186 -0
diff --git a/apps/cube-v1/src/pages/cube/department-search/index.vue b/apps/cube-v1/src/pages/cube/department-search/index.vue
new file mode 100644
index 0000000..8f2de4f
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/department-search/index.vue
@@ -0,0 +1,186 @@
+<template>
+  <div class="cube-department-search-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>部门搜索</h3>
+          <el-button type="primary" @click="handleSearch">搜索部门</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="上级部门ID">
+          <el-input-number v-model="searchForm.parentid" :min="-1" placeholder="上级部门ID" />
+        </el-form-item>
+        <el-form-item label="关键字">
+          <el-input v-model="searchForm.key" placeholder="请输入关键字" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="部门名称" min-width="150" />
+        <el-table-column prop="fullName" label="全名" min-width="200" />
+        <el-table-column prop="parentId" label="上级部门ID" width="120" />
+        <el-table-column prop="sort" label="排序" width="80" />
+        <el-table-column prop="manager" label="负责人" width="100" />
+        <el-table-column prop="phone" label="电话" width="120" />
+        <el-table-column prop="address" label="地址" min-width="150" />
+        <el-table-column prop="createTime" label="创建时间" width="160" />
+        <el-table-column label="状态" width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.enable ? 'success' : 'danger'">
+              {{ scope.row.enable ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义搜索参数类型
+interface DepartmentSearchParams {
+  parentid: number;
+  key: string;
+}
+
+// 定义部门数据类型
+interface DepartmentData {
+  id: number;
+  name: string;
+  fullName: string;
+  parentId: number;
+  sort: number;
+  manager: string;
+  phone: string;
+  address: string;
+  createTime: string;
+  enable: boolean;
+}
+
+// 表格数据
+const tableData = ref<DepartmentData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 查询表单
+const searchForm = reactive<DepartmentSearchParams>({
+  parentid: -1,
+  key: '',
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/DepartmentSearch', {
+      params: {
+        parentid: searchForm.parentid,
+        key: searchForm.key || undefined,
+      },
+    });
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `部门${index + 1}`,
+        fullName: item.fullName || item.name || `部门${index + 1}`,
+        parentId: item.parentId || item.parentID || 0,
+        sort: item.sort || 0,
+        manager: item.manager || '',
+        phone: item.phone || '',
+        address: item.address || '',
+        createTime: item.createTime || new Date().toLocaleString(),
+        enable: item.enable !== false,
+      }));
+      total.value = response.length;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 搜索
+const handleSearch = () => {
+  currentPage.value = 1;
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.parentid = -1;
+  searchForm.key = '';
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-department-search-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +302 -0
diff --git a/apps/cube-v1/src/pages/cube/file/index.vue b/apps/cube-v1/src/pages/cube/file/index.vue
new file mode 100644
index 0000000..8d89094
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/file/index.vue
@@ -0,0 +1,302 @@
+<template>
+  <div class="cube-file-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>文件管理</h3>
+          <el-button type="primary" @click="handleGetFile">获取文件</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="文件ID">
+          <el-input v-model="searchForm.id" placeholder="请输入文件ID" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleGetFile">获取文件</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 文件列表 -->
+      <el-table :data="fileList" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="文件ID" width="120" />
+        <el-table-column prop="name" label="文件名" min-width="200" />
+        <el-table-column prop="size" label="文件大小" width="100">
+          <template #default="scope">
+            {{ formatFileSize(scope.row.size) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="文件类型" width="120" />
+        <el-table-column prop="url" label="文件URL" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="uploadTime" label="上传时间" width="160" />
+        <el-table-column label="操作" width="200">
+          <template #default="scope">
+            <el-button type="primary" size="small" @click="previewFile(scope.row)">预览</el-button>
+            <el-button type="success" size="small" @click="downloadFile(scope.row)">下载</el-button>
+            <el-button type="info" size="small" @click="copyFileUrl(scope.row)">复制链接</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+
+    <!-- 文件预览对话框 -->
+    <el-dialog v-model="previewVisible" :title="previewFile.name" width="80%">
+      <div class="file-preview-container">
+        <!-- 图片预览 -->
+        <div v-if="isImageFile(selectedFile)" class="image-preview">
+          <img :src="selectedFile.url" :alt="selectedFile.name" class="preview-image" />
+        </div>
+        <!-- 文本文件预览 -->
+        <div v-else-if="isTextFile(selectedFile)" class="text-preview">
+          <el-input
+            v-model="fileContent"
+            type="textarea"
+            :rows="20"
+            readonly
+            placeholder="文本内容将显示在这里"
+          />
+        </div>
+        <!-- 其他文件类型 -->
+        <div v-else class="other-file-preview">
+          <el-empty description="该文件类型不支持预览">
+            <el-button type="primary" @click="downloadFile(selectedFile)">下载文件</el-button>
+          </el-empty>
+        </div>
+      </div>
+      <template #footer>
+        <el-button @click="previewVisible = false">关闭</el-button>
+        <el-button type="primary" @click="downloadFile(selectedFile)">下载</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage } from 'element-plus';
+
+// 定义接口类型
+interface FileParams {
+  id?: string;
+}
+
+interface FileData {
+  id: string;
+  name: string;
+  size: number;
+  type: string;
+  url: string;
+  uploadTime: string;
+}
+
+// 表单数据
+const searchForm = reactive<FileParams>({
+  id: '',
+});
+
+// 文件列表
+const fileList = ref<FileData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 预览相关
+const previewVisible = ref(false);
+const selectedFile = ref<FileData | null>(null);
+const fileContent = ref('');
+
+// 获取文件
+const handleGetFile = async () => {
+  if (!searchForm.id) {
+    ElMessage.warning('请输入文件ID');
+    return;
+  }
+
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/File', {
+      params: {
+        id: searchForm.id,
+      },
+    });
+
+    // 处理响应数据
+    if (response) {
+      const fileData: FileData = {
+        id: searchForm.id,
+        name: response.name || response.fileName || `文件_${searchForm.id}`,
+        size: response.size || 0,
+        type: response.type || response.contentType || 'unknown',
+        url: response.url || `/Cube/File?id=${searchForm.id}`,
+        uploadTime: response.uploadTime || new Date().toLocaleString(),
+      };
+
+      fileList.value = [fileData];
+      total.value = 1;
+      ElMessage.success('文件获取成功');
+    } else {
+      fileList.value = [];
+      total.value = 0;
+    }
+  } catch {
+    ElMessage.error('文件获取失败');
+    fileList.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.id = '';
+  fileList.value = [];
+  total.value = 0;
+};
+
+// 预览文件
+const previewFile = (file: FileData) => {
+  selectedFile.value = file;
+  previewVisible.value = true;
+
+  // 如果是文本文件,尝试获取内容
+  if (isTextFile(file)) {
+    loadTextContent(file);
+  }
+};
+
+// 下载文件
+const downloadFile = (file: FileData) => {
+  const link = document.createElement('a');
+  link.href = file.url;
+  link.download = file.name;
+  link.target = '_blank';
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+
+  ElMessage.success('文件下载完成');
+};
+
+// 复制文件链接
+const copyFileUrl = async (file: FileData) => {
+  try {
+    await navigator.clipboard.writeText(file.url);
+    ElMessage.success('文件链接已复制到剪贴板');
+  } catch {
+    ElMessage.error('复制失败,请手动复制');
+  }
+};
+
+// 判断是否为图片文件
+const isImageFile = (file: FileData | null): boolean => {
+  if (!file) return false;
+  const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
+  return imageTypes.includes(file.type.toLowerCase()) ||
+         /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name);
+};
+
+// 判断是否为文本文件
+const isTextFile = (file: FileData | null): boolean => {
+  if (!file) return false;
+  const textTypes = ['text/plain', 'text/html', 'text/css', 'text/javascript', 'application/json'];
+  return textTypes.includes(file.type.toLowerCase()) ||
+         /\.(txt|html|css|js|json|xml|md)$/i.test(file.name);
+};
+
+// 加载文本内容
+const loadTextContent = async (file: FileData) => {
+  try {
+    const response = await request.get(file.url, {
+      responseType: 'text',
+    });
+    fileContent.value = response;
+  } catch {
+    fileContent.value = '文本内容加载失败';
+  }
+};
+
+// 格式化文件大小
+const formatFileSize = (size: number): string => {
+  if (size === 0) return '0 B';
+  const k = 1024;
+  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+  const i = Math.floor(Math.log(size) / Math.log(k));
+  return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+};
+</script>
+
+<style scoped>
+.cube-file-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.file-preview-container {
+  min-height: 400px;
+}
+
+.image-preview {
+  text-align: center;
+  padding: 20px;
+}
+
+.preview-image {
+  max-width: 100%;
+  max-height: 500px;
+  border-radius: 8px;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+.text-preview {
+  padding: 20px;
+}
+
+.other-file-preview {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 300px;
+}
+</style>
Added +199 -0
diff --git a/apps/cube-v1/src/pages/cube/get-area/index.vue b/apps/cube-v1/src/pages/cube/get-area/index.vue
new file mode 100644
index 0000000..4862a2d
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/get-area/index.vue
@@ -0,0 +1,199 @@
+<template>
+  <div class="cube-get-area-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取区域</h3>
+          <el-button type="primary" @click="handleGetArea">获取区域信息</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="区域ID">
+          <el-input-number v-model="searchForm.id" :min="0" placeholder="区域ID" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="区域名称" min-width="150" />
+        <el-table-column prop="fullName" label="全名" min-width="200" />
+        <el-table-column prop="parentId" label="上级区域ID" width="120" />
+        <el-table-column prop="level" label="级别" width="80" />
+        <el-table-column prop="code" label="代码" width="100" />
+        <el-table-column prop="pinyin" label="拼音" width="120" />
+        <el-table-column prop="latitude" label="纬度" width="100" />
+        <el-table-column prop="longitude" label="经度" width="100" />
+        <el-table-column label="状态" width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.enable ? 'success' : 'danger'">
+              {{ scope.row.enable ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义搜索参数类型
+interface AreaParams {
+  id: number;
+}
+
+// 定义区域数据类型
+interface AreaData {
+  id: number;
+  name: string;
+  fullName: string;
+  parentId: number;
+  level: number;
+  code: string;
+  pinyin: string;
+  latitude: number;
+  longitude: number;
+  enable: boolean;
+}
+
+// 表格数据
+const tableData = ref<AreaData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 查询表单
+const searchForm = reactive<AreaParams>({
+  id: 0,
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/GetArea', {
+      params: {
+        id: searchForm.id || undefined,
+      },
+    });
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `区域${index + 1}`,
+        fullName: item.fullName || item.name || `区域${index + 1}`,
+        parentId: item.parentId || item.parentID || 0,
+        level: item.level || 0,
+        code: item.code || '',
+        pinyin: item.pinyin || '',
+        latitude: item.latitude || 0,
+        longitude: item.longitude || 0,
+        enable: item.enable !== false,
+      }));
+      total.value = response.length;
+    } else if (response && typeof response === 'object') {
+      // 如果返回单个对象,转换为数组
+      tableData.value = [{
+        id: response.id || 1,
+        name: response.name || '区域',
+        fullName: response.fullName || response.name || '区域',
+        parentId: response.parentId || response.parentID || 0,
+        level: response.level || 0,
+        code: response.code || '',
+        pinyin: response.pinyin || '',
+        latitude: response.latitude || 0,
+        longitude: response.longitude || 0,
+        enable: response.enable !== false,
+      }];
+      total.value = 1;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 获取区域
+const handleGetArea = () => {
+  loadData();
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 搜索
+const handleSearch = () => {
+  currentPage.value = 1;
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.id = 0;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-get-area-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +231 -0
diff --git a/apps/cube-v1/src/pages/cube/get-page-config/index.vue b/apps/cube-v1/src/pages/cube/get-page-config/index.vue
new file mode 100644
index 0000000..7ae0536
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/get-page-config/index.vue
@@ -0,0 +1,231 @@
+<template>
+  <div class="get-page-config-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取页面配置</h3>
+          <el-button type="primary" @click="handleGetConfig">获取配置</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="类型">
+          <el-input v-model="searchForm.kind" placeholder="请输入配置类型" clearable />
+        </el-form-item>
+        <el-form-item label="页面">
+          <el-input v-model="searchForm.page" placeholder="请输入页面名称" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleGetConfig">获取配置</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 配置结果展示 -->
+      <el-card v-if="configData" class="config-card">
+        <template #header>
+          <h4>配置结果</h4>
+        </template>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="类型">
+            {{ searchForm.kind }}
+          </el-descriptions-item>
+          <el-descriptions-item label="页面">
+            {{ searchForm.page }}
+          </el-descriptions-item>
+          <el-descriptions-item label="配置数据">
+            <el-input
+              v-model="formattedConfig"
+              type="textarea"
+              :rows="15"
+              readonly
+              placeholder="配置数据将显示在这里"
+            />
+          </el-descriptions-item>
+        </el-descriptions>
+        <div class="config-actions">
+          <el-button type="primary" @click="copyConfig">复制配置</el-button>
+          <el-button type="success" @click="downloadConfig">下载配置</el-button>
+        </div>
+      </el-card>
+
+      <!-- 历史查询记录 -->
+      <el-card v-if="queryHistory.length > 0" class="history-card">
+        <template #header>
+          <h4>查询历史</h4>
+        </template>
+        <el-table :data="queryHistory" border style="width: 100%">
+          <el-table-column prop="kind" label="类型" width="150" />
+          <el-table-column prop="page" label="页面" width="150" />
+          <el-table-column prop="queryTime" label="查询时间" width="160" />
+          <el-table-column prop="hasData" label="是否有数据" width="100">
+            <template #default="scope">
+              <el-tag :type="scope.row.hasData ? 'success' : 'warning'">
+                {{ scope.row.hasData ? '有数据' : '无数据' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="120">
+            <template #default="scope">
+              <el-button type="primary" size="small" @click="loadHistory(scope.row)">重新查询</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage } from 'element-plus';
+
+// 定义接口类型
+interface PageConfigParams {
+  kind?: string;
+  page?: string;
+}
+
+interface QueryHistoryItem extends PageConfigParams {
+  queryTime: string;
+  hasData: boolean;
+}
+
+// 查询表单
+const searchForm = reactive<PageConfigParams>({
+  kind: '',
+  page: '',
+});
+
+// 配置数据
+const configData = ref<unknown>(null);
+const queryHistory = ref<QueryHistoryItem[]>([]);
+
+// 格式化后的配置数据
+const formattedConfig = computed(() => {
+  if (!configData.value) return '';
+  try {
+    return JSON.stringify(configData.value, null, 2);
+  } catch {
+    return String(configData.value);
+  }
+});
+
+// 获取配置
+const handleGetConfig = async () => {
+  if (!searchForm.kind || !searchForm.page) {
+    ElMessage.warning('请输入类型和页面名称');
+    return;
+  }
+
+  try {
+    const response = await request.get('/Cube/GetPageConfig', {
+      params: {
+        kind: searchForm.kind,
+        page: searchForm.page,
+      },
+    });
+
+    configData.value = response;
+
+    // 添加到查询历史
+    queryHistory.value.unshift({
+      kind: searchForm.kind,
+      page: searchForm.page,
+      queryTime: new Date().toLocaleString(),
+      hasData: response !== null && response !== undefined,
+    });
+
+    // 保持历史记录在10条以内
+    if (queryHistory.value.length > 10) {
+      queryHistory.value = queryHistory.value.slice(0, 10);
+    }
+
+    ElMessage.success('配置获取成功');
+  } catch {
+    ElMessage.error('配置获取失败');
+    configData.value = null;
+  }
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.kind = '';
+  searchForm.page = '';
+  configData.value = null;
+};
+
+// 复制配置
+const copyConfig = async () => {
+  if (!formattedConfig.value) {
+    ElMessage.warning('没有配置数据可复制');
+    return;
+  }
+
+  try {
+    await navigator.clipboard.writeText(formattedConfig.value);
+    ElMessage.success('配置已复制到剪贴板');
+  } catch {
+    ElMessage.error('复制失败,请手动复制');
+  }
+};
+
+// 下载配置
+const downloadConfig = () => {
+  if (!formattedConfig.value) {
+    ElMessage.warning('没有配置数据可下载');
+    return;
+  }
+
+  const blob = new Blob([formattedConfig.value], { type: 'application/json' });
+  const url = URL.createObjectURL(blob);
+  const a = document.createElement('a');
+  a.href = url;
+  a.download = `${searchForm.kind}_${searchForm.page}_config.json`;
+  document.body.appendChild(a);
+  a.click();
+  document.body.removeChild(a);
+  URL.revokeObjectURL(url);
+
+  ElMessage.success('配置文件下载完成');
+};
+
+// 载入历史记录
+const loadHistory = (item: QueryHistoryItem) => {
+  Object.assign(searchForm, {
+    kind: item.kind,
+    page: item.page,
+  });
+  handleGetConfig();
+};
+</script>
+
+<style scoped>
+.get-page-config-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.config-card {
+  margin-top: 20px;
+}
+
+.config-actions {
+  margin-top: 15px;
+  text-align: right;
+}
+
+.history-card {
+  margin-top: 20px;
+}
+</style>
Added +162 -0
diff --git a/apps/cube-v1/src/pages/cube/info/index.vue b/apps/cube-v1/src/pages/cube/info/index.vue
new file mode 100644
index 0000000..bbebc89
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/info/index.vue
@@ -0,0 +1,162 @@
+<template>
+  <div class="cube-info-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>Cube信息</h3>
+          <el-button type="primary" @click="handleGetInfo">获取信息</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="状态">
+          <el-input v-model="searchForm.state" placeholder="请输入状态" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="key" label="键" />
+        <el-table-column prop="value" label="值" />
+        <el-table-column prop="description" label="描述" />
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义接口类型
+interface CubeInfo {
+  state?: string;
+}
+
+// 定义数据类型
+interface CubeInfoData {
+  key: string;
+  value: string;
+  description: string;
+}
+
+// 表格数据
+const tableData = ref<CubeInfoData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 查询表单
+const searchForm = reactive<CubeInfo>({
+  state: '',
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/Info', {
+      params: {
+        state: searchForm.state,
+      },
+    });
+
+    // 处理响应数据
+    if (response && typeof response === 'object') {
+      const dataArray: CubeInfoData[] = [];
+      Object.keys(response).forEach((key) => {
+        const value = response[key as keyof typeof response];
+        dataArray.push({
+          key,
+          value: String(value),
+          description: `${key}的值`,
+        });
+      });
+      tableData.value = dataArray;
+      total.value = dataArray.length;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 获取信息
+const handleGetInfo = () => {
+  loadData();
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 搜索
+const handleSearch = () => {
+  currentPage.value = 1;
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.state = '';
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-info-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +186 -0
diff --git a/apps/cube-v1/src/pages/cube/lookup/index.vue b/apps/cube-v1/src/pages/cube/lookup/index.vue
new file mode 100644
index 0000000..d797ca9
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/lookup/index.vue
@@ -0,0 +1,186 @@
+<template>
+  <div class="cube-lookup-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>Cube Lookup 查询</h3>
+          <el-button type="primary" @click="handleLookup">查询</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="代码">
+          <el-input v-model="searchForm.codes" placeholder="请输入代码,多个用逗号分隔" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleLookup">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="code" label="代码" width="120" />
+        <el-table-column prop="name" label="名称" min-width="150" />
+        <el-table-column prop="value" label="值" min-width="200" />
+        <el-table-column prop="description" label="描述" min-width="200" />
+        <el-table-column prop="category" label="分类" width="120" />
+        <el-table-column prop="sort" label="排序" width="80" />
+        <el-table-column prop="status" label="状态" width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.status ? 'success' : 'danger'">
+              {{ scope.row.status ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义接口类型
+interface LookupParams {
+  codes: string;
+}
+
+interface LookupData {
+  code: string;
+  name: string;
+  value: string;
+  description: string;
+  category: string;
+  sort: number;
+  status: boolean;
+}
+
+// 表格数据
+const tableData = ref<LookupData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 查询表单
+const searchForm = reactive<LookupParams>({
+  codes: '',
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/Lookup', {
+      params: {
+        codes: searchForm.codes || undefined,
+      },
+    });
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        code: item.code || item.key || `CODE_${index + 1}`,
+        name: item.name || item.displayName || '',
+        value: item.value || item.val || '',
+        description: item.description || item.desc || item.remark || '',
+        category: item.category || item.type || '',
+        sort: item.sort || item.order || 0,
+        status: item.status !== false,
+      }));
+      total.value = response.length;
+    } else if (response && typeof response === 'object') {
+      // 如果返回的是对象,尝试转换为数组
+      const lookupList: LookupData[] = [];
+      Object.keys(response).forEach((key, index) => {
+        const item = response[key as keyof typeof response];
+        lookupList.push({
+          code: key,
+          name: typeof item === 'object' && item !== null ? (item as Record<string, unknown>).name as string || key : key,
+          value: String(item),
+          description: typeof item === 'object' && item !== null ? (item as Record<string, unknown>).description as string || '' : '',
+          category: typeof item === 'object' && item !== null ? (item as Record<string, unknown>).category as string || '' : '',
+          sort: index,
+          status: true,
+        });
+      });
+      tableData.value = lookupList;
+      total.value = lookupList.length;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 查询
+const handleLookup = () => {
+  currentPage.value = 1;
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.codes = '';
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-lookup-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +202 -0
diff --git a/apps/cube-v1/src/pages/cube/save-layout/index.vue b/apps/cube-v1/src/pages/cube/save-layout/index.vue
new file mode 100644
index 0000000..e175a01
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/save-layout/index.vue
@@ -0,0 +1,202 @@
+<template>
+  <div class="save-layout-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>保存布局配置</h3>
+          <el-button type="primary" @click="handleSaveLayout">保存布局</el-button>
+        </div>
+      </template>
+
+      <el-form :model="layoutForm" :rules="formRules" ref="formRef" label-width="120px" class="layout-form">
+        <el-form-item label="用户ID" prop="userid">
+          <el-input-number v-model="layoutForm.userid" placeholder="请输入用户ID" :min="0" />
+        </el-form-item>
+        <el-form-item label="分类" prop="category">
+          <el-input v-model="layoutForm.category" placeholder="请输入分类" />
+        </el-form-item>
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="layoutForm.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="配置值" prop="value">
+          <el-input
+            v-model="layoutForm.value"
+            type="textarea"
+            :rows="10"
+            placeholder="请输入配置值(JSON格式)"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSaveLayout" :loading="saving">保存布局</el-button>
+          <el-button @click="resetForm">重置</el-button>
+          <el-button @click="formatJson">格式化JSON</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 保存历史记录 -->
+      <el-card v-if="saveHistory.length > 0" class="history-card">
+        <template #header>
+          <h4>保存历史</h4>
+        </template>
+        <el-table :data="saveHistory" border style="width: 100%">
+          <el-table-column prop="userid" label="用户ID" width="80" />
+          <el-table-column prop="category" label="分类" width="120" />
+          <el-table-column prop="name" label="名称" min-width="150" />
+          <el-table-column prop="value" label="配置值" min-width="200" show-overflow-tooltip />
+          <el-table-column prop="saveTime" label="保存时间" width="160" />
+          <el-table-column label="操作" width="120">
+            <template #default="scope">
+              <el-button type="primary" size="small" @click="loadHistory(scope.row)">载入</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
+
+// 定义接口类型
+interface SaveLayoutParams {
+  userid?: number;
+  category?: string;
+  name?: string;
+  value?: string;
+}
+
+interface HistoryItem extends SaveLayoutParams {
+  saveTime: string;
+}
+
+// 表单引用
+const formRef = ref<FormInstance | null>(null);
+const saving = ref(false);
+
+// 表单数据
+const layoutForm = reactive<SaveLayoutParams>({
+  userid: 0,
+  category: '',
+  name: '',
+  value: '',
+});
+
+// 保存历史
+const saveHistory = ref<HistoryItem[]>([]);
+
+// 表单验证规则
+const formRules = reactive<FormRules>({
+  userid: [
+    { required: true, message: '请输入用户ID', trigger: 'blur' },
+  ],
+  category: [
+    { required: true, message: '请输入分类', trigger: 'blur' },
+  ],
+  name: [
+    { required: true, message: '请输入名称', trigger: 'blur' },
+  ],
+  value: [
+    { required: true, message: '请输入配置值', trigger: 'blur' },
+  ],
+});
+
+// 保存布局
+const handleSaveLayout = async () => {
+  if (!formRef.value) return;
+
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      saving.value = true;
+      try {
+        await request.post('/Cube/SaveLayout', null, {
+          params: {
+            userid: layoutForm.userid,
+            category: layoutForm.category,
+            name: layoutForm.name,
+            value: layoutForm.value,
+          },
+        });
+
+        ElMessage.success('布局保存成功');
+
+        // 添加到历史记录
+        saveHistory.value.unshift({
+          ...layoutForm,
+          saveTime: new Date().toLocaleString(),
+        });
+
+        // 保持历史记录在10条以内
+        if (saveHistory.value.length > 10) {
+          saveHistory.value = saveHistory.value.slice(0, 10);
+        }
+
+      } catch (error) {
+        ElMessage.error('布局保存失败');
+        console.error('Save layout error:', error);
+      } finally {
+        saving.value = false;
+      }
+    }
+  });
+};
+
+// 重置表单
+const resetForm = () => {
+  if (formRef.value) {
+    formRef.value.resetFields();
+  }
+  Object.assign(layoutForm, {
+    userid: 0,
+    category: '',
+    name: '',
+    value: '',
+  });
+};
+
+// 格式化JSON
+const formatJson = () => {
+  if (layoutForm.value) {
+    try {
+      const parsed = JSON.parse(layoutForm.value);
+      layoutForm.value = JSON.stringify(parsed, null, 2);
+      ElMessage.success('JSON格式化成功');
+    } catch {
+      ElMessage.error('JSON格式不正确');
+    }
+  }
+};
+
+// 载入历史记录
+const loadHistory = (item: HistoryItem) => {
+  Object.assign(layoutForm, {
+    userid: item.userid,
+    category: item.category,
+    name: item.name,
+    value: item.value,
+  });
+  ElMessage.success('历史记录已载入');
+};
+</script>
+
+<style scoped>
+.save-layout-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.layout-form {
+  max-width: 800px;
+}
+
+.history-card {
+  margin-top: 20px;
+}
+</style>
Added +327 -0
diff --git a/apps/cube-v1/src/pages/cube/set-page-config/index.vue b/apps/cube-v1/src/pages/cube/set-page-config/index.vue
new file mode 100644
index 0000000..63fb94c
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/set-page-config/index.vue
@@ -0,0 +1,327 @@
+<template>
+  <div class="set-page-config-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>设置页面配置</h3>
+          <el-button type="primary" @click="handleSetConfig">保存配置</el-button>
+        </div>
+      </template>
+
+      <el-form :model="configForm" :rules="formRules" ref="formRef" label-width="120px" class="config-form">
+        <el-form-item label="类型" prop="kind">
+          <el-input v-model="configForm.kind" placeholder="请输入配置类型" />
+        </el-form-item>
+        <el-form-item label="页面" prop="page">
+          <el-input v-model="configForm.page" placeholder="请输入页面名称" />
+        </el-form-item>
+        <el-form-item label="配置数据" prop="configData">
+          <el-input
+            v-model="configForm.configData"
+            type="textarea"
+            :rows="15"
+            placeholder="请输入配置数据(JSON格式)"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSetConfig" :loading="saving">保存配置</el-button>
+          <el-button @click="resetForm">重置</el-button>
+          <el-button @click="formatJson">格式化JSON</el-button>
+          <el-button @click="validateJson">验证JSON</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 配置模板 -->
+      <el-card class="template-card">
+        <template #header>
+          <h4>配置模板</h4>
+        </template>
+        <el-row :gutter="20">
+          <el-col :span="8" v-for="template in configTemplates" :key="template.name">
+            <el-card class="template-item" @click="loadTemplate(template)">
+              <h5>{{ template.name }}</h5>
+              <p>{{ template.description }}</p>
+            </el-card>
+          </el-col>
+        </el-row>
+      </el-card>
+
+      <!-- 保存历史记录 -->
+      <el-card v-if="saveHistory.length > 0" class="history-card">
+        <template #header>
+          <h4>保存历史</h4>
+        </template>
+        <el-table :data="saveHistory" border style="width: 100%">
+          <el-table-column prop="kind" label="类型" width="150" />
+          <el-table-column prop="page" label="页面" width="150" />
+          <el-table-column prop="configData" label="配置数据" min-width="200" show-overflow-tooltip />
+          <el-table-column prop="saveTime" label="保存时间" width="160" />
+          <el-table-column label="操作" width="120">
+            <template #default="scope">
+              <el-button type="primary" size="small" @click="loadHistory(scope.row)">载入</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
+
+// 定义接口类型
+interface SetConfigParams {
+  kind?: string;
+  page?: string;
+  configData?: string;
+}
+
+interface HistoryItem extends SetConfigParams {
+  saveTime: string;
+}
+
+interface ConfigTemplate {
+  name: string;
+  description: string;
+  kind: string;
+  page: string;
+  data: string;
+}
+
+// 表单引用
+const formRef = ref<FormInstance | null>(null);
+const saving = ref(false);
+
+// 表单数据
+const configForm = reactive<SetConfigParams>({
+  kind: '',
+  page: '',
+  configData: '',
+});
+
+// 保存历史
+const saveHistory = ref<HistoryItem[]>([]);
+
+// 配置模板
+const configTemplates = ref<ConfigTemplate[]>([
+  {
+    name: '表格配置',
+    description: '数据表格的基本配置',
+    kind: 'table',
+    page: 'list',
+    data: JSON.stringify({
+      columns: [
+        { prop: 'id', label: 'ID', width: 80 },
+        { prop: 'name', label: '名称', minWidth: 150 },
+        { prop: 'status', label: '状态', width: 100 }
+      ],
+      pagination: {
+        pageSize: 20,
+        pageSizes: [10, 20, 50, 100]
+      }
+    }, null, 2)
+  },
+  {
+    name: '表单配置',
+    description: '表单字段的配置',
+    kind: 'form',
+    page: 'edit',
+    data: JSON.stringify({
+      fields: [
+        { name: 'name', label: '名称', type: 'input', required: true },
+        { name: 'email', label: '邮箱', type: 'input', required: true },
+        { name: 'status', label: '状态', type: 'switch', required: false }
+      ],
+      layout: {
+        labelWidth: '100px',
+        size: 'default'
+      }
+    }, null, 2)
+  },
+  {
+    name: '菜单配置',
+    description: '页面菜单的配置',
+    kind: 'menu',
+    page: 'navigation',
+    data: JSON.stringify({
+      items: [
+        { name: '首页', path: '/home', icon: 'home' },
+        { name: '用户管理', path: '/users', icon: 'user' },
+        { name: '设置', path: '/settings', icon: 'setting' }
+      ],
+      style: {
+        theme: 'dark',
+        collapsed: false
+      }
+    }, null, 2)
+  }
+]);
+
+// 表单验证规则
+const formRules = reactive<FormRules>({
+  kind: [
+    { required: true, message: '请输入配置类型', trigger: 'blur' },
+  ],
+  page: [
+    { required: true, message: '请输入页面名称', trigger: 'blur' },
+  ],
+  configData: [
+    { required: true, message: '请输入配置数据', trigger: 'blur' },
+  ],
+});
+
+// 设置配置
+const handleSetConfig = async () => {
+  if (!formRef.value) return;
+
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      // 验证JSON格式
+      try {
+        JSON.parse(configForm.configData || '{}');
+      } catch {
+        ElMessage.error('配置数据不是有效的JSON格式');
+        return;
+      }
+
+      saving.value = true;
+      try {
+        await request.post('/Cube/SetPageConfig', JSON.parse(configForm.configData || '{}'), {
+          params: {
+            kind: configForm.kind,
+            page: configForm.page,
+          },
+        });
+
+        ElMessage.success('配置保存成功');
+
+        // 添加到历史记录
+        saveHistory.value.unshift({
+          ...configForm,
+          saveTime: new Date().toLocaleString(),
+        });
+
+        // 保持历史记录在10条以内
+        if (saveHistory.value.length > 10) {
+          saveHistory.value = saveHistory.value.slice(0, 10);
+        }
+
+      } catch (error) {
+        ElMessage.error('配置保存失败');
+        console.error('Set page config error:', error);
+      } finally {
+        saving.value = false;
+      }
+    }
+  });
+};
+
+// 重置表单
+const resetForm = () => {
+  if (formRef.value) {
+    formRef.value.resetFields();
+  }
+  Object.assign(configForm, {
+    kind: '',
+    page: '',
+    configData: '',
+  });
+};
+
+// 格式化JSON
+const formatJson = () => {
+  if (configForm.configData) {
+    try {
+      const parsed = JSON.parse(configForm.configData);
+      configForm.configData = JSON.stringify(parsed, null, 2);
+      ElMessage.success('JSON格式化成功');
+    } catch {
+      ElMessage.error('JSON格式不正确');
+    }
+  }
+};
+
+// 验证JSON
+const validateJson = () => {
+  if (!configForm.configData) {
+    ElMessage.warning('请先输入配置数据');
+    return;
+  }
+
+  try {
+    JSON.parse(configForm.configData);
+    ElMessage.success('JSON格式验证通过');
+  } catch {
+    ElMessage.error('JSON格式验证失败');
+  }
+};
+
+// 载入模板
+const loadTemplate = (template: ConfigTemplate) => {
+  Object.assign(configForm, {
+    kind: template.kind,
+    page: template.page,
+    configData: template.data,
+  });
+  ElMessage.success(`模板 "${template.name}" 已载入`);
+};
+
+// 载入历史记录
+const loadHistory = (item: HistoryItem) => {
+  Object.assign(configForm, {
+    kind: item.kind,
+    page: item.page,
+    configData: item.configData,
+  });
+  ElMessage.success('历史记录已载入');
+};
+</script>
+
+<style scoped>
+.set-page-config-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.config-form {
+  max-width: 800px;
+}
+
+.template-card {
+  margin-top: 20px;
+}
+
+.template-item {
+  cursor: pointer;
+  transition: all 0.3s;
+  margin-bottom: 10px;
+}
+
+.template-item:hover {
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  transform: translateY(-2px);
+}
+
+.template-item h5 {
+  margin: 0 0 8px 0;
+  color: #409eff;
+}
+
+.template-item p {
+  margin: 0;
+  color: #666;
+  font-size: 12px;
+}
+
+.history-card {
+  margin-top: 20px;
+}
+</style>
Added +190 -0
diff --git a/apps/cube-v1/src/pages/cube/user-search/index.vue b/apps/cube-v1/src/pages/cube/user-search/index.vue
new file mode 100644
index 0000000..97e2db1
--- /dev/null
+++ b/apps/cube-v1/src/pages/cube/user-search/index.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="cube-user-search-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>用户搜索</h3>
+          <el-button type="primary" @click="handleSearch">搜索用户</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="角色ID">
+          <el-input-number v-model="searchForm.roleId" :min="0" placeholder="角色ID" />
+        </el-form-item>
+        <el-form-item label="部门ID">
+          <el-input-number v-model="searchForm.departmentId" :min="0" placeholder="部门ID" />
+        </el-form-item>
+        <el-form-item label="关键字">
+          <el-input v-model="searchForm.key" placeholder="请输入关键字" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <el-table :data="tableData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="name" label="用户名" min-width="120" />
+        <el-table-column prop="displayName" label="显示名称" min-width="120" />
+        <el-table-column prop="email" label="邮箱" min-width="150" />
+        <el-table-column prop="mobile" label="手机号" min-width="120" />
+        <el-table-column prop="roleId" label="角色ID" width="80" />
+        <el-table-column prop="departmentId" label="部门ID" width="80" />
+        <el-table-column prop="createTime" label="创建时间" width="160" />
+        <el-table-column label="状态" width="80">
+          <template #default="scope">
+            <el-tag :type="scope.row.enable ? 'success' : 'danger'">
+              {{ scope.row.enable ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, onMounted } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义搜索参数类型
+interface UserSearchParams {
+  roleId: number;
+  departmentId: number;
+  key: string;
+}
+
+// 定义用户数据类型
+interface UserData {
+  id: number;
+  name: string;
+  displayName: string;
+  email: string;
+  mobile: string;
+  roleId: number;
+  departmentId: number;
+  createTime: string;
+  enable: boolean;
+}
+
+// 表格数据
+const tableData = ref<UserData[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const currentPage = ref(1);
+const pageSize = ref(10);
+
+// 查询表单
+const searchForm = reactive<UserSearchParams>({
+  roleId: 0,
+  departmentId: 0,
+  key: '',
+});
+
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const response = await request.get('/Cube/UserSearch', {
+      params: {
+        roleId: searchForm.roleId || undefined,
+        departmentId: searchForm.departmentId || undefined,
+        key: searchForm.key || undefined,
+      },
+    });
+
+    // 处理响应数据
+    if (Array.isArray(response)) {
+      tableData.value = response.map((item, index) => ({
+        id: item.id || index + 1,
+        name: item.name || `用户${index + 1}`,
+        displayName: item.displayName || item.name || `用户${index + 1}`,
+        email: item.email || item.mail || '',
+        mobile: item.mobile || item.phone || '',
+        roleId: item.roleId || item.roleID || 0,
+        departmentId: item.departmentId || item.departmentID || 0,
+        createTime: item.createTime || new Date().toLocaleString(),
+        enable: item.enable !== false,
+      }));
+      total.value = response.length;
+    } else {
+      tableData.value = [];
+      total.value = 0;
+    }
+  } catch {
+    tableData.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 页码变更处理
+const handleCurrentChange = (page: number) => {
+  currentPage.value = page;
+  loadData();
+};
+
+// 每页显示条数变更处理
+const handleSizeChange = (size: number) => {
+  pageSize.value = size;
+  currentPage.value = 1;
+  loadData();
+};
+
+// 搜索
+const handleSearch = () => {
+  currentPage.value = 1;
+  loadData();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.roleId = 0;
+  searchForm.departmentId = 0;
+  searchForm.key = '';
+  currentPage.value = 1;
+  loadData();
+};
+
+// 初始化加载数据
+onMounted(() => {
+  loadData();
+});
+</script>
+
+<style scoped>
+.cube-user-search-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.pagination {
+  margin-top: 20px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>
Added +252 -0
diff --git a/apps/cube-v1/src/pages/home/index.vue b/apps/cube-v1/src/pages/home/index.vue
new file mode 100644
index 0000000..6456098
--- /dev/null
+++ b/apps/cube-v1/src/pages/home/index.vue
@@ -0,0 +1,252 @@
+<template>
+  <div class="home-container">
+    <el-card class="welcome-card">
+      <template #header>
+        <h1>Cube V1 API 管理系统</h1>
+        <p>基于 v1_OpenAPI.json 自动生成的 API 管理界面</p>
+      </template>
+
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-card class="api-group-card">
+            <template #header>
+              <h3>🎯 Cube API</h3>
+            </template>
+            <div class="api-list">
+              <el-button
+                v-for="api in cubeApis"
+                :key="api.name"
+                type="primary"
+                @click="navigateToApi(api.path)"
+                class="api-button"
+              >
+                {{ api.name }}
+              </el-button>
+            </div>
+          </el-card>
+        </el-col>
+
+        <el-col :span="12">
+          <el-card class="api-group-card">
+            <template #header>
+              <h3>🔐 SSO API</h3>
+            </template>
+            <div class="api-list">
+              <el-button
+                v-for="api in ssoApis"
+                :key="api.name"
+                type="success"
+                @click="navigateToApi(api.path)"
+                class="api-button"
+              >
+                {{ api.name }}
+              </el-button>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <!-- 统计信息 -->
+    <el-card class="stats-card">
+      <template #header>
+        <h3>📊 统计信息</h3>
+      </template>
+      <el-row :gutter="20">
+        <el-col :span="6">
+          <el-statistic title="Cube API 数量" :value="cubeApis.length" />
+        </el-col>
+        <el-col :span="6">
+          <el-statistic title="SSO API 数量" :value="ssoApis.length" />
+        </el-col>
+        <el-col :span="6">
+          <el-statistic title="总 API 数量" :value="cubeApis.length + ssoApis.length" />
+        </el-col>
+        <el-col :span="6">
+          <el-statistic title="页面数量" :value="cubeApis.length + ssoApis.length" />
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <!-- 最近访问 -->
+    <el-card class="recent-card" v-if="recentVisited.length > 0">
+      <template #header>
+        <h3>🕒 最近访问</h3>
+      </template>
+      <div class="recent-list">
+        <el-tag
+          v-for="item in recentVisited"
+          :key="item.path"
+          @click="navigateToApi(item.path)"
+          class="recent-tag"
+          type="info"
+        >
+          {{ item.name }}
+        </el-tag>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+
+interface ApiItem {
+  name: string;
+  path: string;
+  method: string;
+  description: string;
+}
+
+const router = useRouter();
+
+// Cube API 列表
+const cubeApis = reactive<ApiItem[]>([
+  { name: 'Cube 信息', path: '/Cube/Info', method: 'GET', description: '获取 Cube 系统信息' },
+  { name: 'API 列表', path: '/Cube/Apis', method: 'GET', description: '获取所有可用的 API 列表' },
+  { name: '用户搜索', path: '/Cube/UserSearch', method: 'GET', description: '搜索用户信息' },
+  { name: '部门搜索', path: '/Cube/DepartmentSearch', method: 'GET', description: '搜索部门信息' },
+  { name: '获取区域', path: '/Cube/GetArea', method: 'GET', description: '获取指定区域信息' },
+  { name: '区域子节点', path: '/Cube/AreaChilds', method: 'GET', description: '获取区域的子节点' },
+  { name: '区域父节点', path: '/Cube/AreaParents', method: 'GET', description: '获取区域的父节点' },
+  { name: '区域所有父节点', path: '/Cube/AreaAllParents', method: 'GET', description: '获取区域的所有父节点' },
+  { name: '头像管理', path: '/Cube/Avatar', method: 'GET', description: '获取用户头像' },
+  { name: '查找配置', path: '/Cube/Lookup', method: 'GET', description: '查找系统配置' },
+  { name: '保存布局', path: '/Cube/SaveLayout', method: 'POST', description: '保存页面布局配置' },
+  { name: '获取页面配置', path: '/Cube/GetPageConfig', method: 'GET', description: '获取页面配置' },
+  { name: '设置页面配置', path: '/Cube/SetPageConfig', method: 'POST', description: '设置页面配置' },
+  { name: '图片管理', path: '/Cube/Image', method: 'GET', description: '图片资源管理' },
+  { name: '文件管理', path: '/Cube/File', method: 'GET', description: '文件资源管理' },
+]);
+
+// SSO API 列表
+const ssoApis = reactive<ApiItem[]>([
+  { name: 'SSO 登录', path: '/Sso/Login', method: 'GET', description: 'SSO 登录入口' },
+  { name: '登录信息', path: '/Sso/LoginInfo', method: 'GET', description: '获取登录信息' },
+  { name: 'SSO 登出', path: '/Sso/Logout', method: 'GET', description: 'SSO 登出' },
+  { name: '绑定账户', path: '/Sso/Bind', method: 'GET', description: '绑定 SSO 账户' },
+  { name: '解绑账户', path: '/Sso/UnBind', method: 'GET', description: '解绑 SSO 账户' },
+  { name: '授权认证', path: '/Sso/Authorize', method: 'GET', description: 'OAuth 授权认证' },
+  { name: 'Auth2 认证', path: '/Sso/Auth2', method: 'GET', description: 'Auth2 认证' },
+  { name: 'Access Token', path: '/Sso/Access_Token', method: 'GET/POST', description: '获取访问令牌' },
+  { name: 'Token 管理', path: '/Sso/Token', method: 'GET/POST', description: 'Token 管理' },
+  { name: '密码令牌', path: '/Sso/PasswordToken', method: 'GET/POST', description: '密码令牌管理' },
+  { name: '用户信息', path: '/Sso/UserInfo', method: 'GET', description: '获取用户信息' },
+  { name: '刷新令牌', path: '/Sso/Refresh_Token', method: 'GET/POST', description: '刷新访问令牌' },
+  { name: '认证验证', path: '/Sso/Auth', method: 'GET', description: '认证验证' },
+  { name: '获取密钥', path: '/Sso/GetKey', method: 'GET', description: '获取加密密钥' },
+  { name: '验证令牌', path: '/Sso/Verify', method: 'GET', description: '验证令牌有效性' },
+  { name: '用户认证', path: '/Sso/UserAuth', method: 'GET/POST', description: '用户认证' },
+  { name: 'SSO 头像', path: '/Sso/Avatar', method: 'GET', description: 'SSO 用户头像' },
+]);
+
+// 最近访问记录
+const recentVisited = ref<ApiItem[]>([]);
+
+// 导航到 API 页面
+const navigateToApi = (path: string) => {
+  // 找到对应的 API 信息
+  const api = [...cubeApis, ...ssoApis].find(item => item.path === path);
+  if (api) {
+    // 添加到最近访问记录
+    const existingIndex = recentVisited.value.findIndex(item => item.path === path);
+    if (existingIndex > -1) {
+      recentVisited.value.splice(existingIndex, 1);
+    }
+    recentVisited.value.unshift(api);
+
+    // 限制最近访问记录数量
+    if (recentVisited.value.length > 10) {
+      recentVisited.value = recentVisited.value.slice(0, 10);
+    }
+  }
+
+  // 导航到页面
+  router.push(path);
+};
+</script>
+
+<style scoped>
+.home-container {
+  padding: 20px;
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+.welcome-card {
+  margin-bottom: 20px;
+}
+
+.welcome-card h1 {
+  color: #409eff;
+  margin-bottom: 10px;
+}
+
+.welcome-card p {
+  color: #666;
+  margin: 0;
+}
+
+.api-group-card {
+  height: 400px;
+  margin-bottom: 20px;
+}
+
+.api-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  max-height: 320px;
+  overflow-y: auto;
+}
+
+.api-button {
+  width: 100%;
+  justify-content: flex-start;
+  text-align: left;
+}
+
+.stats-card {
+  margin-bottom: 20px;
+}
+
+.recent-card {
+  margin-bottom: 20px;
+}
+
+.recent-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.recent-tag {
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.recent-tag:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+}
+
+/* 滚动条样式 */
+.api-list::-webkit-scrollbar {
+  width: 6px;
+}
+
+.api-list::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 3px;
+}
+
+.api-list::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+.api-list::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+</style>
Added +375 -0
diff --git a/apps/cube-v1/src/pages/sso/access-token/index.vue b/apps/cube-v1/src/pages/sso/access-token/index.vue
new file mode 100644
index 0000000..c3f7709
--- /dev/null
+++ b/apps/cube-v1/src/pages/sso/access-token/index.vue
@@ -0,0 +1,375 @@
+<template>
+  <div class="sso-access-token-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>获取 Access Token</h3>
+          <el-button type="primary" @click="handleGetAccessToken">获取 Token</el-button>
+        </div>
+      </template>
+
+      <el-tabs v-model="activeTab" class="token-tabs">
+        <!-- GET 请求 Tab -->
+        <el-tab-pane label="GET 请求" name="get">
+          <el-form :inline="true" :model="getForm" class="search-form">
+            <el-form-item label="Client ID">
+              <el-input v-model="getForm.client_id" placeholder="请输入Client ID" clearable />
+            </el-form-item>
+            <el-form-item label="Client Secret">
+              <el-input v-model="getForm.client_secret" placeholder="请输入Client Secret" clearable />
+            </el-form-item>
+            <el-form-item label="Code">
+              <el-input v-model="getForm.code" placeholder="请输入授权码" clearable />
+            </el-form-item>
+            <el-form-item label="Grant Type">
+              <el-select v-model="getForm.grant_type" placeholder="请选择Grant Type">
+                <el-option label="authorization_code" value="authorization_code" />
+                <el-option label="refresh_token" value="refresh_token" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="handleGetRequest">GET 请求</el-button>
+              <el-button @click="resetGetForm">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+
+        <!-- POST 请求 Tab -->
+        <el-tab-pane label="POST 请求" name="post">
+          <el-form :model="postForm" label-width="120px" class="post-form">
+            <el-form-item label="Client ID">
+              <el-input v-model="postForm.client_id" placeholder="请输入Client ID" />
+            </el-form-item>
+            <el-form-item label="Client Secret">
+              <el-input v-model="postForm.client_secret" placeholder="请输入Client Secret" />
+            </el-form-item>
+            <el-form-item label="Code">
+              <el-input v-model="postForm.code" placeholder="请输入授权码" />
+            </el-form-item>
+            <el-form-item label="Grant Type">
+              <el-select v-model="postForm.grant_type" placeholder="请选择Grant Type">
+                <el-option label="authorization_code" value="authorization_code" />
+                <el-option label="refresh_token" value="refresh_token" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="handlePostRequest">POST 请求</el-button>
+              <el-button @click="resetPostForm">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+      </el-tabs>
+
+      <!-- Token 结果展示 -->
+      <el-card v-if="tokenResult" class="result-card">
+        <template #header>
+          <h4>Token 结果</h4>
+        </template>
+        <el-descriptions :column="1" border>
+          <el-descriptions-item label="Access Token">
+            <div class="token-display">
+              <el-input v-model="tokenResult.access_token" readonly />
+              <el-button
+                type="primary"
+                size="small"
+                @click="copyToken(tokenResult.access_token)"
+                class="copy-btn"
+              >
+                复制
+              </el-button>
+            </div>
+          </el-descriptions-item>
+          <el-descriptions-item label="Token Type">
+            {{ tokenResult.token_type || 'Bearer' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="Expires In">
+            {{ tokenResult.expires_in ? `${tokenResult.expires_in} 秒` : '未知' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="Refresh Token" v-if="tokenResult.refresh_token">
+            <div class="token-display">
+              <el-input v-model="tokenResult.refresh_token" readonly />
+              <el-button
+                type="success"
+                size="small"
+                @click="copyToken(tokenResult.refresh_token)"
+                class="copy-btn"
+              >
+                复制
+              </el-button>
+            </div>
+          </el-descriptions-item>
+          <el-descriptions-item label="Scope">
+            {{ tokenResult.scope || '未指定' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="获取时间">
+            {{ tokenResult.timestamp }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-card>
+
+      <!-- Token 历史记录 -->
+      <el-card v-if="tokenHistory.length > 0" class="history-card">
+        <template #header>
+          <h4>Token 历史</h4>
+        </template>
+        <el-table :data="tokenHistory" border style="width: 100%">
+          <el-table-column prop="client_id" label="Client ID" width="150" show-overflow-tooltip />
+          <el-table-column prop="grant_type" label="Grant Type" width="150" />
+          <el-table-column prop="access_token" label="Access Token" min-width="200" show-overflow-tooltip />
+          <el-table-column prop="expires_in" label="过期时间" width="100" />
+          <el-table-column prop="timestamp" label="获取时间" width="160" />
+          <el-table-column label="操作" width="120">
+            <template #default="scope">
+              <el-button type="primary" size="small" @click="useToken(scope.row)">使用</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import { ElMessage } from 'element-plus';
+
+// 定义接口类型
+interface AccessTokenParams {
+  client_id?: string;
+  client_secret?: string;
+  code?: string;
+  grant_type?: string;
+}
+
+interface TokenResult {
+  access_token?: string;
+  token_type?: string;
+  expires_in?: number;
+  refresh_token?: string;
+  scope?: string;
+  timestamp: string;
+}
+
+interface TokenHistoryItem extends TokenResult, AccessTokenParams {}
+
+// 当前激活的 Tab
+const activeTab = ref('get');
+
+// GET 请求表单
+const getForm = reactive<AccessTokenParams>({
+  client_id: '',
+  client_secret: '',
+  code: '',
+  grant_type: 'authorization_code',
+});
+
+// POST 请求表单
+const postForm = reactive<AccessTokenParams>({
+  client_id: '',
+  client_secret: '',
+  code: '',
+  grant_type: 'authorization_code',
+});
+
+// Token 结果
+const tokenResult = ref<TokenResult | null>(null);
+const tokenHistory = ref<TokenHistoryItem[]>([]);
+
+// 处理 GET 请求
+const handleGetRequest = async () => {
+  if (!getForm.client_id || !getForm.client_secret) {
+    ElMessage.warning('请输入 Client ID 和 Client Secret');
+    return;
+  }
+
+  try {
+    const response = await request.get('/Sso/Access_Token', {
+      params: getForm,
+    });
+
+    const result: TokenResult = {
+      access_token: response.access_token,
+      token_type: response.token_type,
+      expires_in: response.expires_in,
+      refresh_token: response.refresh_token,
+      scope: response.scope,
+      timestamp: new Date().toLocaleString(),
+    };
+
+    tokenResult.value = result;
+
+    // 添加到历史记录
+    tokenHistory.value.unshift({
+      ...result,
+      ...getForm,
+    });
+
+    // 保持历史记录在10条以内
+    if (tokenHistory.value.length > 10) {
+      tokenHistory.value = tokenHistory.value.slice(0, 10);
+    }
+
+    ElMessage.success('Access Token 获取成功');
+  } catch {
+    ElMessage.error('Access Token 获取失败');
+  }
+};
+
+// 处理 POST 请求
+const handlePostRequest = async () => {
+  if (!postForm.client_id || !postForm.client_secret) {
+    ElMessage.warning('请输入 Client ID 和 Client Secret');
+    return;
+  }
+
+  try {
+    const response = await request.post('/Sso/Access_Token', null, {
+      params: postForm,
+    });
+
+    const result: TokenResult = {
+      access_token: response.access_token,
+      token_type: response.token_type,
+      expires_in: response.expires_in,
+      refresh_token: response.refresh_token,
+      scope: response.scope,
+      timestamp: new Date().toLocaleString(),
+    };
+
+    tokenResult.value = result;
+
+    // 添加到历史记录
+    tokenHistory.value.unshift({
+      ...result,
+      ...postForm,
+    });
+
+    // 保持历史记录在10条以内
+    if (tokenHistory.value.length > 10) {
+      tokenHistory.value = tokenHistory.value.slice(0, 10);
+    }
+
+    ElMessage.success('Access Token 获取成功');
+  } catch {
+    ElMessage.error('Access Token 获取失败');
+  }
+};
+
+// 获取 Access Token(通用方法)
+const handleGetAccessToken = () => {
+  if (activeTab.value === 'get') {
+    handleGetRequest();
+  } else {
+    handlePostRequest();
+  }
+};
+
+// 复制 Token
+const copyToken = async (token?: string) => {
+  if (!token) {
+    ElMessage.warning('Token 为空');
+    return;
+  }
+
+  try {
+    await navigator.clipboard.writeText(token);
+    ElMessage.success('Token 已复制到剪贴板');
+  } catch {
+    ElMessage.error('复制失败,请手动复制');
+  }
+};
+
+// 使用 Token(从历史记录中恢复)
+const useToken = (item: TokenHistoryItem) => {
+  tokenResult.value = {
+    access_token: item.access_token,
+    token_type: item.token_type,
+    expires_in: item.expires_in,
+    refresh_token: item.refresh_token,
+    scope: item.scope,
+    timestamp: item.timestamp,
+  };
+
+  // 同时恢复表单数据
+  if (activeTab.value === 'get') {
+    Object.assign(getForm, {
+      client_id: item.client_id,
+      client_secret: item.client_secret,
+      code: item.code,
+      grant_type: item.grant_type,
+    });
+  } else {
+    Object.assign(postForm, {
+      client_id: item.client_id,
+      client_secret: item.client_secret,
+      code: item.code,
+      grant_type: item.grant_type,
+    });
+  }
+
+  ElMessage.success('Token 信息已恢复');
+};
+
+// 重置 GET 表单
+const resetGetForm = () => {
+  Object.assign(getForm, {
+    client_id: '',
+    client_secret: '',
+    code: '',
+    grant_type: 'authorization_code',
+  });
+};
+
+// 重置 POST 表单
+const resetPostForm = () => {
+  Object.assign(postForm, {
+    client_id: '',
+    client_secret: '',
+    code: '',
+    grant_type: 'authorization_code',
+  });
+};
+</script>
+
+<style scoped>
+.sso-access-token-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.token-tabs {
+  margin-bottom: 20px;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.post-form {
+  max-width: 600px;
+}
+
+.result-card {
+  margin-top: 20px;
+}
+
+.token-display {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.copy-btn {
+  flex-shrink: 0;
+}
+
+.history-card {
+  margin-top: 20px;
+}
+</style>
Added +165 -0
diff --git a/apps/cube-v1/src/pages/sso/login/index.vue b/apps/cube-v1/src/pages/sso/login/index.vue
new file mode 100644
index 0000000..69faa8a
--- /dev/null
+++ b/apps/cube-v1/src/pages/sso/login/index.vue
@@ -0,0 +1,165 @@
+<template>
+  <div class="sso-login-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>SSO 登录</h3>
+          <el-button type="primary" @click="handleLogin">执行登录</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="loginForm" class="search-form">
+        <el-form-item label="登录名">
+          <el-input v-model="loginForm.name" placeholder="请输入登录名" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleLogin">登录</el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div v-if="loginResult" class="login-result">
+        <el-alert
+          :title="loginResult.success ? '登录成功' : '登录失败'"
+          :type="loginResult.success ? 'success' : 'error'"
+          :description="loginResult.message"
+          show-icon
+          :closable="false"
+        />
+
+        <el-table v-if="loginResult.data" :data="[loginResult.data]" border style="width: 100%; margin-top: 20px;">
+          <el-table-column prop="key" label="字段" width="150" />
+          <el-table-column prop="value" label="值" />
+        </el-table>
+      </div>
+
+      <div v-if="loading" class="loading">
+        <el-loading-directive v-loading="loading" />
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+
+// 定义登录参数类型
+interface SsoLoginParams {
+  name: string;
+}
+
+// 定义登录结果类型
+interface LoginResult {
+  success: boolean;
+  message: string;
+  data?: Record<string, unknown>;
+}
+
+// 登录表单
+const loginForm = reactive<SsoLoginParams>({
+  name: '',
+});
+
+// 状态
+const loading = ref(false);
+const loginResult = ref<LoginResult | null>(null);
+
+// 执行登录
+const handleLogin = async () => {
+  if (!loginForm.name) {
+    loginResult.value = {
+      success: false,
+      message: '请输入登录名',
+    };
+    return;
+  }
+
+  loading.value = true;
+  loginResult.value = null;
+
+  try {
+    const response = await request.get('/Sso/Login', {
+      params: {
+        name: loginForm.name,
+      },
+    });
+
+    // 处理响应数据
+    if (response) {
+      loginResult.value = {
+        success: true,
+        message: '登录请求成功',
+        data: flattenObject(response),
+      };
+    } else {
+      loginResult.value = {
+        success: false,
+        message: '登录响应为空',
+      };
+    }
+  } catch (error) {
+    loginResult.value = {
+      success: false,
+      message: `登录失败: ${error}`,
+    };
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 重置表单
+const resetForm = () => {
+  loginForm.name = '';
+  loginResult.value = null;
+};
+
+// 扁平化对象用于表格显示
+const flattenObject = (obj: Record<string, unknown>): Array<{key: string, value: string}> => {
+  const result: Array<{key: string, value: string}> = [];
+
+  const flatten = (current: Record<string, unknown>, prefix = '') => {
+    Object.keys(current).forEach(key => {
+      const value = current[key];
+      const newKey = prefix ? `${prefix}.${key}` : key;
+
+      if (value && typeof value === 'object' && !Array.isArray(value)) {
+        flatten(value as Record<string, unknown>, newKey);
+      } else {
+        result.push({
+          key: newKey,
+          value: String(value),
+        });
+      }
+    });
+  };
+
+  flatten(obj);
+  return result;
+};
+</script>
+
+<style scoped>
+.sso-login-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+
+.login-result {
+  margin-top: 20px;
+}
+
+.loading {
+  text-align: center;
+  padding: 20px;
+}
+</style>
Added +239 -0
diff --git a/apps/cube-v1/src/pages/sso/token/index.vue b/apps/cube-v1/src/pages/sso/token/index.vue
new file mode 100644
index 0000000..882631f
--- /dev/null
+++ b/apps/cube-v1/src/pages/sso/token/index.vue
@@ -0,0 +1,239 @@
+<template>
+  <div class="sso-token-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>SSO Token</h3>
+          <el-button type="primary" @click="handleGetToken">获取Token</el-button>
+        </div>
+      </template>
+
+      <el-form :model="tokenForm" :rules="tokenRules" ref="tokenFormRef" label-width="120px">
+        <el-form-item label="客户端ID" prop="client_id">
+          <el-input v-model="tokenForm.client_id" placeholder="请输入客户端ID" />
+        </el-form-item>
+        <el-form-item label="客户端密钥" prop="client_secret">
+          <el-input v-model="tokenForm.client_secret" type="password" placeholder="请输入客户端密钥" />
+        </el-form-item>
+        <el-form-item label="用户名" prop="username">
+          <el-input v-model="tokenForm.username" placeholder="请输入用户名" />
+        </el-form-item>
+        <el-form-item label="密码" prop="password">
+          <el-input v-model="tokenForm.password" type="password" placeholder="请输入密码" />
+        </el-form-item>
+        <el-form-item label="刷新令牌" prop="refresh_token">
+          <el-input v-model="tokenForm.refresh_token" placeholder="请输入刷新令牌" />
+        </el-form-item>
+        <el-form-item label="授权类型" prop="grant_type">
+          <el-select v-model="tokenForm.grant_type" placeholder="请选择授权类型">
+            <el-option label="password" value="password" />
+            <el-option label="client_credentials" value="client_credentials" />
+            <el-option label="authorization_code" value="authorization_code" />
+            <el-option label="refresh_token" value="refresh_token" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleGetToken" :loading="loading">获取Token</el-button>
+          <el-button @click="handlePostToken" :loading="loading">POST获取Token</el-button>
+          <el-button @click="resetForm">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div v-if="tokenResult" class="token-result">
+        <el-alert
+          :title="tokenResult.success ? '获取Token成功' : '获取Token失败'"
+          :type="tokenResult.success ? 'success' : 'error'"
+          :description="tokenResult.message"
+          show-icon
+          :closable="false"
+        />
+
+        <el-table v-if="tokenResult.data" :data="tokenResult.data" border style="width: 100%; margin-top: 20px;">
+          <el-table-column prop="key" label="字段" width="200" />
+          <el-table-column prop="value" label="值" />
+        </el-table>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive } from 'vue';
+import { request } from '@core/utils/request';
+import type { FormInstance, FormRules } from 'element-plus';
+
+// 定义Token参数类型
+interface SsoTokenParams {
+  client_id: string;
+  client_secret: string;
+  username: string;
+  password: string;
+  refresh_token: string;
+  grant_type: string;
+}
+
+// 定义结果类型
+interface TokenResult {
+  success: boolean;
+  message: string;
+  data?: Array<{key: string, value: string}>;
+}
+
+// 表单引用
+const tokenFormRef = ref<FormInstance | null>(null);
+
+// Token表单
+const tokenForm = reactive<SsoTokenParams>({
+  client_id: '',
+  client_secret: '',
+  username: '',
+  password: '',
+  refresh_token: '',
+  grant_type: 'password',
+});
+
+// 表单验证规则
+const tokenRules = reactive<FormRules>({
+  client_id: [
+    { required: true, message: '请输入客户端ID', trigger: 'blur' }
+  ],
+  client_secret: [
+    { required: true, message: '请输入客户端密钥', trigger: 'blur' }
+  ],
+  grant_type: [
+    { required: true, message: '请选择授权类型', trigger: 'change' }
+  ]
+});
+
+// 状态
+const loading = ref(false);
+const tokenResult = ref<TokenResult | null>(null);
+
+// GET方式获取Token
+const handleGetToken = async () => {
+  if (!tokenFormRef.value) return;
+
+  await tokenFormRef.value.validate(async (valid: boolean) => {
+    if (!valid) return;
+
+    loading.value = true;
+    tokenResult.value = null;
+
+    try {
+      const response = await request.get('/Sso/Token', {
+        params: {
+          client_id: tokenForm.client_id,
+          client_secret: tokenForm.client_secret,
+          username: tokenForm.username || undefined,
+          password: tokenForm.password || undefined,
+          refresh_token: tokenForm.refresh_token || undefined,
+          grant_type: tokenForm.grant_type,
+        },
+      });
+
+      tokenResult.value = {
+        success: true,
+        message: '获取Token成功',
+        data: flattenObject(response),
+      };
+    } catch (error) {
+      tokenResult.value = {
+        success: false,
+        message: `获取Token失败: ${error}`,
+      };
+    } finally {
+      loading.value = false;
+    }
+  });
+};
+
+// POST方式获取Token
+const handlePostToken = async () => {
+  if (!tokenFormRef.value) return;
+
+  await tokenFormRef.value.validate(async (valid: boolean) => {
+    if (!valid) return;
+
+    loading.value = true;
+    tokenResult.value = null;
+
+    try {
+      const response = await request.post('/Sso/Token', null, {
+        params: {
+          client_id: tokenForm.client_id,
+          client_secret: tokenForm.client_secret,
+          username: tokenForm.username || undefined,
+          password: tokenForm.password || undefined,
+          refresh_token: tokenForm.refresh_token || undefined,
+          grant_type: tokenForm.grant_type,
+        },
+      });
+
+      tokenResult.value = {
+        success: true,
+        message: '获取Token成功',
+        data: flattenObject(response),
+      };
+    } catch (error) {
+      tokenResult.value = {
+        success: false,
+        message: `获取Token失败: ${error}`,
+      };
+    } finally {
+      loading.value = false;
+    }
+  });
+};
+
+// 重置表单
+const resetForm = () => {
+  if (tokenFormRef.value) {
+    tokenFormRef.value.resetFields();
+  }
+  tokenResult.value = null;
+};
+
+// 扁平化对象用于表格显示
+const flattenObject = (obj: unknown): Array<{key: string, value: string}> => {
+  const result: Array<{key: string, value: string}> = [];
+
+  if (!obj || typeof obj !== 'object') {
+    return result;
+  }
+
+  const flatten = (current: Record<string, unknown>, prefix = '') => {
+    Object.keys(current).forEach(key => {
+      const value = current[key];
+      const newKey = prefix ? `${prefix}.${key}` : key;
+
+      if (value && typeof value === 'object' && !Array.isArray(value)) {
+        flatten(value as Record<string, unknown>, newKey);
+      } else {
+        result.push({
+          key: newKey,
+          value: String(value),
+        });
+      }
+    });
+  };
+
+  flatten(obj as Record<string, unknown>);
+  return result;
+};
+</script>
+
+<style scoped>
+.sso-token-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.token-result {
+  margin-top: 20px;
+}
+</style>
Added +175 -0
diff --git a/apps/cube-v1/src/routes/index.ts b/apps/cube-v1/src/routes/index.ts
new file mode 100644
index 0000000..66601ad
--- /dev/null
+++ b/apps/cube-v1/src/routes/index.ts
@@ -0,0 +1,175 @@
+import { type RouteRecordRaw } from 'vue-router';
+
+const routes: RouteRecordRaw[] = [
+  // 首页
+  {
+    path: '/',
+    name: 'home',
+    component: () => import('../pages/home/index.vue'),
+  },
+  // Cube 相关路由 - 只保留接口文档中存在的接口
+  {
+    path: '/Cube/Info',
+    name: 'cube-info',
+    component: () => import('../pages/cube/info/index.vue'),
+  },
+  {
+    path: '/Cube/Apis',
+    name: 'cube-apis',
+    component: () => import('../pages/cube/apis/index.vue'),
+  },
+  {
+    path: '/Cube/UserSearch',
+    name: 'cube-user-search',
+    component: () => import('../pages/cube/user-search/index.vue'),
+  },
+  {
+    path: '/Cube/DepartmentSearch',
+    name: 'cube-department-search',
+    component: () => import('../pages/cube/department-search/index.vue'),
+  },
+  {
+    path: '/Cube/GetArea',
+    name: 'cube-get-area',
+    component: () => import('../pages/cube/get-area/index.vue'),
+  },
+  {
+    path: '/Cube/AreaChilds',
+    name: 'cube-area-childs',
+    component: () => import('../pages/cube/area-childs/index.vue'),
+  },
+  {
+    path: '/Cube/AreaParents',
+    name: 'cube-area-parents',
+    component: () => import('../pages/cube/area-parents/index.vue'),
+  },
+  {
+    path: '/Cube/AreaAllParents',
+    name: 'cube-area-all-parents',
+    component: () => import('../pages/cube/area-all-parents/index.vue'),
+  },
+  {
+    path: '/Cube/Avatar',
+    name: 'cube-avatar',
+    component: () => import('../pages/cube/avatar/index.vue'),
+  },
+  {
+    path: '/Cube/Lookup',
+    name: 'cube-lookup',
+    component: () => import('../pages/cube/lookup/index.vue'),
+  },
+  {
+    path: '/Cube/SaveLayout',
+    name: 'cube-save-layout',
+    component: () => import('../pages/cube/save-layout/index.vue'),
+  },
+  {
+    path: '/Cube/GetPageConfig',
+    name: 'cube-get-page-config',
+    component: () => import('../pages/cube/get-page-config/index.vue'),
+  },
+  {
+    path: '/Cube/SetPageConfig',
+    name: 'cube-set-page-config',
+    component: () => import('../pages/cube/set-page-config/index.vue'),
+  },
+  {
+    path: '/Cube/Image',
+    name: 'cube-image',
+    component: () => import('../pages/cube/image/index.vue'),
+  },
+  {
+    path: '/Cube/File',
+    name: 'cube-file',
+    component: () => import('../pages/cube/file/index.vue'),
+  },
+
+  // SSO 相关路由 - 只保留接口文档中存在的接口
+  {
+    path: '/Sso/Login',
+    name: 'sso-login',
+    component: () => import('../pages/sso/login/index.vue'),
+  },
+  {
+    path: '/Sso/LoginInfo/:id?',
+    name: 'sso-login-info',
+    component: () => import('../pages/sso/login-info/index.vue'),
+  },
+  {
+    path: '/Sso/Logout',
+    name: 'sso-logout',
+    component: () => import('../pages/sso/logout/index.vue'),
+  },
+  {
+    path: '/Sso/Bind',
+    name: 'sso-bind',
+    component: () => import('../pages/sso/bind/index.vue'),
+  },
+  {
+    path: '/Sso/UnBind',
+    name: 'sso-unbind',
+    component: () => import('../pages/sso/unbind/index.vue'),
+  },
+  {
+    path: '/Sso/Authorize',
+    name: 'sso-authorize',
+    component: () => import('../pages/sso/authorize/index.vue'),
+  },
+  {
+    path: '/Sso/Auth2',
+    name: 'sso-auth2',
+    component: () => import('../pages/sso/auth2/index.vue'),
+  },
+  {
+    path: '/Sso/Access_Token',
+    name: 'sso-access-token',
+    component: () => import('../pages/sso/access-token/index.vue'),
+  },
+  {
+    path: '/Sso/Token',
+    name: 'sso-token',
+    component: () => import('../pages/sso/token/index.vue'),
+  },
+  {
+    path: '/Sso/PasswordToken',
+    name: 'sso-password-token',
+    component: () => import('../pages/sso/password-token/index.vue'),
+  },
+  {
+    path: '/Sso/UserInfo',
+    name: 'sso-user-info',
+    component: () => import('../pages/sso/user-info/index.vue'),
+  },
+  {
+    path: '/Sso/Refresh_Token',
+    name: 'sso-refresh-token',
+    component: () => import('../pages/sso/refresh-token/index.vue'),
+  },
+  {
+    path: '/Sso/Auth',
+    name: 'sso-auth',
+    component: () => import('../pages/sso/auth/index.vue'),
+  },
+  {
+    path: '/Sso/GetKey',
+    name: 'sso-get-key',
+    component: () => import('../pages/sso/get-key/index.vue'),
+  },
+  {
+    path: '/Sso/Verify',
+    name: 'sso-verify',
+    component: () => import('../pages/sso/verify/index.vue'),
+  },
+  {
+    path: '/Sso/UserAuth',
+    name: 'sso-user-auth',
+    component: () => import('../pages/sso/user-auth/index.vue'),
+  },
+  {
+    path: '/Sso/Avatar',
+    name: 'sso-avatar',
+    component: () => import('../pages/sso/avatar/index.vue'),
+  },
+];
+
+export default routes;
Added +103 -0
diff --git a/apps/cube-v1/src/types/index.ts b/apps/cube-v1/src/types/index.ts
new file mode 100644
index 0000000..928cbfd
--- /dev/null
+++ b/apps/cube-v1/src/types/index.ts
@@ -0,0 +1,103 @@
+// v1 API 相关类型定义
+
+// SSO Token 模型
+export interface SsoTokenModel {
+  client_id?: string;
+  client_secret?: string;
+  userName?: string;
+  password?: string;
+  grant_type?: string;
+}
+
+// Cube 相关接口类型
+export interface CubeInfo {
+  state?: string;
+}
+
+export interface UserSearchParams {
+  roleId?: number;
+  departmentId?: number;
+  key?: string;
+}
+
+export interface DepartmentSearchParams {
+  parentid?: number;
+  key?: string;
+}
+
+export interface AreaParams {
+  id?: number;
+  isContainSelf?: boolean;
+}
+
+export interface SaveLayoutParams {
+  userid?: number;
+  category?: string;
+  name?: string;
+  value?: string;
+}
+
+export interface PageConfigParams {
+  kind?: string;
+  page?: string;
+}
+
+// SSO 相关接口类型
+export interface SsoLoginParams {
+  name?: string;
+}
+
+export interface SsoLoginInfoParams {
+  id?: string;
+  code?: string;
+  state?: string;
+}
+
+export interface SsoAuthorizeParams {
+  client_id?: string;
+  redirect_uri?: string;
+  response_type?: string;
+  scope?: string;
+  state?: string;
+  loginUrl?: string;
+}
+
+export interface SsoTokenParams {
+  client_id?: string;
+  client_secret?: string;
+  code?: string;
+  grant_type?: string;
+  username?: string;
+  password?: string;
+  refresh_token?: string;
+}
+
+export interface SsoUserInfoParams {
+  access_token?: string;
+}
+
+export interface SsoAuthParams {
+  access_token?: string;
+  redirect_uri?: string;
+}
+
+export interface SsoVerifyParams {
+  access_token?: string;
+  redirect_uri?: string;
+}
+
+// 通用响应类型
+export interface ApiResponse<T = unknown> {
+  code?: number;
+  message?: string;
+  data?: T;
+  success?: boolean;
+}
+
+// 分页响应类型
+export interface PagedResponse<T = unknown> {
+  data?: T[];
+  total?: number;
+  pageIndex?: number;
+  pageSize?: number;
+}
Added +16 -0
diff --git a/apps/cube-v1/vite.config.ts b/apps/cube-v1/vite.config.ts
new file mode 100644
index 0000000..043138f
--- /dev/null
+++ b/apps/cube-v1/vite.config.ts
@@ -0,0 +1,16 @@
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import { resolve } from 'path';
+
+export default defineConfig({
+  plugins: [vue()],
+  resolve: {
+    alias: {
+      '@': resolve(__dirname, 'src'),
+      '@core': resolve(__dirname, '../../core'),
+    },
+  },
+  server: {
+    port: 5174,
+  },
+});