docs: 新增V30.0版本相关设计文档与指南

新增服务器启动文档、设计说明书、风险清单等核心文档
补充前端集成蓝图、多租户实施清单、上线红线检查清单
添加质量保障文档与早期业务规格书
This commit is contained in:
Ansonai
2026-03-16 01:31:26 +08:00
commit 6759d47de4
74 changed files with 9310 additions and 0 deletions

238
docs/maiteng-crawler.js Normal file
View File

@@ -0,0 +1,238 @@
/**
* 麦腾后台菜单爬虫脚本
* 用于自动探索和记录麦腾智能管理平台的所有菜单功能
*
* 使用方法:
* 1. 在浏览器中打开麦腾后台并登录
* 2. 打开浏览器开发者工具 (F12)
* 3. 切换到 Console 标签
* 4. 复制粘贴此脚本并运行
* 5. 等待探索完成后,复制输出的 JSON 数据
*/
class MaitengCrawler {
constructor() {
this.discoveredMenus = [];
this.discoveredPages = [];
this.visitedUrls = new Set();
this.delayBetweenActions = 1000; // 毫秒
}
// 等待函数
async wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 获取当前页面的菜单结构
getMenuStructure() {
const menus = [];
const menuItems = document.querySelectorAll('[role="menuitem"], .ant-menu-item, .menu-item');
menuItems.forEach((item, index) => {
const menuInfo = {
id: index,
text: item.textContent?.trim() || '',
element: item,
href: item.querySelector('a')?.href || '',
isExpanded: item.classList?.contains('expanded') || false,
isCollapsed: item.classList?.contains('collapsed') || false,
hasSubmenu: item.querySelector('ul, [role="menu"]') !== null
};
if (menuInfo.text) {
menus.push(menuInfo);
}
});
return menus;
}
// 获取当前页面信息
getCurrentPageInfo() {
return {
url: window.location.href,
title: document.title,
timestamp: new Date().toISOString(),
pageElements: this.getPageElements()
};
}
// 获取页面关键元素
getPageElements() {
const elements = {
buttons: [],
inputs: [],
tables: [],
filters: []
};
// 获取按钮
document.querySelectorAll('button, [role="button"]').forEach((btn, idx) => {
elements.buttons.push({
id: idx,
text: btn.textContent?.trim() || '',
disabled: btn.disabled || false
});
});
// 获取输入框
document.querySelectorAll('input, textarea, select').forEach((input, idx) => {
elements.inputs.push({
id: idx,
type: input.tagName?.toLowerCase() || '',
placeholder: input.placeholder || '',
name: input.name || ''
});
});
// 获取表格
document.querySelectorAll('table').forEach((table, idx) => {
elements.tables.push({
id: idx,
rowCount: table.querySelectorAll('tr')?.length || 0
});
});
return elements;
}
// 尝试展开菜单
async expandMenu(menuElement) {
try {
menuElement.click();
await this.wait(this.delayBetweenActions);
return true;
} catch (error) {
console.log('展开菜单失败:', error);
return false;
}
}
// 点击菜单项并记录页面
async clickMenuItem(menuItem) {
try {
if (menuItem.href && !menuItem.href.startsWith('javascript:')) {
if (!this.visitedUrls.has(menuItem.href)) {
this.visitedUrls.add(menuItem.href);
window.location.href = menuItem.href;
await this.wait(3000); // 等待页面加载
const pageInfo = this.getCurrentPageInfo();
this.discoveredPages.push(pageInfo);
console.log('发现新页面:', pageInfo.title);
// 返回上一页继续探索
window.history.back();
await this.wait(this.delayBetweenActions);
}
} else if (menuItem.element) {
menuItem.element.click();
await this.wait(this.delayBetweenActions);
const pageInfo = this.getCurrentPageInfo();
if (!this.visitedUrls.has(pageInfo.url)) {
this.visitedUrls.add(pageInfo.url);
this.discoveredPages.push(pageInfo);
console.log('发现新页面:', pageInfo.title);
}
}
return true;
} catch (error) {
console.log('点击菜单失败:', error);
return false;
}
}
// 主爬虫函数
async crawl() {
console.log('🚀 开始麦腾后台菜单爬虫...');
console.log('当前页面:', window.location.href);
// 获取初始菜单结构
const initialMenus = this.getMenuStructure();
console.log('发现菜单数量:', initialMenus.length);
this.discoveredMenus = initialMenus;
// 尝试展开所有可展开的菜单
for (const menu of initialMenus) {
if (menu.isCollapsed && menu.hasSubmenu) {
console.log('尝试展开菜单:', menu.text);
await this.expandMenu(menu.element);
}
}
// 重新获取展开后的菜单结构
const expandedMenus = this.getMenuStructure();
console.log('展开后菜单数量:', expandedMenus.length);
this.discoveredMenus = expandedMenus;
// 记录当前页面信息
const currentPage = this.getCurrentPageInfo();
this.discoveredPages.push(currentPage);
this.visitedUrls.add(currentPage.url);
console.log('\n✅ 爬虫完成!');
console.log('\n📊 发现的菜单:');
this.discoveredMenus.forEach((menu, idx) => {
console.log(`${idx + 1}. ${menu.text} ${menu.isExpanded ? '[展开]' : menu.isCollapsed ? '[折叠]' : ''}`);
});
console.log('\n📄 发现的页面:');
this.discoveredPages.forEach((page, idx) => {
console.log(`${idx + 1}. ${page.title} - ${page.url}`);
});
// 返回完整数据
return {
menus: this.discoveredMenus.map(m => ({
text: m.text,
href: m.href,
isExpanded: m.isExpanded,
isCollapsed: m.isCollapsed
})),
pages: this.discoveredPages.map(p => ({
url: p.url,
title: p.title,
timestamp: p.timestamp,
buttons: p.pageElements.buttons.map(b => b.text),
inputs: p.pageElements.inputs.map(i => i.placeholder || i.name)
}))
};
}
// 导出数据为JSON
exportToJSON() {
const data = {
crawlTime: new Date().toISOString(),
menus: this.discoveredMenus,
pages: this.discoveredPages
};
const jsonStr = JSON.stringify(data, null, 2);
console.log('\n📋 完整JSON数据:');
console.log(jsonStr);
// 下载到文件
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `maiteng-crawl-${Date.now()}.json`;
a.click();
URL.revokeObjectURL(url);
console.log('\n💾 JSON文件已下载');
}
}
// 使用示例
console.log('=== 麦腾后台菜单爬虫 ===');
console.log('请运行: const crawler = new MaitengCrawler(); const result = await crawler.crawl(); crawler.exportToJSON();');
// 自动运行(可选)
// (async () => {
// const crawler = new MaitengCrawler();
// const result = await crawler.crawl();
// crawler.exportToJSON();
// })();