签入版本
@@ -1,51 +1,47 @@
|
||||
// import type { DefaultTheme, LocaleSpecificConfig } from "vitepress";
|
||||
import type { DefaultTheme, LocaleSpecificConfig } from "vitepress";
|
||||
|
||||
// export const META_URL = "https://www.rxthink.cn";
|
||||
// export const META_TITLE = "RXThinkCMF";
|
||||
// export const META_DESCRIPTION = "Enterprise Admin Framework";
|
||||
export const META_URL = "https://www.easygoadmin.vip";
|
||||
export const META_TITLE = "EasyGoAdmin";
|
||||
export const META_DESCRIPTION = "Enterprise Admin Framework";
|
||||
|
||||
// export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
// description: META_DESCRIPTION,
|
||||
// head: [
|
||||
// ["meta", { property: "og:url", content: META_URL }],
|
||||
// ["meta", { property: "og:description", content: META_DESCRIPTION }],
|
||||
// ["meta", { property: "twitter:url", content: META_URL }],
|
||||
// ["meta", { property: "twitter:title", content: META_TITLE }],
|
||||
// ["meta", { property: "twitter:description", content: META_DESCRIPTION }],
|
||||
// [
|
||||
// "script",
|
||||
// {},
|
||||
// `
|
||||
// var _hmt = _hmt || [];
|
||||
// (function() {
|
||||
// var hm = document.createElement("script");
|
||||
// hm.src = "https://hm.baidu.com/hm.js?f2662051bbed33ef4673edf8bfe609fe";
|
||||
// var s = document.getElementsByTagName("script")[0];
|
||||
// s.parentNode.insertBefore(hm, s);
|
||||
// })();
|
||||
// `,
|
||||
// ],
|
||||
// ],
|
||||
//
|
||||
// themeConfig: {
|
||||
// editLink: {
|
||||
// pattern: "https://gitee.com/rxthinkcmf/RXThinkCMF_ThinkPhp8_EleVue",
|
||||
// text: "Suggest changes to this page",
|
||||
// },
|
||||
//
|
||||
// nav: [
|
||||
// { text: "Guide", link: "/en/introduction.html" },
|
||||
// ],
|
||||
//
|
||||
// sidebar: {
|
||||
// "/en/": [
|
||||
// {
|
||||
// text: "Introduction",
|
||||
// items: [
|
||||
// { text: "About", link: "/en/introduction.html" },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
description: META_DESCRIPTION,
|
||||
head: [
|
||||
["meta", { property: "og:url", content: META_URL }],
|
||||
["meta", { property: "og:description", content: META_DESCRIPTION }],
|
||||
["meta", { property: "twitter:url", content: META_URL }],
|
||||
["meta", { property: "twitter:title", content: META_TITLE }],
|
||||
["meta", { property: "twitter:description", content: META_DESCRIPTION }],
|
||||
[
|
||||
"script",
|
||||
{},
|
||||
`
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?f2662051bbed33ef4673edf8bfe609fe";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
`,
|
||||
],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
editLink: {
|
||||
pattern: "https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue",
|
||||
text: "Suggest changes to this page",
|
||||
},
|
||||
|
||||
nav: [{ text: "Guide", link: "/en/introduction.html" }],
|
||||
|
||||
sidebar: {
|
||||
"/en/": [
|
||||
{
|
||||
text: "Introduction",
|
||||
items: [{ text: "About", link: "/en/introduction.html" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export declare const SITE_URL: string;
|
||||
export declare const SITE_DESCRIPTION: string;
|
||||
export declare function stripNumberPrefix(title: string): string;
|
||||
export declare function extractDescription(md: string): string;
|
||||
export declare function extractFaqs(md: string): { q: string; a: string }[];
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* SEO/GEO 共享工具(纯 ESM,零依赖)。
|
||||
*
|
||||
* 同时被两类调用方 import:
|
||||
* 1. VitePress 配置(.ts,esbuild 打包时内联本文件)
|
||||
* 2. scripts/generate-llms-txt.mjs(Node 直接运行)
|
||||
*
|
||||
* 注意:SITE_URL 是全站唯一 URL 真相源。
|
||||
* docs 子域当前 TLS 证书为腾讯 CDN 默认证书(*.cdn.myqcloud.com,校验失败),
|
||||
* 故暂用 http;证书修复后只需改这里一处。
|
||||
*/
|
||||
|
||||
export const SITE_URL = "http://docs.goframe.elevue.easygoadmin.vip";
|
||||
|
||||
export const SITE_DESCRIPTION =
|
||||
"EasyGoAdmin 企业级多租户后台管理基座 - GoFrame v2 + Vue3 + ElementPlus";
|
||||
|
||||
/**
|
||||
* 剥离 H1/标题中的章节编号前缀,用于 <title> 与 JSON-LD headline。
|
||||
* 例:"5.10 字典模块" → "字典模块";"K. 贡献指南" → "贡献指南"。
|
||||
* 页内 H1 与侧边栏编号保持不变,仅影响 SEO 输出。
|
||||
*/
|
||||
export function stripNumberPrefix(title) {
|
||||
return String(title)
|
||||
.replace(/^(?:\d+(?:\.\d+)+|[A-Z]\.)\s+/, "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从页面 Markdown 提取 meta description:
|
||||
* 1. 首选 `:::tip xxx` 容器内的首句(141/143 页的标准 opener)
|
||||
* 2. 回退到 H1 后的第一个普通段落
|
||||
* 输出压缩为单行、去除行内 Markdown,按中文句末标点截断(≤100 字符)。
|
||||
*/
|
||||
export function extractDescription(md) {
|
||||
let body = String(md).replace(/^---[\s\S]*?\n---\s*/, "");
|
||||
|
||||
let text = "";
|
||||
const tip = body.match(/^:::\s*tip[^\n]*\n([\s\S]*?)\n:::/m);
|
||||
if (tip) {
|
||||
text = tip[1];
|
||||
} else {
|
||||
const afterH1 = body.match(/^# (?!#)(.+)$/m);
|
||||
if (afterH1) {
|
||||
const rest = body.slice((afterH1.index ?? 0) + afterH1[0].length);
|
||||
const para = rest
|
||||
.split(/\n{2,}/)
|
||||
.find(
|
||||
(p) =>
|
||||
p.trim() &&
|
||||
!/^\s*#/.test(p) &&
|
||||
!/^\s*:::/.test(p) &&
|
||||
!/^\s*```/.test(p) &&
|
||||
!/^\s*\|/.test(p),
|
||||
);
|
||||
text = para || "";
|
||||
}
|
||||
}
|
||||
|
||||
text = text
|
||||
.replace(/\s+/g, " ")
|
||||
.replace(/`([^`]+)`/g, "$1")
|
||||
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
||||
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
|
||||
.trim();
|
||||
|
||||
if (!text) return "";
|
||||
|
||||
// 按中文句末标点截取首句,上限 100 字符;截断时避免切碎词
|
||||
const m = text.match(/^.{1,100}?(?:[。!?!?]|$)/);
|
||||
let out = m ? m[0] : text.slice(0, 100);
|
||||
if (out.length < text.length && !/[。!?!?]$/.test(out)) {
|
||||
out = out.replace(/[^\s,、;:,;:]+$/, "");
|
||||
}
|
||||
return out.trim() || text.slice(0, 100);
|
||||
}
|
||||
|
||||
function cleanText(s) {
|
||||
return s
|
||||
.replace(/^:::[^\n]*$/gm, "")
|
||||
.replace(/^```[^\n]*$/gm, "")
|
||||
.replace(/`([^`]+)`/g, "$1")
|
||||
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
||||
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取页面中的 Q/A 对(用于 FAQPage JSON-LD),支持两种站内格式:
|
||||
* A. `### Q:问题` 标题式(如 zh/quickstart/faq.md)
|
||||
* B. `**Q:问题**` 加粗式(如 zh/appendix/faq.md)
|
||||
* 返回 [{ q, a }];无匹配返回 []。
|
||||
*/
|
||||
export function extractFaqs(md) {
|
||||
const body = String(md).replace(/^---[\s\S]*?\n---\s*/, "");
|
||||
let faqs = [];
|
||||
|
||||
// 格式 A:按 `### Q:` 切块,答案截断到下一个标题
|
||||
for (const part of body.split(/(?=^###\s*Q[::])/m)) {
|
||||
const m = part.match(/^###\s*Q[::]\s*([^\n]+)\n+([\s\S]*)/);
|
||||
if (!m) continue;
|
||||
let a = m[2];
|
||||
const cut = a.search(/^#{1,4}\s/m);
|
||||
if (cut >= 0) a = a.slice(0, cut);
|
||||
faqs.push({ q: cleanText(m[1]), a: cleanText(a) });
|
||||
}
|
||||
|
||||
// 格式 B:按 `**Q:` 切块
|
||||
if (!faqs.length) {
|
||||
for (const part of body.split(/(?=^\*\*Q[::])/m)) {
|
||||
const m = part.match(/^\*\*Q[::]\s*([^*]+)\*\*\s*\n+([\s\S]*)/);
|
||||
if (!m) continue;
|
||||
let a = m[2];
|
||||
const cut = a.search(/^(?:#{1,4}\s|\*\*Q)/m);
|
||||
if (cut >= 0) a = a.slice(0, cut);
|
||||
faqs.push({ q: cleanText(m[1]), a: cleanText(a) });
|
||||
}
|
||||
}
|
||||
|
||||
return faqs.filter((f) => f.q && f.a);
|
||||
}
|
||||
@@ -1,14 +1,22 @@
|
||||
import { defineConfig } from "vitepress";
|
||||
import { enConfig } from "./en";
|
||||
import { createSeoHooks } from "./seo";
|
||||
import { sharedConfig } from "./shared";
|
||||
import { zhConfig } from "./zh";
|
||||
|
||||
const seo = createSeoHooks(zhConfig.themeConfig?.sidebar);
|
||||
|
||||
export default defineConfig({
|
||||
...sharedConfig,
|
||||
ignoreDeadLinks: [
|
||||
(link) => link.includes('localhost'),
|
||||
],
|
||||
|
||||
// SEO:页面级 title/description、canonical/OG/JSON-LD、sitemap+lastmod
|
||||
transformPageData: seo.transformPageData,
|
||||
transformHead: seo.transformHead,
|
||||
sitemap: seo.sitemap,
|
||||
|
||||
locales: {
|
||||
root: { label: "简体中文", lang: "zh-CN", link: "/", ...zhConfig },
|
||||
// root: { label: "English", lang: "en-US", link: "/", ...enConfig },
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* SEO/GEO 构建期钩子(仅 Node 构建时运行,不进客户端 bundle):
|
||||
* - transformPageData:每页独立 title(去编号前缀)与 description(取 :::tip 首句)
|
||||
* - transformHead:canonical / Open Graph / twitter 卡片 / JSON-LD 结构化数据
|
||||
* - sitemap.transformItems:注入 lastmod(git 最后提交时间)并过滤 404
|
||||
*
|
||||
* 由 config/index.ts 通过 createSeoHooks(zhConfig.themeConfig?.sidebar) 挂载。
|
||||
* 依赖 extract.mjs(纯 ESM,同被 scripts/generate-llms-txt.mjs 复用)。
|
||||
*/
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { execSync } from "node:child_process";
|
||||
import {
|
||||
SITE_URL,
|
||||
extractDescription,
|
||||
extractFaqs,
|
||||
stripNumberPrefix,
|
||||
} from "./extract.mjs";
|
||||
|
||||
/** 与 vitepress HeadConfig 同构:[tag, attrs, innerHTML?] */
|
||||
type HeadTuple = [string, Record<string, any>, string?];
|
||||
|
||||
interface SideItem {
|
||||
text?: string;
|
||||
link?: string;
|
||||
items?: SideItem[];
|
||||
}
|
||||
|
||||
interface PageDataLike {
|
||||
relativePath?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
frontmatter?: Record<string, any>;
|
||||
[k: string]: any;
|
||||
}
|
||||
|
||||
interface TransformCtx {
|
||||
pageData?: PageDataLike;
|
||||
title?: string;
|
||||
description?: string;
|
||||
content?: string;
|
||||
siteConfig?: { root?: string; srcDir?: string };
|
||||
}
|
||||
|
||||
const ORG = {
|
||||
"@type": "Organization",
|
||||
name: "EasyGoAdmin",
|
||||
url: "https://www.easygoadmin.vip",
|
||||
logo: `${SITE_URL}/logo.png`,
|
||||
sameAs: [
|
||||
"https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue",
|
||||
"https://www.easygoadmin.vip",
|
||||
],
|
||||
};
|
||||
|
||||
/** 相对路径 → 站内路由(cleanUrls 关闭,正文页带 .html) */
|
||||
function routeOf(relativePath: string): string {
|
||||
if (relativePath === "index.md") return "/";
|
||||
if (relativePath === "404.md") return "/404.html";
|
||||
return `/${relativePath.replace(/\.md$/, ".html")}`;
|
||||
}
|
||||
|
||||
/** 去掉侧边栏文案前导 emoji/符号,保留 "1.1 项目介绍" 这类编号文字 */
|
||||
function cleanLabel(s?: string): string {
|
||||
return (s || "").replace(/^[^\p{L}\p{N}]+/u, "").trim();
|
||||
}
|
||||
|
||||
/** 从侧边栏构建 route → 面包屑文案链(含分组小节) */
|
||||
function buildCrumbMap(sidebar: unknown): Map<string, string[]> {
|
||||
const map = new Map<string, string[]>();
|
||||
const groups: SideItem[] = Array.isArray(sidebar)
|
||||
? sidebar
|
||||
: ((sidebar as Record<string, SideItem[]>)?.["/zh/"] ?? []);
|
||||
const walk = (items: SideItem[], trail: string[]) => {
|
||||
for (const item of items) {
|
||||
if (item.link && item.link.startsWith("/")) {
|
||||
map.set(item.link, [...trail, cleanLabel(item.text)]);
|
||||
} else if (item.items?.length) {
|
||||
walk(item.items, [...trail, cleanLabel(item.text)]);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const group of groups) {
|
||||
walk(group.items ?? [], [cleanLabel(group.text)].filter(Boolean));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/** 从渲染后的 HTML 提取 H1 纯文本(JSON-LD headline 须与页面 H1 一致) */
|
||||
function h1OfHtml(html?: string): string {
|
||||
const m = (html || "").match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
|
||||
if (!m) return "";
|
||||
return m[1]
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.trim();
|
||||
}
|
||||
|
||||
/** 从 Markdown 源提取 H1 纯文本(去除行内 markdown 标记) */
|
||||
function h1OfMd(md: string): string {
|
||||
const m = md.match(/^# (?!#)(.+)$/m);
|
||||
if (!m) return "";
|
||||
return m[1]
|
||||
.replace(/`([^`]+)`/g, "$1")
|
||||
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function createSeoHooks(sidebar: unknown) {
|
||||
const crumbs = buildCrumbMap(sidebar);
|
||||
const projectDirs: string[] = [];
|
||||
let gitDates: Map<string, string> | null = null;
|
||||
|
||||
const readMd = (relativePath: string, srcDir?: string): string => {
|
||||
try {
|
||||
return fs.readFileSync(
|
||||
path.resolve(srcDir || process.cwd(), relativePath),
|
||||
"utf8",
|
||||
);
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 项目内每个文件最后一次 git 提交的 ISO 时间。
|
||||
* 单次 git log 调用构建全量映射(key = 相对路径,与 pageData.relativePath 一致);
|
||||
* git 不可用时静默降级(sitemap 无 lastmod、JSON-LD 无 dateModified)。
|
||||
*/
|
||||
const getGitDates = (root: string): Map<string, string> => {
|
||||
if (gitDates) return gitDates;
|
||||
gitDates = new Map<string, string>();
|
||||
try {
|
||||
const out = execSync(
|
||||
"git log --format=:::%cI --name-only --relative -n 500 -- .",
|
||||
{
|
||||
cwd: root,
|
||||
encoding: "utf8",
|
||||
maxBuffer: 64 * 1024 * 1024,
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
},
|
||||
);
|
||||
let current = "";
|
||||
for (const line of out.split(/\r?\n/)) {
|
||||
if (line.startsWith(":::")) {
|
||||
current = line.slice(3).trim();
|
||||
continue;
|
||||
}
|
||||
const file = line.trim();
|
||||
if (file && current && !gitDates.has(file)) {
|
||||
gitDates.set(file, current);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// 降级:无 lastmod / dateModified
|
||||
}
|
||||
return gitDates;
|
||||
};
|
||||
|
||||
/** 每页独立 title(去 "5.10 " 编号前缀,关键词前置)与 description(:::tip 首句) */
|
||||
function transformPageData(pageData: PageDataLike, ctx?: any): Record<string, unknown> {
|
||||
const srcDir: string | undefined = ctx?.siteConfig?.srcDir;
|
||||
const root: string | undefined = ctx?.siteConfig?.root;
|
||||
if (root && !projectDirs.includes(root)) projectDirs.push(root);
|
||||
|
||||
const out: Record<string, unknown> = {};
|
||||
const rel = pageData.relativePath;
|
||||
if (rel && !pageData.frontmatter?.description) {
|
||||
const desc = extractDescription(readMd(rel, srcDir));
|
||||
if (desc) out.description = desc;
|
||||
}
|
||||
if (pageData.title) {
|
||||
out.title = stripNumberPrefix(pageData.title);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 构建期注入 canonical / OG / twitter / JSON-LD */
|
||||
function transformHead(ctx: TransformCtx): HeadTuple[] {
|
||||
const rel = ctx?.pageData?.relativePath || "";
|
||||
if (!rel || rel === "404.md") return [];
|
||||
|
||||
const route = routeOf(rel);
|
||||
const url = `${SITE_URL}${route}`;
|
||||
const title = ctx.pageData?.title || ctx.title || "";
|
||||
const desc = ctx.description || "";
|
||||
const isHome = rel === "index.md";
|
||||
const image = `${SITE_URL}/logo.png`;
|
||||
|
||||
const heads: HeadTuple[] = [
|
||||
["link", { rel: "canonical", href: url }],
|
||||
["meta", { property: "og:type", content: isHome ? "website" : "article" }],
|
||||
["meta", { property: "og:site_name", content: "EasyGoAdmin" }],
|
||||
["meta", { property: "og:locale", content: "zh_CN" }],
|
||||
["meta", { property: "og:title", content: title }],
|
||||
["meta", { property: "og:description", content: desc }],
|
||||
["meta", { property: "og:url", content: url }],
|
||||
["meta", { property: "og:image", content: image }],
|
||||
["meta", { property: "twitter:title", content: title }],
|
||||
["meta", { property: "twitter:description", content: desc }],
|
||||
["meta", { property: "twitter:url", content: url }],
|
||||
["meta", { property: "twitter:image", content: image }],
|
||||
];
|
||||
|
||||
// ---- JSON-LD ----
|
||||
const root = ctx.siteConfig?.root || projectDirs[0] || process.cwd();
|
||||
const srcDir = ctx.siteConfig?.srcDir || root;
|
||||
const lastMod = getGitDates(root).get(rel);
|
||||
const blocks: Record<string, any>[] = [];
|
||||
|
||||
if (isHome) {
|
||||
blocks.push({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
name: "EasyGoAdmin 开发文档",
|
||||
url: `${SITE_URL}/`,
|
||||
inLanguage: "zh-CN",
|
||||
description: desc,
|
||||
});
|
||||
blocks.push({ "@context": "https://schema.org", ...ORG });
|
||||
} else {
|
||||
const md = readMd(rel, srcDir);
|
||||
const article: Record<string, any> = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
headline: h1OfMd(md) || h1OfHtml(ctx.content) || title,
|
||||
description: desc,
|
||||
url,
|
||||
inLanguage: "zh-CN",
|
||||
mainEntityOfPage: { "@type": "WebPage", "@id": url },
|
||||
publisher: ORG,
|
||||
};
|
||||
if (lastMod) article.dateModified = lastMod;
|
||||
blocks.push(article);
|
||||
|
||||
const trail = crumbs.get(route);
|
||||
if (trail?.length) {
|
||||
const items: Record<string, any>[] = [
|
||||
{ "@type": "ListItem", position: 1, name: "首页", item: `${SITE_URL}/` },
|
||||
];
|
||||
trail.forEach((name, i) => {
|
||||
const node: Record<string, any> = {
|
||||
"@type": "ListItem",
|
||||
position: i + 2,
|
||||
name,
|
||||
};
|
||||
if (i === trail.length - 1) node.item = url;
|
||||
items.push(node);
|
||||
});
|
||||
blocks.push({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: items,
|
||||
});
|
||||
}
|
||||
|
||||
const faqs = extractFaqs(md);
|
||||
if (faqs.length) {
|
||||
blocks.push({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: faqs.map((f) => ({
|
||||
"@type": "Question",
|
||||
name: f.q,
|
||||
acceptedAnswer: { "@type": "Answer", text: f.a },
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 转义 "<",防止内容中出现 </script> 破坏注入
|
||||
const json = JSON.stringify(blocks).replace(/</g, "\\u003c");
|
||||
heads.push(["script", { type: "application/ld+json" }, json]);
|
||||
return heads;
|
||||
}
|
||||
|
||||
/** sitemap.xml:过滤 404/README,注入 git lastmod */
|
||||
const sitemap = {
|
||||
hostname: SITE_URL,
|
||||
transformItems(items: { url: string; lastmod?: string }[]) {
|
||||
const root = projectDirs[0] || process.cwd();
|
||||
const dates = getGitDates(root);
|
||||
const out: { url: string; lastmod?: string }[] = [];
|
||||
for (const item of items) {
|
||||
// ⚠ vitepress 传入的 item.url 是相对路径("404.html"、"zh/x.html"、""),
|
||||
// 无前导斜杠也无域名——hostname 由 SitemapStream 事后拼接。
|
||||
if (/(^|\/)404\.html$/.test(item.url)) continue; // 404 页不收录
|
||||
if (/(^|\/)README\.html$/.test(item.url)) continue; // 仓库 README 非文档页
|
||||
const p = item.url.replace(/^\//, "");
|
||||
const rel =
|
||||
p === "" || p === "index.html" ? "index.md" : p.replace(/\.html$/, ".md");
|
||||
const lastmod = dates.get(rel);
|
||||
out.push(lastmod ? { ...item, lastmod } : item);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
};
|
||||
|
||||
return { transformPageData, transformHead, sitemap };
|
||||
}
|
||||
@@ -23,6 +23,8 @@ export const slugify = (str: string): string =>
|
||||
|
||||
export const sharedConfig = defineConfig({
|
||||
title: "EasyGoAdmin",
|
||||
// 页面 <title> 后缀:「字典模块 | EasyGoAdmin 开发文档」(index.md frontmatter 可覆盖)
|
||||
titleTemplate: "EasyGoAdmin 开发文档",
|
||||
appearance: "light",
|
||||
|
||||
markdown: {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { DefaultTheme, LocaleSpecificConfig } from "vitepress";
|
||||
|
||||
export const META_URL = "http://docs.goframe.elevue.easygoadmin.vip/";
|
||||
export const META_URL = "http://docs.goframe.elevue.easygoadmin.vip";
|
||||
export const META_TITLE = "EasyGoAdmin GoFrame+ElementPlus 开发文档";
|
||||
export const META_DESCRIPTION =
|
||||
"EasyGoAdmin 企业级多租户后台管理基座 - GoFrame v2 + Vue3 + ElementPlus";
|
||||
export const META_DESCRIPTION = "EasyGoAdmin 企业级多租户后台管理基座 - GoFrame v2 + Vue3 + ElementPlus";
|
||||
|
||||
export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
description: META_DESCRIPTION,
|
||||
@@ -13,6 +12,19 @@ export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
["meta", { property: "twitter:url", content: META_URL }],
|
||||
["meta", { property: "twitter:title", content: META_TITLE }],
|
||||
["meta", { property: "twitter:description", content: META_DESCRIPTION }],
|
||||
[
|
||||
"script",
|
||||
{},
|
||||
`
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?09709f15864acfe85b0d8edd6dabcbbc";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
`,
|
||||
],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
@@ -32,8 +44,149 @@ export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
|
||||
nav: [
|
||||
{ text: "官网", link: "https://www.easygoadmin.vip" },
|
||||
{ text: "Gitee 仓库", link: "https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue" },
|
||||
{ text: "在线文档", link: "http://docs.goframe.elevue.easygoadmin.vip/" },
|
||||
{ text: "授权", link: "https://www.easygoadmin.vip/goods/detail/2" },
|
||||
{
|
||||
text: "部署文档",
|
||||
items: [
|
||||
{
|
||||
text: "EasyGoAdmin混编版GoFrame+Layui版本",
|
||||
link: "http://docs.goframe.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+ElementPlus版本",
|
||||
link: "http://docs.goframe.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+AntDesign版本",
|
||||
link: "http://docs.goframe.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+NaiveUI版本",
|
||||
link: "http://docs.goframe.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Gin+Layui版本",
|
||||
link: "http://docs.gin.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+ElementPlus版本",
|
||||
link: "http://docs.gin.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+AntDesign版本",
|
||||
link: "http://docs.gin.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+NaiveUI版本",
|
||||
link: "http://docs.gin.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Beego+Layui版本",
|
||||
link: "http://docs.beego.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+ElementPlus版本",
|
||||
link: "http://docs.beego.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+AntDesign版本",
|
||||
link: "http://docs.beego.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+NaiveUI版本",
|
||||
link: "http://docs.beego.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Iris+Layui版本",
|
||||
link: "http://docs.iris.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+ElementPlus版本",
|
||||
link: "http://docs.iris.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+AntDesign版本",
|
||||
link: "http://docs.iris.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+NaiveUI版本",
|
||||
link: "http://docs.iris.naivevue.easygoadmin.vip",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "在线演示",
|
||||
items: [
|
||||
{
|
||||
text: "EasyGoAdmin混编版GoFrame+Layui版本",
|
||||
link: "http://manage.goframe.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+ElementPlus版本",
|
||||
link: "http://manage.goframe.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+AntDesign版本",
|
||||
link: "http://manage.goframe.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离GoFrame+NaiveUI版本",
|
||||
link: "http://manage.goframe.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Gin+Layui版本",
|
||||
link: "http://manage.gin.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+ElementPlus版本",
|
||||
link: "http://manage.gin.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+AntDesign版本",
|
||||
link: "http://manage.gin.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Gin+NaiveUI版本",
|
||||
link: "http://manage.gin.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Beego+Layui版本",
|
||||
link: "http://manage.beego.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+ElementPlus版本",
|
||||
link: "http://manage.beego.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+AntDesign版本",
|
||||
link: "http://manage.beego.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Beego+NaiveUI版本",
|
||||
link: "http://manage.beego.naivevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin混编版Iris+Layui版本",
|
||||
link: "http://manage.iris.layui.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+ElementPlus版本",
|
||||
link: "http://manage.iris.elevue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+AntDesign版本",
|
||||
link: "http://manage.iris.antdvue.easygoadmin.vip",
|
||||
},
|
||||
{
|
||||
text: "EasyGoAdmin前后端分离Iris+NaiveUI版本",
|
||||
link: "http://manage.iris.naivevue.easygoadmin.vip",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "广告赞助",
|
||||
link: "/zh/other/sponsor.html",
|
||||
},
|
||||
{
|
||||
text: "相关链接",
|
||||
items: [
|
||||
@@ -173,10 +326,10 @@ export const zhConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "📄 注解系统",
|
||||
text: "📄 标签系统",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: "📄 5.18 gmeta 注解系统总览", link: "/zh/core/attributes.html" },
|
||||
{ text: "📄 5.18 gmeta 标签系统总览", link: "/zh/core/gmeta.html" },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -24,8 +24,8 @@ const asideSponsors = computed(() => {
|
||||
: [
|
||||
{
|
||||
name: "Become a sponsor",
|
||||
url: "https://www.rxthink.cn",
|
||||
img: "/sponsor/rxthinkcmf.png",
|
||||
url: "https://www.easygoadmin.vip",
|
||||
img: "/sponsor/sponsor.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -45,8 +45,8 @@ const asideSponsors = computed(() => {
|
||||
<template>
|
||||
<VPDocAsideSponsors :data="asideSponsors" />
|
||||
|
||||
<a class="banner mp" href="https://www.rxthink.cn" target="_blank">
|
||||
<img width="22" height="22" src="/sponsor/rxthinkcmf.png" />
|
||||
<a class="banner mp" href="https://www.easygoadmin.vip" target="_blank">
|
||||
<img width="22" height="22" src="/sponsor/sponsor.png" />
|
||||
<span>
|
||||
<p class="extra-info">赋能开发者</p>
|
||||
<p class="heading">企业级中台解决方案</p>
|
||||
@@ -54,8 +54,8 @@ const asideSponsors = computed(() => {
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a class="banner cert" href="https://www.rxthink.cn" target="_blank">
|
||||
<img width="22" height="22" src="/sponsor/rxthinkcmf.png" />
|
||||
<a class="banner cert" href="https://www.easygoadmin.vip" target="_blank">
|
||||
<img width="22" height="22" src="/sponsor/sponsor.png" />
|
||||
<span>
|
||||
<p class="extra-info">赋能开发者</p>
|
||||
<p class="heading">企业级中台解决方案</p>
|
||||
|
||||
@@ -67,12 +67,12 @@ const isVideoOpen = ref(false);
|
||||
<div class="watch-more">
|
||||
{{ translations.watchMoreA[site.lang] }}
|
||||
<a
|
||||
:href="mpLink || 'https://www.rxthink.cn'"
|
||||
:href="mpLink || 'https://www.easygoadmin.vip'"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
小蚂蚁云
|
||||
<img src="../../../public/logo.svg" alt="小蚂蚁云" />
|
||||
EasyGoAdmin
|
||||
<img src="../../../public/logo.svg" alt="EasyGoAdmin" />
|
||||
</a>
|
||||
{{ translations.watchMoreB[site.lang] }}
|
||||
</div>
|
||||
|
||||
@@ -4,35 +4,35 @@
|
||||
"silver": [
|
||||
{
|
||||
"alt": "企业级中台解决方案",
|
||||
"href": "https://www.rxthink.cn",
|
||||
"imgSrcDark": "/sponsor/rxthinkcmf.png",
|
||||
"imgSrcLight": "/sponsor/rxthinkcmf.png"
|
||||
"href": "https://www.easygoadmin.vip",
|
||||
"imgSrcDark": "/sponsor/sponsor.png",
|
||||
"imgSrcLight": "/sponsor/sponsor.png"
|
||||
},
|
||||
{
|
||||
"alt": "企业级中台解决方案",
|
||||
"href": "https://www.rxthink.cn",
|
||||
"imgSrcDark": "/sponsor/rxthinkcmf.png",
|
||||
"imgSrcLight": "/sponsor/rxthinkcmf.png"
|
||||
"href": "https://www.easygoadmin.vip",
|
||||
"imgSrcDark": "/sponsor/sponsor.png",
|
||||
"imgSrcLight": "/sponsor/sponsor.png"
|
||||
}
|
||||
],
|
||||
"bronze": [
|
||||
{
|
||||
"alt": "企业级中台解决方案",
|
||||
"href": "https://www.rxthink.cn",
|
||||
"imgSrcDark": "/sponsor/rxthinkcmf.png",
|
||||
"imgSrcLight": "/sponsor/rxthinkcmf.png"
|
||||
"href": "https://www.easygoadmin.vip",
|
||||
"imgSrcDark": "/sponsor/sponsor.png",
|
||||
"imgSrcLight": "/sponsor/sponsor.png"
|
||||
},
|
||||
{
|
||||
"alt": "企业级中台解决方案",
|
||||
"href": "https://www.rxthink.cn",
|
||||
"imgSrcDark": "/sponsor/rxthinkcmf.png",
|
||||
"imgSrcLight": "/sponsor/rxthinkcmf.png"
|
||||
"href": "https://www.easygoadmin.vip",
|
||||
"imgSrcDark": "/sponsor/sponsor.png",
|
||||
"imgSrcLight": "/sponsor/sponsor.png"
|
||||
},
|
||||
{
|
||||
"alt": "企业级中台解决方案",
|
||||
"href": "https://www.rxthink.cn",
|
||||
"imgSrcDark": "/sponsor/rxthinkcmf.png",
|
||||
"imgSrcLight": "/sponsor/rxthinkcmf.png"
|
||||
"href": "https://www.easygoadmin.vip",
|
||||
"imgSrcDark": "/sponsor/sponsor.png",
|
||||
"imgSrcLight": "/sponsor/sponsor.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { h } from "vue";
|
||||
import { type Theme, useRoute } from "vitepress";
|
||||
import DefaultTheme from "vitepress/theme";
|
||||
import AsideSponsors from "./components/AsideSponsors.vue";
|
||||
import VideoModuleLink from "./components/VideoModuleLink.vue";
|
||||
import "./styles/vars.css";
|
||||
import imageViewer from "vitepress-plugin-image-viewer";
|
||||
import vImageViewer from "vitepress-plugin-image-viewer/lib/vImageViewer.vue";
|
||||
@@ -18,6 +20,7 @@ const theme: Theme = {
|
||||
alt: "EasyGoAdmin",
|
||||
}),
|
||||
),
|
||||
"aside-ads-before": () => h(AsideSponsors),
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
@@ -25,6 +28,7 @@ const theme: Theme = {
|
||||
imageViewer(route);
|
||||
},
|
||||
enhanceApp({ app }) {
|
||||
app.component("VideoModuleLink", VideoModuleLink);
|
||||
app.component("vImageViewer", vImageViewer);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
head:
|
||||
- - meta
|
||||
- name: robots
|
||||
content: noindex
|
||||
---
|
||||
|
||||
# 页面不存在
|
||||
|
||||
抱歉,您访问的页面不存在或已被移动。
|
||||
|
||||
[返回首页](/) · [浏览文档](/zh/introduction)
|
||||
@@ -1,46 +0,0 @@
|
||||
# EasyGoAdmin GoFrame+ElementPlus 文档
|
||||
|
||||
基于 VitePress 构建的 EasyGoAdmin(GoFrame v2 + Vue3 + Element Plus)开发者文档站点。
|
||||
|
||||
+ 官网:[https://www.easygoadmin.vip](https://www.easygoadmin.vip)
|
||||
+ Gitee 仓库:[https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue)
|
||||
+ 在线文档:[http://docs.goframe.elevue.easygoadmin.vip/](http://docs.goframe.elevue.easygoadmin.vip/)
|
||||
|
||||
## 本地开发
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 启动开发服务器
|
||||
pnpm docs
|
||||
|
||||
# 构建静态站点
|
||||
pnpm docs:build
|
||||
|
||||
# 预览构建结果
|
||||
pnpm docs:preview
|
||||
```
|
||||
|
||||
## 文档结构
|
||||
|
||||
```
|
||||
index.md # 文档首页(hero + features)
|
||||
zh/
|
||||
├── introduction.md # 1.1 项目介绍(及 why/directory/course/tech-stack/changelog)
|
||||
├── quickstart/ # 第 2 章 快速入门
|
||||
├── guide/ # 第 3 章 模块开发实战
|
||||
├── architecture/ # 第 4 章 架构设计
|
||||
├── core/ # 第 5 章 核心功能
|
||||
├── modules/ # 第 6 章 业务模块
|
||||
├── tools/ # 第 7 章 文件处理
|
||||
├── api-spec/ # 第 8 章 接口规范与对接
|
||||
├── frontend/ # 第 9 章 前端开发
|
||||
├── generator/ # 第 10 章 代码生成器
|
||||
├── deploy/ # 第 11 章 运维部署
|
||||
├── standards/ # 第 12 章 规范标准
|
||||
├── appendix/ # 附录 A-J
|
||||
└── other/ # 附录 K-M(贡献指南、免责声明、赞助)
|
||||
```
|
||||
|
||||
侧栏与导航配置:`.vitepress/config/zh.ts`。
|
||||
|
||||
@@ -11,16 +11,19 @@ hero:
|
||||
image:
|
||||
src: /logo.svg
|
||||
alt: EasyGoAdmin
|
||||
actions:
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 开始使用
|
||||
link: /zh/introduction
|
||||
- theme: alt
|
||||
text: Gitee 仓库
|
||||
link: https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_NaiveVue
|
||||
text: 在线演示
|
||||
link: http://manage.goframe.naivevue.easygoadmin.vip
|
||||
- theme: alt
|
||||
text: 在线文档
|
||||
link: http://docs.goframe.naivevue.easygoadmin.vip
|
||||
text: 官方授权
|
||||
link: https://www.easygoadmin.vip/goods/detail/4
|
||||
- theme: alt
|
||||
text: ❤️ 成为赞助商
|
||||
link: /zh/other/sponsor.html
|
||||
|
||||
features:
|
||||
- title: 🚀 全新技术栈
|
||||
@@ -43,8 +46,8 @@ features:
|
||||
link: /zh/guide/logic.html
|
||||
linkText: 查看更多
|
||||
rel: noreferrer
|
||||
- title: 🏷️ gmeta 注解系统
|
||||
details: 请求结构体上的 gmeta 扩展标签统一驱动路由注册、权限校验、操作日志与 OpenAPI 文档,注解即事实,杜绝三处不一致。
|
||||
- title: 🏷️ gmeta 标签系统
|
||||
details: 请求结构体上的 gmeta 扩展标签统一驱动路由注册、权限校验、操作日志与 OpenAPI 文档,标签即事实,杜绝三处不一致。
|
||||
link: /zh/core/attributes.html
|
||||
linkText: 查看更多
|
||||
rel: noreferrer
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"docs": "vitepress dev .",
|
||||
"docs:build": "vitepress build .",
|
||||
"docs:llms": "node scripts/generate-llms-txt.mjs",
|
||||
"docs:build": "node scripts/generate-llms-txt.mjs && vitepress build .",
|
||||
"docs:preview": "vitepress preview ."
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
|
Before Width: | Height: | Size: 680 KiB After Width: | Height: | Size: 828 KiB |
|
Before Width: | Height: | Size: 610 KiB After Width: | Height: | Size: 557 KiB |
|
Before Width: | Height: | Size: 610 KiB After Width: | Height: | Size: 570 KiB |
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 470 KiB |
|
Before Width: | Height: | Size: 521 KiB After Width: | Height: | Size: 512 KiB |
|
Before Width: | Height: | Size: 748 KiB After Width: | Height: | Size: 795 KiB |
|
Before Width: | Height: | Size: 801 KiB After Width: | Height: | Size: 856 KiB |
|
Before Width: | Height: | Size: 647 KiB After Width: | Height: | Size: 423 KiB |
|
Before Width: | Height: | Size: 392 KiB After Width: | Height: | Size: 660 KiB |
|
Before Width: | Height: | Size: 618 KiB After Width: | Height: | Size: 554 KiB |
|
Before Width: | Height: | Size: 841 KiB After Width: | Height: | Size: 828 KiB |
|
Before Width: | Height: | Size: 530 KiB After Width: | Height: | Size: 610 KiB |
|
Before Width: | Height: | Size: 830 KiB After Width: | Height: | Size: 687 KiB |
|
Before Width: | Height: | Size: 386 KiB After Width: | Height: | Size: 428 KiB |
|
Before Width: | Height: | Size: 664 KiB After Width: | Height: | Size: 639 KiB |
|
Before Width: | Height: | Size: 862 KiB After Width: | Height: | Size: 915 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 377 KiB After Width: | Height: | Size: 414 KiB |
|
Before Width: | Height: | Size: 549 KiB After Width: | Height: | Size: 618 KiB |
|
Before Width: | Height: | Size: 411 KiB After Width: | Height: | Size: 515 KiB |
|
Before Width: | Height: | Size: 813 KiB After Width: | Height: | Size: 704 KiB |
|
Before Width: | Height: | Size: 659 KiB After Width: | Height: | Size: 728 KiB |
|
Before Width: | Height: | Size: 806 KiB After Width: | Height: | Size: 872 KiB |
|
Before Width: | Height: | Size: 733 KiB After Width: | Height: | Size: 890 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 651 KiB |
|
After Width: | Height: | Size: 761 KiB |
|
Before Width: | Height: | Size: 824 KiB After Width: | Height: | Size: 866 KiB |
|
Before Width: | Height: | Size: 830 KiB After Width: | Height: | Size: 758 KiB |
|
Before Width: | Height: | Size: 872 KiB After Width: | Height: | Size: 761 KiB |
|
Before Width: | Height: | Size: 719 KiB After Width: | Height: | Size: 685 KiB |
|
Before Width: | Height: | Size: 845 KiB After Width: | Height: | Size: 843 KiB |
|
Before Width: | Height: | Size: 771 KiB After Width: | Height: | Size: 889 KiB |
@@ -0,0 +1,185 @@
|
||||
# EasyGoAdmin GoFrame+ElementPlus 开发文档
|
||||
|
||||
> EasyGoAdmin 企业级多租户后台管理基座 - GoFrame v2 + Vue3 + ElementPlus。支持五种数据库一键切换、RBAC 按钮级权限、多租户数据隔离、声明式 CRUD 基座与代码生成器。本文档共 143 篇,按章节组织。
|
||||
|
||||
## 1. 了解项目
|
||||
|
||||
- [1.1 项目介绍](http://docs.goframe.elevue.easygoadmin.vip/zh/introduction.html): EasyGoAdmin 是企业级多租户后台管理基座,后端基于 GoFrame v2 框架,前端基于 Vue3 + ElementPlus,完全前后端分离架构。
|
||||
- [1.2 为什么选择我们](http://docs.goframe.elevue.easygoadmin.vip/zh/why.html): 选择一个后台管理基座,核心看三点:架构是否经得起二次开发、功能是否开箱即用、工程是否可持续维护。
|
||||
- [1.3 项目目录结构](http://docs.goframe.elevue.easygoadmin.vip/zh/directory.html): 在软件开发过程中,优秀的目录结构对项目的组织、开发、维护和扩展至关重要。
|
||||
- [1.4 新手入门指南](http://docs.goframe.elevue.easygoadmin.vip/zh/course.html): 本节面向第一次接触本项目的开发者,给出一条最短路径:跑起来 → 看懂一个请求 → 改一个字段 → 开发一个新模块。
|
||||
- [1.5 技术栈说明](http://docs.goframe.elevue.easygoadmin.vip/zh/tech-stack.html): 本项目以后端 GoFrame v2 + 前端 Vue3/ElementPlus 为核心,全部依赖选型遵循"主流、稳定、长期维护"原则。
|
||||
- [1.6 更新日志](http://docs.goframe.elevue.easygoadmin.vip/zh/changelog.html): 更新日志是项目演进的完整记录,帮助开发者和企业了解每个版本的能力变化与技术演进方向。
|
||||
|
||||
## 2. 快速入门
|
||||
|
||||
- [2.1 开发环境准备](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/environment.html): 本章指导您从零搭建开发环境,包括 Go、Node.js/pnpm、MySQL、Redis 的安装与配置。
|
||||
- [2.2 后端服务启动](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/backend-start.html): 后端为标准 GoFrame v2 工程,单入口 main.go,启动后监听 :8000。
|
||||
- [2.3 前端服务启动](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/frontend-start.html): 前端为 Vue3 + TypeScript + Vite + ElementPlus 工程(ui/ 目录),通过 pnpm 安装依赖后一条命令启动开发服务器,接口代理指向后端 :8000。
|
||||
- [2.4 数据库初始化](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/database-init.html): 项目以 MySQL 为规范基准数据库,五方言定稿脚本统一存放于 document/{数据库}/easygoadmin.goframe.elevue.sql。
|
||||
- [2.5 配置文件说明](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/env-vars.html): 本项目唯一运行时配置文件为 manifest/config/config.yaml,GoFrame gcfg 加载。
|
||||
- [2.6 第一个接口调试](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/first-api.html): 本节通过三个最基础的接口(健康检查 → 登录 → 带令牌调用业务接口)带你完成第一次接口调试。
|
||||
- [2.7 Docker 快速体验](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/docker.html): 项目根目录已内置完整 Docker 化文件(docker/ 目录 + 根目录 .dockerignore),一条命令拉起 后端 + MySQL + Redis 三容器全栈。
|
||||
- [2.8 常见问题 FAQ](http://docs.goframe.elevue.easygoadmin.vip/zh/quickstart/faq.html): 本节收录环境搭建与首次运行阶段最常遇到的问题。
|
||||
|
||||
## 3. 模块开发实战
|
||||
|
||||
- [3.1 概述与目标](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/overview.html): 本章以「案例演示模块(example)」为主线,完整走一遍模块开发全流程:建表 → DAO → 请求与校验 → 逻辑层 → 控制器 → 服务注册与路由 → 权限节点 → 前端联调。
|
||||
- [3.2 数据库建表](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/database.html): 建表是模块开发的第一步。
|
||||
- [3.3 DAO 数据层](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/model.html): DAO 四件(dao/{m}.go、dao/internal/{m}.go、entity、do)由 gf gen dao 或代码生成器产出,无需手写。
|
||||
- [3.4 请求与校验](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/validator.html): 本项目没有独立的"验证器文件"——请求校验由 api/v1 请求结构体上的 gvalid 标签完成,路由/权限/日志元数据由内嵌 gmeta.Meta 声明。
|
||||
- [3.5 逻辑层开发](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/logic.html): 逻辑层是业务核心。
|
||||
- [3.6 控制器开发](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/controller.html): 控制器是 HTTP 薄层,只做一件事:把解析好的请求转发给 service 接口。
|
||||
- [3.7 服务注册与路由](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/route.html): 本项目没有传统的路由表文件逐条登记——路由由 Bind 反射绑定从 gmeta 标签自动生成。
|
||||
- [3.8 权限节点配置](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/permission.html): 本项目权限校验的声明在接口 gmeta 标签,落地在菜单表的权限节点(menu.type=1)。
|
||||
- [3.9 前端联调指引](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/frontend-integration.html): 前端每个列表模块由三件套组成:api/{域}/{模块}.ts(接口)、views/{域}/{模块}/columns.ts(表格列)、
|
||||
- [3.10 完整代码清单](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/code-list.html): 本节汇总 example 模块的后端四件完整代码(api / controller / service / logic),全部摘自项目实际文件(含注释),可作为手动开发新模块的对照模板。
|
||||
- [3.11 常见问题与排错](http://docs.goframe.elevue.easygoadmin.vip/zh/guide/faq.html): 本节收录模块开发阶段的高频问题,按「路由/编译/数据/权限/生成器」分组。
|
||||
|
||||
## 4. 架构设计
|
||||
|
||||
- [4.1 整体架构概览](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/overview.html): 系统采用分层架构 + 声明式基座 + 全局钩子横切 + gmeta 反射标签的组合。
|
||||
- [4.2 请求处理链路](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/request-flow.html): 一个受保护的写请求依次穿过七层中间件与 Bind 包装层。
|
||||
- [4.3 后端分层架构](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/backend-layer.html): 后端五层:api / controller / service / logic / dao。
|
||||
- [4.4 前端分层架构](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/frontend-layer.html): 前端采用 Vue3 Composition API + TypeScript + Pinia + ElementPlus,分层为:views(页面)→ components(公共组件)→
|
||||
- [4.5 目录结构设计](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/directory-design.html): 目录结构是架构决策的物理体现。
|
||||
- [4.6 核心基座体系](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/base-classes.html): 本项目没有传统"基类继承"——用组合替代继承:ModuleSpec 泛型基座(module_spec.go)承担 CRUD 流水线,base.go 共享能力层提供横切函数。
|
||||
- [4.7 横切机制](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/cross-cutting.html): 审计字段盖章、软删除改写、租户隔离三类横切逻辑不在任何业务代码中出现——它们统一在 gdb 模型钩子层(internal/model/hooks)执行。
|
||||
- [4.8 缓存架构设计](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/cache.html): 缓存实现为 utility/cache 统一门面:Redis 优先,连接失败或运行期出错自动降级进程内存 gcache(UsingMemory() 可查)。
|
||||
- [4.9 数据库设计](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/database-design.html): 25 张业务表、统一审计列、13 个唯一索引、9 张租户级表、注释枚举驱动字典——本节给出数据模型全景与 ER 关系。
|
||||
- [4.10 安全架构设计](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/security.html): 安全设计按威胁面组织:每项威胁对应明确控制措施与代码落点。
|
||||
- [4.11 扩展性设计](http://docs.goframe.elevue.easygoadmin.vip/zh/architecture/extensibility.html): 扩展性来自两方面:一是标准变更的操作清单(按变更类型给出 checklist,不漏步骤、不变异架构);二是逃生舱挂点(基座装不下的需求有明确的合法出口)。
|
||||
|
||||
## 5. 核心功能
|
||||
|
||||
- [5.1 用户认证(JWT 双令牌)](http://docs.goframe.elevue.easygoadmin.vip/zh/core/jwt.html): JWT(JSON Web Token)是系统核心认证机制。
|
||||
- [5.2 认证流程实战](http://docs.goframe.elevue.easygoadmin.vip/zh/core/auth-flow.html): 本节以登录闭环为主线,串起验证码、用户查找、状态校验、密码比对、令牌签发、登录日志、在线登记八个步骤,给出完整时序图与失败分支处理。
|
||||
- [5.3 验证码机制](http://docs.goframe.elevue.easygoadmin.vip/zh/core/captcha.html): 图形验证码由 utility/captcha 生成:6 位字符(排除易混淆字符)、PNG 渲染(TTF 字体 + 干扰线/噪点)、Redis 缓存 300 秒、一次性校验。
|
||||
- [5.4 权限管理(RBAC)](http://docs.goframe.elevue.easygoadmin.vip/zh/core/rbac.html): RBAC(基于角色的访问控制)链路:user →(user_role)→ role →(role_menu)→ menu(type=1 权限节点)。
|
||||
- [5.5 跨域资源共享](http://docs.goframe.elevue.easygoadmin.vip/zh/core/cors.html): CORS 由中间件链第一层处理(middleware/cors.go)。
|
||||
- [5.6 密码加密服务](http://docs.goframe.elevue.easygoadmin.vip/zh/core/password.html): 密码加密由 utility/crypto 实现:bcrypt(password+salt) 双重加盐。
|
||||
- [5.7 演示模式](http://docs.goframe.elevue.easygoadmin.vip/zh/core/demo-mode.html): 演示模式(app.demo)为对外演示站设计:读操作照常、写操作一律拦截。
|
||||
- [5.8 多租户隔离](http://docs.goframe.elevue.easygoadmin.vip/zh/core/tenant.html): 多租户是硬隔离:9 张租户级表的 tenant_id 过滤与盖章由全局钩子强制执行,业务代码零感知、不可绕过。
|
||||
- [5.9 数据权限](http://docs.goframe.elevue.easygoadmin.vip/zh/core/data-scope.html): 角色数据权限(role.data_scope)是叠加在租户隔离之上的第二层行级过滤,四档可配置。
|
||||
- [5.10 字典模块](http://docs.goframe.elevue.easygoadmin.vip/zh/core/dict.html): 字典是枚举数据的唯一真相:dict(字典)+ dict_item(字典项)两级结构,驱动全系统的 {field}Text 显示名。
|
||||
- [5.11 字典配置与使用](http://docs.goframe.elevue.easygoadmin.vip/zh/core/dict-guide.html): 本节是 {field}Text 字典驱动的使用手册:如何声明、填充链路如何工作、文案如何修改生效、常见坑有哪些。
|
||||
- [5.12 系统配置管理](http://docs.goframe.elevue.easygoadmin.vip/zh/core/config.html): 系统配置采用两级结构:config(配置分组)+ config_item(配置项)。
|
||||
- [5.13 系统参数管理](http://docs.goframe.elevue.easygoadmin.vip/zh/core/param.html): 参数模块(goframe_param)管理系统级键值参数:code 唯一标识 + name + value。
|
||||
- [5.14 操作日志](http://docs.goframe.elevue.easygoadmin.vip/zh/core/operation-log.html): 操作日志由中间件异步采集:gmeta log/logType 标签声明记录内容,OperationLog 中间件组装(含脱敏),有界通道 + 单 worker 批量落库,绝不阻塞业务。
|
||||
- [5.15 登录日志](http://docs.goframe.elevue.easygoadmin.vip/zh/core/login-log.html): 登录日志由业务写入(logic/auth.go writeLoginLog):登录成功、失败、退出全记录,含 IP 归属地(ip2region)、操作系统与浏览器解析、耗时统计。
|
||||
- [5.16 异常与响应处理](http://docs.goframe.elevue.easygoadmin.vip/zh/core/exception.html): 全部响应经 utility/response 统一信封写出;panic 由 Response 中间件 recover 兜底;404/500 状态页输出 JSON 而非 HTML。
|
||||
- [5.17 接口限流](http://docs.goframe.elevue.easygoadmin.vip/zh/core/idempotent.html): 接口防护采用固定窗口限流(middleware/ratelimit.go):按 IP + 路径计数,普通接口与认证入口双阈值。
|
||||
- [5.18 gmeta 标签系统总览](http://docs.goframe.elevue.easygoadmin.vip/zh/core/gmeta.html): gmeta 标签是本项目的"声明即事实"机制:请求结构体上的一个 gmeta.Meta 标签同时驱动路由注册、权限校验、操作日志、OpenAPI 文档四件事。
|
||||
|
||||
## 6. 业务模块
|
||||
|
||||
- [6.1 用户管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/user.html): 用户模块(goframe_user,租户级表)是机制最全的模块:唯一校验(按行现租户)、租户用户上限、角色全量重写、城市编解码、Excel 导入导出、数据权限接线、批量名称回填。
|
||||
- [6.2 角色管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/role.html): 角色模块(goframe_role,租户级表)承载 RBAC 分配与数据权限四档:MenuList 返回带勾选状态的全量菜单树,SavePermission 全量重写角色菜单并清理身份缓存,
|
||||
- [6.3 菜单管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/menu.html): 菜单模块(goframe_menu,平台级表)统一承载两类节点:type=0 目录/菜单(进前端菜单树)与 type=1 权限节点(进后端 Perms 校验)。
|
||||
- [6.4 部门管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/dept.html): 部门模块(goframe_dept,租户级表)管理组织架构:树形结构、删除有子级/用户守卫、租户内名称唯一。
|
||||
- [6.5 职级管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/level.html): 职级模块(goframe_level,租户级表)管理用户职级属性:标准 CRUD + 状态切换 + Excel 导入导出(与 user/example 并列的三个导入导出示范模块之一),列表带
|
||||
- [6.6 岗位管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/position.html): 岗位模块(goframe_position,租户级表)管理用户岗位属性:标准 CRUD + 状态切换 + 引用统计。
|
||||
- [6.7 文章管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/article.html): 文章模块(goframe_article,租户级表)是文件/富文本字段的代表模块:cover 单图、images 多图、content 富文本([IMG_URL] 持久化契约),
|
||||
- [6.8 公告与链接管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/content.html): 内容域还有两个租户级模块:通知公告(goframe_notice)与友情链接(goframe_link)。
|
||||
- [6.9 行政区划管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/city.html): 行政区划模块(goframe_city,平台级大表)管理全国省/市/区/街道/社区数据:树形双键(pid + parent_code)、级联懒加载查询、双向编解码包级函数(user/index
|
||||
- [6.10 分类管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/category.html): 分类模块(goframe_category,租户级表)管理文章/商品等树形分类:ModuleSpec 树形声明(IsTree + ParentOf)、租户内名称唯一、删除守卫。
|
||||
- [6.11 定时任务](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/job.html): 定时任务是数据驱动的常驻调度器:任务定义在 goframe_job 表,启动时加载 status=1 任务挂载 gcron,执行目标分双形态(HTTP 调用 / 本地处理器),
|
||||
- [6.12 参数管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/param.html): 参数模块(goframe_param,平台级表)管理系统级扁平键值参数:code 全局唯一(uk_code),标准七件套 CRUD。
|
||||
- [6.13 租户管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/tenant.html): 租户模块(goframe_tenant,平台级表)管理多租户生命周期:状态/过期、用户上限、事务化开户(Account,code 按 T+ID 规则回填)。
|
||||
- [6.14 文件模板管理](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/filetemplate.html): 文件模板模块(goframe_file_template,平台级表)在线管理文件/代码片段模板:code 全局唯一、按编码查询(getTemplateByCode)。
|
||||
- [6.15 首页与个人中心](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/index.html): index 模块(无表,聚合 user/menu)提供个人中心五接口:当前用户信息(超管返回通配权限)、菜单树、修改密码、更新个人信息。
|
||||
- [6.16 在线用户监控](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/online-user.html): 在线用户是无表模块(数据源 Redis):登录/刷新登记会话,分页查看在线列表,强退踢出(access+refresh 双令牌拉黑,防被踢会话经刷新复活)。
|
||||
- [6.17 服务器监控](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/server-monitor.html): 服务器监控是无表模块:单接口聚合返回运行时、内存、磁盘、数据库连通、缓存模式与调度器健康。
|
||||
- [6.18 缓存监控](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/cache-monitor.html): 缓存监控是无表模块:解析 Redis INFO 返回内存、客户端、命中率、键空间等指标;内存降级时返回 mode=memory 标识。
|
||||
- [6.19 案例演示模块](http://docs.goframe.elevue.easygoadmin.vip/zh/modules/example.html): 案例演示模块(goframe_example,tool 域)是官方完整样板:七件套 + 状态切换 + Excel 导入导出 + 文件字段 + 字典填充,前端五件套齐备。
|
||||
|
||||
## 7. 文件处理
|
||||
|
||||
- [7.1 文件上传全流程](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/upload.html): 上传采用两段式:SaveTemp 先入临时目录(白名单+大小+图片嗅探校验),表单保存时 SaveFromTemp 移动到正式子目录。
|
||||
- [7.2 上传配置详解](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/upload-config.html): 上传行为全部由 config.yaml 的 file.* 配置块控制:物理目录、访问域名、扩展名白名单、大小上限、临时保留天数。
|
||||
- [7.3 富文本处理](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/rich-text.html): 富文本的核心是 [IMG_URL] 持久化契约:存库时本站图片引用转为占位符(LocalizeContentFields),读取时还原为访问基址(ExpandContentFields,唯一还原出口)。
|
||||
- [7.4 数据导入导出](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/excel.html): Excel 导入导出基于 xuri/excelize/v2(utility/excel 封装):导入解析逐行校验写入并返回统计,导出走 ChunkQuery 分批查询防 OOM。
|
||||
- [7.5 前端文件组件](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/file-components.html): 前端文件能力集中在 components/Upload(上传组件族)与 utils/downloadFile(下载工具),配合两段式上传协议:选择文件即调
|
||||
- [7.6 数据库迁移工具](http://docs.goframe.elevue.easygoadmin.vip/zh/tools/db-migrate.html): 整库迁移器(internal/migrate + cmd/migrator)实现五方言互迁:源库内省 → 中间表示 → 目标方言 DDL → 分批搬运 → 序列修复 → 行数校验。
|
||||
|
||||
## 8. 接口规范与对接
|
||||
|
||||
- [8.1 统一响应格式](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/response.html): 全部接口返回统一 JSON 信封:code/ok/msg/data 四字段。
|
||||
- [8.2 错误码对照表](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/error-code.html): 业务错误码定义在 internal/consts/biz_err.go(gcode.Register 语义值)。
|
||||
- [8.3 分页查询规范](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/pagination.html): 分页契约三件套:PageReq 入参(pageNo/pageSize)+ PageData 出参(records/total/size/current/pages)+
|
||||
- [8.4 文件上传接口](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/upload.html): 上传接口统一 multipart:POST /api/upload/uploadFile(单文件)与 uploadFiles(多文件),字段名 file。
|
||||
- [8.5 字典数据接口](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/dict-api.html): 字典接口分三层:管理接口(dict/dict_item 七件套,带权限)、前端消费接口(dictionary 别名 + getDictItemList,登录即可)、缓存刷新接口。
|
||||
- [8.6 Token 使用说明](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/token.html): 本文档面向 API 对接方:如何获取令牌、如何携带、如何刷新、如何撤销。
|
||||
- [8.7 API 接口总览](http://docs.goframe.elevue.easygoadmin.vip/zh/api-spec/overview.html): 全部接口经 gmeta 标签自动生成 OpenAPI:GET /api.json(原生 JSON)+ GET /swagger(本地 Redoc UI)。
|
||||
|
||||
## 9. 前端开发
|
||||
|
||||
- [9.1 前端工程概述](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/overview.html): 前端为 Vue3 + TypeScript + Vite + ElementPlus + Pinia 的标准工程化项目(ui/ 目录),采用 Composition API,核心机制为:动态菜单路由、
|
||||
- [9.2 目录结构详解](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/directory.html): 前端目录按"共享层平铺、页面层按域分目录"组织:api/views 按域(system/data/content/monitor/tool)对应后端模块域;
|
||||
- [9.3 环境与构建配置](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/env-config.html): 前端构建基于 Vite 多环境模式:dev/test/uat/prod 四套构建命令 + 环境变量文件。
|
||||
- [9.4 HTTP 请求封装](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/http.html): HTTP 封装在 utils/http/axios:VAxios 类 + transform 链式处理。
|
||||
- [9.5 路由与动态菜单](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/router.html): 路由分两层:constant.ts 常量路由(login/redirect/403/404,登录前可访问)与动态菜单路由(登录后由 /api/index/getMenus 返回的菜单树经
|
||||
- [9.6 状态管理(Pinia)](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/store.html): 状态管理用 Pinia,modules 七个状态域:user(登录身份)、asyncRoute(动态路由)、tabsView(标签页)、
|
||||
- [9.7 权限控制](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/permission.html): 前端权限是按钮级 UX 控制:directives/permission.ts 按 getUser 返回的 permissions 数组控制元素显隐;超管通配权限 *:*:* 直接放行。
|
||||
- [9.8 登录流程](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/login.html): 登录页支持多表单形态(账号/手机/Qrcode),核心链路为:验证码获取 → 登录请求 → access_token 存储 → 跳转首页。
|
||||
- [9.9 数据展示组件](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/display-components.html): components/ 提供 25 类公共组件,覆盖数据展示(Table/Page/CountTo/Qrcode/Render)、容器(Modal)、
|
||||
- [9.10 数据录入组件](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/form-components.html): 数据录入组件覆盖表单场景:Form(querySchemas 驱动)、Select(下拉)、ChinaArea/Region(级联区划)、Cropper(裁剪)、Password(密码强度)、
|
||||
- [9.11 Excel 导入导出组件](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/excel-components.html): 前端 Excel 能力由 components/Excel 与 importFile 组件 + xlsx 库提供:导入走文件上传接口拿统计结果,导出走导出接口拿文件 URL 再下载。
|
||||
- [9.12 新增页面开发步骤](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/new-page.html): 新增前端页面的标准路径:api 模块 → columns.ts → querySchemas.ts → index.vue → edit.vue/detail.vue → 菜单权限。
|
||||
- [9.13 API 模块编写规范](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/api-module.html): api 模块按域组织(src/api/{域}/{模块}.ts),每接口一个导出函数,内部 http.request 调用。
|
||||
- [9.14 样式与主题定制](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/style.html): 样式体系基于 ElementPlus CSS 变量 + styles/ 全局覆盖:主题色、暗黑模式、水印、动画等经 designSetting/projectSetting 在线配置。
|
||||
- [9.15 布局系统](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/layout.html): 布局系统(src/layout/)提供管理后台标准骨架:侧栏菜单、顶栏(面包屑/用户区)、标签页(tabsView)、内容区(keep-alive 页面缓存)、锁屏等,全部受
|
||||
- [9.16 工具函数](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/utils.html): utils/ 提供通用工具:HTTP 封装(9.4 已述)、Storage 本地存储、auth 路径工具、downloadFile 下载、dateUtil/formatTime 时间、
|
||||
- [9.17 枚举与全局设置](http://docs.goframe.elevue.easygoadmin.vip/zh/frontend/i18n.html): 本项目前端不引入 i18n(当前仅简体中文)。
|
||||
|
||||
## 10. 代码生成器
|
||||
|
||||
- [10.1 概述与架构](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/overview.html): 代码生成器根据表结构一键产出前后端全套文件,并同步创建菜单、权限节点、字典数据、路由注册行(全部幂等)。
|
||||
- [10.2 CLI 命令行使用](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/cli.html): CLI 入口 cmd/generator:go run ./cmd/generator -tables "表名|注释"。
|
||||
- [10.3 Web 管理界面](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/web-ui.html): 管理界面位于「工具 → 代码生成」(ui/src/views/tool/generator/):数据表清单分页浏览、代码预览、一键生成、批量生成。
|
||||
- [10.4 表结构解析引擎](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/parser.html): 解析引擎负责把数据库表翻译为生成元数据:表注释(MySQL information_schema / 非 MySQL 降级)、字段类型映射、注释智能解析(枚举/标签/图片/富文本识别)、
|
||||
- [10.5 代码生成引擎](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/code-engine.html): 生成引擎按模板渲染全部产物:后端八件套(统一 gofmt)+ 前端五件/三件,然后经 writeFile 四态落盘决策,最后执行幂等副作用。
|
||||
- [10.6 模板开发](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/templates.html): 生成器模板在 templates/ 磁盘目录:后端模板用 Go text/template 默认 {{ }} 定界;前端模板因与 Vue 插值冲突改用 [[ ]] 定界。
|
||||
- [10.7 配置文件详解](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/config.html): 生成器配置在 config.yaml 的 generator 块:parentMenuId(菜单挂载父级)与 overwrite(覆盖开关,唯一入口)。
|
||||
- [10.8 实战案例](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/demo.html): 本节以数据库中真实存在的 goframe_example(案例演示表)为实操对象,演示生成器全流程:预览 → 生成(幂等)→ 副作用核对。
|
||||
- [10.9 常见问题](http://docs.goframe.elevue.easygoadmin.vip/zh/generator/faq.html): 生成器 FAQ 按"识别/产出/副作用/覆盖"分组。
|
||||
|
||||
## 11. 运维部署
|
||||
|
||||
- [11.1 部署 Checklist](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/checklist.html): 生产上线前逐项核对:安全基线(密钥/万能码/错误信息)、依赖服务(MySQL/Redis)、配置核对、静态资源、验证步骤。
|
||||
- [11.2 环境规划](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/env-plan.html): 推荐三套环境(开发/测试/生产)+ 环境差异经 GF_ 环境变量覆盖(不改配置文件)。
|
||||
- [11.3 数据库迁移](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/db-migrate.html): 部署场景的两类迁移:① 全新环境初始化(导入定稿脚本);② 存量环境跨方言迁移(整库迁移器)。
|
||||
- [11.4 后端部署](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/backend.html): 后端为单二进制部署:go build 产物 + manifest 配置 + resource 静态资源 + ip2region 数据文件。
|
||||
- [11.5 前端部署](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/frontend.html): 前端构建为静态产物(dist/),生产由 Nginx 托管:静态文件 + SPA 路由回退 + /api 与 /upload 反代后端。
|
||||
- [11.6 Docker 生产部署](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/docker.html): 项目已内置 Docker 化文件:docker/Dockerfile(多阶段静态编译)、docker/docker-compose.yml(后端 + MySQL + Redis 编排)、
|
||||
- [11.7 性能调优](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/performance.html): 性能调优按层次展开:数据库(连接池/索引/大表)、Redis(连接池/内存)、应用(缓存策略/日志异步)、前端(构建/缓存)。
|
||||
- [11.8 安全加固清单](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/security.html): 安全加固按层次组织:配置层(密钥/开关)、网络层(暴露面/代理)、数据层(账号/备份)、应用层(上传/权限)。
|
||||
- [11.9 备份与恢复](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/backup.html): 备份对象:数据库(核心)、上传文件、配置与密钥。
|
||||
- [11.10 故障排查手册](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/troubleshooting.html): 按故障类别速查:启动失败 / 认证授权 / 数据异常 / 性能 / 缓存 / 定时任务 / 文件上传。
|
||||
- [11.11 CI/CD 流水线](http://docs.goframe.elevue.easygoadmin.vip/zh/deploy/ci-cd.html): CI 门禁:后端 go vet + gofmt + build + test;前端 vue-tsc + eslint + 构建。
|
||||
|
||||
## 12. 规范标准
|
||||
|
||||
- [12.1 API 响应规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/api-response.html): 必须遵守的响应契约:统一信封四字段、code 语义、data 形态、命名驼峰(含下划线例外)。
|
||||
- [12.2 分页查询规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/pagination.html): 必须遵守的查询契约:筛选对齐三件套、分页默认值与上限、导出=所见、排序白名单。
|
||||
- [12.3 Git 提交规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/git.html): 提交遵循 Conventional Commits(前端工程内置 commitlint + husky 校验)。
|
||||
- [12.4 数据删除规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/deletion.html): 删除一律软删(del_flag=1,由全局钩子强制改写);物理删除只在定时清理任务中出现。
|
||||
- [12.5 代码审查清单](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/code-review.html): Review 按"架构红线 → 安全 → 正确性 → 规范"四层组织。
|
||||
- [12.6 后端编码规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/backend-code.html): 后端规范汇总:分层职责、命名、错误处理、事务纪律、注释风格。
|
||||
- [12.7 前端编码规范](http://docs.goframe.elevue.easygoadmin.vip/zh/standards/frontend-code.html): 前端规范汇总:三件套对齐、组件使用、权限、状态管理、类型与样式。
|
||||
|
||||
## 附录
|
||||
|
||||
- [A. 常见问题汇总](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/faq.html): 全书 FAQ 汇总(按主题分组),结论均可回溯到代码位置。
|
||||
- [B. 数据库表结构速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/database-tables.html): 25 张业务表速查:表名/中文/域/租户级/关键列。
|
||||
- [C. 配置项速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/config-reference.html): manifest/config/config.yaml 全键速查。
|
||||
- [D. 公共函数速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/functions.html): 后端共享能力速查:logic/base.go 15 个导出函数 + module_spec/data_scope 包级函数 + utility 九包。
|
||||
- [E. API 接口速查表](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/api-cheatsheet.html): 全部接口速查(按模块)。
|
||||
- [F. 中间件执行顺序](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/middleware.html): 七层中间件 + Bind 包装层的完整执行顺序与短路行为速查。
|
||||
- [G. 前端组件速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/components.html): ui/src/components/ 全部公共组件速查(25 类),按展示/录入/布局/能力分组。
|
||||
- [H. 前端 Store 速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/stores.html): Pinia store 模块速查(store/modules/ 七个):
|
||||
- [I. 前端 Enums 速查](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/enums.html): src/enums/ 枚举常量速查。
|
||||
- [J. 术语表](http://docs.goframe.elevue.easygoadmin.vip/zh/appendix/glossary.html): 项目核心术语速查(按字母/主题排序)。
|
||||
- [K. 贡献指南](http://docs.goframe.elevue.easygoadmin.vip/zh/other/contributing.html): 感谢关注 EasyGoAdmin!
|
||||
- [L. 免责声明](http://docs.goframe.elevue.easygoadmin.vip/zh/other/declare.html): 使用本项目前请阅读以下免责声明。
|
||||
- [M. 广告赞助](http://docs.goframe.elevue.easygoadmin.vip/zh/other/sponsor.html): 如果本项目对你的工作有帮助,欢迎通过赞助支持它的持续演进。
|
||||
@@ -0,0 +1,33 @@
|
||||
# EasyGoAdmin GoFrame+ElementPlus 开发文档
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
# 显式放行生成式引擎 / AI 爬虫(GEO)
|
||||
User-agent: GPTBot
|
||||
Allow: /
|
||||
|
||||
User-agent: ChatGPT-User
|
||||
Allow: /
|
||||
|
||||
User-agent: ClaudeBot
|
||||
Allow: /
|
||||
|
||||
User-agent: Claude-Web
|
||||
Allow: /
|
||||
|
||||
User-agent: anthropic-ai
|
||||
Allow: /
|
||||
|
||||
User-agent: PerplexityBot
|
||||
Allow: /
|
||||
|
||||
User-agent: Google-Extended
|
||||
Allow: /
|
||||
|
||||
User-agent: Bytespider
|
||||
Allow: /
|
||||
|
||||
User-agent: bingbot
|
||||
Allow: /
|
||||
|
||||
Sitemap: http://docs.goframe.elevue.easygoadmin.vip/sitemap.xml
|
||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 367 KiB |
|
Before Width: | Height: | Size: 947 KiB |
|
Before Width: | Height: | Size: 692 KiB |
|
Before Width: | Height: | Size: 610 KiB |
|
Before Width: | Height: | Size: 920 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 606 KiB |
|
Before Width: | Height: | Size: 644 KiB |
|
Before Width: | Height: | Size: 640 KiB |
|
Before Width: | Height: | Size: 780 KiB |
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 生成 public/llms.txt(llmstxt.org 标准)——AI 爬虫的站点摘要索引。
|
||||
*
|
||||
* 数据源:zh 目录下全部 Markdown 的 H1 + :::tip 概述首句(与 meta
|
||||
* description 同源,复用 .vitepress/config/extract.mjs)。按侧边栏章节分组。
|
||||
*
|
||||
* 用法:node scripts/generate-llms-txt.mjs
|
||||
* 已挂入 package.json 的 docs:build 前置步骤。
|
||||
*/
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import {
|
||||
SITE_URL,
|
||||
SITE_DESCRIPTION,
|
||||
extractDescription,
|
||||
} from "../.vitepress/config/extract.mjs";
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const ZH = path.join(ROOT, "zh");
|
||||
|
||||
/** 顶层目录 → 侧边栏章节名(与 .vitepress/config/zh.ts 保持一致) */
|
||||
const SECTIONS = [
|
||||
["", "1. 了解项目"],
|
||||
["quickstart", "2. 快速入门"],
|
||||
["guide", "3. 模块开发实战"],
|
||||
["architecture", "4. 架构设计"],
|
||||
["core", "5. 核心功能"],
|
||||
["modules", "6. 业务模块"],
|
||||
["tools", "7. 文件处理"],
|
||||
["api-spec", "8. 接口规范与对接"],
|
||||
["frontend", "9. 前端开发"],
|
||||
["generator", "10. 代码生成器"],
|
||||
["deploy", "11. 运维部署"],
|
||||
["standards", "12. 规范标准"],
|
||||
["appendix", "附录"],
|
||||
["other", "附录"],
|
||||
];
|
||||
|
||||
function walk(dir, out = []) {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const p = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(p, out);
|
||||
else if (entry.name.endsWith(".md")) out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 提取首个 H1 文本 */
|
||||
function h1Of(md) {
|
||||
const m = md.match(/^# (?!#)(.+)$/m);
|
||||
return m ? m[1].trim() : "";
|
||||
}
|
||||
|
||||
/** H1 编号排序键:"5.10 x" → [5,10];无编号排最后 */
|
||||
function sortKey(h1) {
|
||||
const m = h1.match(/^(\d+(?:\.\d+)*)/);
|
||||
if (m) return m[1].split(".").map(Number);
|
||||
const letter = h1.match(/^([A-Z])\./);
|
||||
if (letter) return [1000 + letter[1].charCodeAt(0)];
|
||||
return [9999];
|
||||
}
|
||||
|
||||
function cmpKey(a, b) {
|
||||
const len = Math.max(a.length, b.length);
|
||||
for (let i = 0; i < len; i++) {
|
||||
const x = a[i] ?? 0;
|
||||
const y = b[i] ?? 0;
|
||||
if (x !== y) return x - y;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const files = walk(ZH);
|
||||
const groups = new Map(SECTIONS.map(([dir, label]) => [label, []]));
|
||||
|
||||
for (const file of files) {
|
||||
const rel = path.relative(ZH, file).replace(/\\/g, "/");
|
||||
const topDir = rel.includes("/") ? rel.split("/")[0] : "";
|
||||
const label =
|
||||
SECTIONS.find(([dir]) => dir === topDir)?.[1] ?? "附录";
|
||||
|
||||
const md = fs.readFileSync(file, "utf8");
|
||||
const h1 = h1Of(md);
|
||||
if (!h1) continue;
|
||||
const desc = extractDescription(md);
|
||||
const url = `${SITE_URL}/zh/${rel.replace(/\.md$/, ".html")}`;
|
||||
groups.get(label).push({ h1, desc, url, key: sortKey(h1) });
|
||||
}
|
||||
|
||||
const lines = [
|
||||
"# EasyGoAdmin GoFrame+ElementPlus 开发文档",
|
||||
"",
|
||||
`> ${SITE_DESCRIPTION}。支持五种数据库一键切换、RBAC 按钮级权限、多租户数据隔离、声明式 CRUD 基座与代码生成器。本文档共 ${files.length} 篇,按章节组织。`,
|
||||
"",
|
||||
];
|
||||
|
||||
// 按章节顺序输出,合并重复 label(appendix/other 同为「附录」,只输出一次)
|
||||
const printed = new Set();
|
||||
for (const [, label] of SECTIONS) {
|
||||
if (printed.has(label)) continue;
|
||||
const items = groups.get(label);
|
||||
if (!items?.length) continue;
|
||||
printed.add(label);
|
||||
|
||||
lines.push(`## ${label}`, "");
|
||||
items.sort((a, b) => cmpKey(a.key, b.key));
|
||||
for (const { h1, desc, url } of items) {
|
||||
lines.push(desc ? `- [${h1}](${url}): ${desc}` : `- [${h1}](${url})`);
|
||||
}
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
const out = path.join(ROOT, "public", "llms.txt");
|
||||
fs.writeFileSync(out, lines.join("\n"), "utf8");
|
||||
console.log(
|
||||
`llms.txt: ${files.length} 页 → ${path.relative(ROOT, out)} (${printed.size} 个章节)`,
|
||||
);
|
||||
@@ -1,7 +1,7 @@
|
||||
# 8.7 API 接口总览
|
||||
|
||||
:::tip 概述
|
||||
全部接口经 gmeta 注解自动生成 OpenAPI:GET /api.json(原生 JSON)+ GET /swagger(本地 Redoc UI)。本节给出接口域总览与权限码总规律,完整清单以 /api.json 为准。
|
||||
全部接口经 gmeta 标签自动生成 OpenAPI:GET /api.json(原生 JSON)+ GET /swagger(本地 Redoc UI)。本节给出接口域总览与权限码总规律,完整清单以 /api.json 为准。
|
||||
:::
|
||||
|
||||
## 在线文档
|
||||
|
||||
@@ -27,7 +27,7 @@ model/entity · model/hooks · gdb
|
||||
### api/v1(契约层)
|
||||
|
||||
+ 全部 Req/Res 结构体,**单包 v1**,每模块一文件(snake_case)
|
||||
+ gmeta 注解声明 method/path/summary/permission/log/logType/public
|
||||
+ gmeta 标签声明 method/path/summary/permission/log/logType/public
|
||||
+ gvalid 标签声明校验规则;`dc` 标签供 OpenAPI 文档
|
||||
+ **禁止**:业务逻辑、数据库引用
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ goframe_user / role / dept / level / position / article / category / notice / li
|
||||
日志采集(不短路) OpenAPI 元数据
|
||||
```
|
||||
|
||||
权限校验不设独立中间件——因为它需要每路由不同的权限码,放在读路由元数据的包装层最自然(与日志注解同源,"注解即事实")。
|
||||
权限校验不设独立中间件——因为它需要每路由不同的权限码,放在读路由元数据的包装层最自然(与日志标签同源,"标签即事实")。
|
||||
|
||||
## 日志横切(OperationLog)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 4.4 前端分层架构
|
||||
|
||||
:::tip 概述
|
||||
前端采用 Vue3 Composition API + TypeScript + Pinia + Element Plus,分层为:views(页面)→ components(公共组件)→ api(接口)→ utils/http(请求封装)→ store(状态)→ router(动态菜单)。本节给出分层视图与协作关系。
|
||||
前端采用 Vue3 Composition API + TypeScript + Pinia + ElementPlus,分层为:views(页面)→ components(公共组件)→ api(接口)→ utils/http(请求封装)→ store(状态)→ router(动态菜单)。本节给出分层视图与协作关系。
|
||||
:::
|
||||
|
||||
## 前端分层视图
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# 4.1 整体架构概览
|
||||
|
||||
:::tip 概述
|
||||
系统采用分层架构 + 声明式基座 + 全局钩子横切 + gmeta 反射注解的组合。本节给出总架构图、模块依赖方向(允许/禁止)与启动编排,是理解全部机制的地图。
|
||||
系统采用分层架构 + 声明式基座 + 全局钩子横切 + gmeta 反射标签的组合。本节给出总架构图、模块依赖方向(允许/禁止)与启动编排,是理解全部机制的地图。
|
||||
:::
|
||||
|
||||
## 系统总架构图
|
||||
|
||||
```text
|
||||
┌───────────────────────────── 客户端 ─────────────────────────────┐
|
||||
│ ui/(Vue3 + Element Plus,baseURL=/api) 其他 API 消费方 │
|
||||
│ ui/(Vue3 + ElementPlus,baseURL=/api) 其他 API 消费方 │
|
||||
└──────────────────────────────────┬─────────────────────────────────┘
|
||||
│ HTTP(Bearer JWT)
|
||||
╔══════════════════════════════════▼═════════════════════════════════╗
|
||||
@@ -19,7 +19,7 @@
|
||||
║ └──────────────────────────┬──────────────────────────────┘ ║
|
||||
║ ┌──────────────────────────▼──────────────────────────────┐ ║
|
||||
║ │ Bind 反射包装层(gmeta):权限校验 → 参数解析 → 分发 │ ║
|
||||
║ │ 路由元数据表 meta(权限/日志 注解即事实,补注册 goai) │ ║
|
||||
║ │ 路由元数据表 meta(权限/日志 标签即事实,补注册 goai) │ ║
|
||||
║ └──────────────────────────┬──────────────────────────────┘ ║
|
||||
║ controller(薄)→ service 接口(手维护)→ logic(ModuleSpec 基座) ║
|
||||
║ │ 侧路:utility/{jwt,captcha,cache,upload,excel,ip2region…} ║
|
||||
@@ -94,7 +94,7 @@ Bind 包装(gmeta 权限/日志元数据)
|
||||
|
||||
| 层 | 位置 | 职责 | 禁止 |
|
||||
|----|------|------|------|
|
||||
| api/v1 | api/v1/{模块}.go | 请求响应结构体 + gmeta 注解 | 业务逻辑 |
|
||||
| api/v1 | api/v1/{模块}.go | 请求响应结构体 + gmeta 标签 | 业务逻辑 |
|
||||
| controller | internal/controller/{模块}.go | 薄层透传 | 业务/dao/手写响应 |
|
||||
| service | internal/service/{模块}.go | 接口契约(手维护) | 实现 |
|
||||
| logic | internal/logic/{模块}.go | 业务实现(基座+钩子+手写) | 反向依赖 task |
|
||||
|
||||
@@ -1,52 +1,349 @@
|
||||
# 1.6 更新日志
|
||||
|
||||
:::tip 概述
|
||||
本项目遵循语义化版本演进,重大架构决策与约定变更记录于此。详细提交历史见 [Gitee 仓库](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue)。
|
||||
:::tip 说明
|
||||
更新日志是项目演进的完整记录,帮助开发者和企业了解每个版本的能力变化与技术演进方向。对于开发者,可快速掌握新功能与 API 变更,降低升级成本;对于企业,可评估版本稳定性与功能成熟度,为技术选型和升级决策提供依据。建议在升级前阅读目标版本的变更内容,确保业务代码平滑适配。
|
||||
:::
|
||||
|
||||
## v4.0.0(2026-10 · 当前版本)
|
||||
## 版本总览
|
||||
|
||||
GoFrame+ElementPlus 版本首个正式封板版本,25 张业务表 → 27 个模块完整落地。
|
||||
| 版本 | 日期 | 主要内容 |
|
||||
|:-----|:-----|:---------|
|
||||
| **4.0.0** | **2026-10-20** | **核心架构定稿:标签体系与泛型基座** |
|
||||
| 3.9.0 | 2026-09-07 | OAuth2 令牌治理 |
|
||||
| 3.8.0 | 2026-07-26 | 安全加固与防护增强 |
|
||||
| 3.7.0 | 2026-06-13 | 五方言驱动与整库迁移 |
|
||||
| 3.6.0 | 2026-05-01 | 代码生成器 |
|
||||
| 3.5.0 | 2026-03-21 | 运行监控体系 |
|
||||
| 3.4.0 | 2026-02-05 | 内置任务与在线用户 |
|
||||
| 3.3.0 | 2025-12-24 | 定时任务调度 |
|
||||
| 3.2.0 | 2025-11-11 | 数据权限四档 |
|
||||
| 3.1.0 | 2025-09-29 | 租户治理与状态校验 |
|
||||
| 3.0.0 | 2025-08-18 | 多租户架构与数据隔离 |
|
||||
| 2.9.0 | 2025-07-06 | 共享能力层沉淀 |
|
||||
| 2.8.0 | 2025-05-24 | 工具模块与案例示范 |
|
||||
| 2.7.0 | 2025-04-12 | 数据导入导出 |
|
||||
| 2.6.0 | 2025-03-01 | 文件上传与富文本契约 |
|
||||
| 2.5.0 | 2025-01-17 | 内容管理与行政区划 |
|
||||
| 2.4.0 | 2024-12-05 | 字典、配置与参数 |
|
||||
| 2.3.0 | 2024-10-23 | 操作审计与日志查询 |
|
||||
| 2.2.0 | 2024-09-10 | 组织架构与个人中心 |
|
||||
| 2.1.0 | 2024-07-29 | 用户管理与 RBAC 权限 |
|
||||
| 2.0.0 | 2024-06-16 | 工程奠基与认证闭环 |
|
||||
|
||||
### 架构定稿
|
||||
|
||||
+ **主键统一 int 数据库自增**(2026-10-13 定稿):禁用雪花算法(`utility/id` 已删除);新增后用 `result.LastInsertId()` 回读;hooks 不填 id
|
||||
+ **目录平铺结构**:api/v1、controller、logic、service 均为单包,每模块一个 snake_case 文件,同包 init 自动注册
|
||||
+ **中间件链定稿**:CORS → Response → RateLimit → Demo → JWT → Tenant → OperationLog,权限校验在 Bind 包装层完成
|
||||
+ **筛选对齐三件套**(2026-10-14 定稿):前端 querySchemas.ts ↔ XxxPageReq 同名驼峰字段 ↔ spec 声明(LikeFields/EqFields),导出与列表同套筛选
|
||||
+ **URL 约定**:全部路由统一 `/api` 前缀,无 `/v1` 版本段;公开白名单三处一致(public.go / gmeta public 标签 / router.go 手工注册)
|
||||
## [4.0.0] - 2026-10-20
|
||||
|
||||
### 功能清单
|
||||
**核心架构定稿:gmeta 标签体系与 ModuleSpec 泛型基座全面落地,路由、权限、日志、文档一体驱动,全域能力就位,生产部署就绪。**
|
||||
|
||||
+ 认证与安全:JWT 双令牌(access 2h + refresh 7d 轮换)、jti 黑名单、图形验证码(TTF 渲染 + SVG 降级)、bcrypt 双重加盐、固定窗口限流(认证入口独立阈值)、演示模式、受信代理 IP
|
||||
+ 权限体系:RBAC(user→role→menu 权限节点)、gmeta permission 标签、前端权限指令、超管通配权限 `*:*:*`
|
||||
+ 多租户:9 张租户级表自动隔离(hooks.tenantTables)、租户状态/过期中间件校验(60s 缓存)、事务化开户、用户上限
|
||||
+ 数据权限:role.data_scope 四档(全部/本部门及以下/本部门/仅本人),`ApplyDataScope("dept_id")` 一行声明接线
|
||||
+ CRUD 基座:ModuleSpec 泛型(筛选/排序/树形/字典/文件/富文本/唯一校验/钩子/数据权限)
|
||||
+ 监控体系:在线用户(双令牌拉黑强退)、服务器监控、缓存监控(Redis INFO)、操作日志(异步批量落库 + 脱敏)、登录日志(ip2region 归属地)
|
||||
+ 定时任务:数据驱动调度器、HTTP/本地处理器双形态、三种执行策略、多实例执行锁(job:lock:{id})、内置 LogClean/CleanTemp
|
||||
+ 代码生成器:HTTP + CLI 双入口、后端八件套 + 前端五件产出、菜单/权限/字典/路由幂等副作用、覆盖策略保护
|
||||
+ 整库迁移器:五方言互迁(内省 → IR → 方言 DDL → 分批搬运 → 序列修复 → 行数校验)
|
||||
+ 文件体系:两段式上传(temp → 正式目录)、富文本 [IMG_URL] 持久化契约、临时目录每日 03:30 自动清理
|
||||
### 新增
|
||||
|
||||
### 工程保障
|
||||
- **gmeta 标签体系定稿**:请求结构体上的一个标签同时驱动路由注册、权限校验、操作日志、OpenAPI 文档四件事,"标签即事实",杜绝多处不一致
|
||||
- **ModuleSpec 泛型基座**:筛选、排序、树形、字典文本、文件字段、富文本、唯一校验、数据权限全部声明化,生命周期钩子承接差异,手写方法为合法逃生舱,基座永不出现按模块分支的代码
|
||||
- **OpenAPI 输出**:gmeta 补注册进 goai,/api.json 原生 JSON + /swagger 本地 Redoc 页面
|
||||
- **生成器与基座对齐**:生成的 logic 直接产出基座声明式实现,go build 后即可运行
|
||||
- **模块版图收口**:监控域(操作日志/登录日志/定时任务/任务日志)与工具域(案例/文件模板/生成器/上传)能力全量就位
|
||||
|
||||
+ 静态门禁:`go vet` + `gofmt` 检查;前端 ESLint + Prettier + Stylelint + commitlint
|
||||
+ 测试:sqlite 集成测试 + hooks MySQL 集成测试
|
||||
+ 回归:hack/golden 黄金样本接口响应比对(录制参数带 pageSize=3 等)
|
||||
+ OpenAPI:gmeta 补注册进 gf goai,`/api.json` 原生输出 + `/swagger` 本地 Redoc 页面
|
||||
### 优化
|
||||
|
||||
## 历史版本
|
||||
- **主键策略定稿**(2026-10-13):统一 int 数据库自增,插入后经 LastInsertId() 回读,全局钩子不填主键
|
||||
- **中间件链定稿**:CORS → Response → RateLimit → Demo → JWT → Tenant → OperationLog,权限校验收敛到 Bind 包装层每请求判定
|
||||
- **筛选对齐三件套定稿**(2026-10-14):前端 querySchemas.ts、请求结构体同名驼峰字段、基座声明(LikeFields/EqFields)三处对齐,导出与列表同套筛选
|
||||
- **目录平铺定稿**:api/controller/logic/service 单包 snake_case 文件,同包 init 自动注册
|
||||
- **URL 约定收口**:统一 /api 前缀、无 /v1 版本段;公开白名单三处一致
|
||||
- **配置环境变量覆盖**:GF_ 前缀 env-first 适配器(键名=配置路径大写下划线),compose 友好名映射,12-Factor 部署就绪
|
||||
- **工程保障**:go vet / gofmt 门禁、sqlite 与 MySQL 集成测试、golden 黄金样本响应比对回归、CI workflow、docker compose 一键部署、145 页文档站
|
||||
|
||||
| 版本 | 说明 |
|
||||
|------|------|
|
||||
| v4.0.0-beta | 27 模块全量实现,架构决策落地(主键自增、中间件链、筛选三件套定稿) |
|
||||
| v4.0.0-alpha | 项目初始化:GoFrame 骨架 + 核心模块(auth/user/role/menu)+ 前端工程搭建 |
|
||||
### 修复
|
||||
|
||||
## 破坏性变更记录
|
||||
- 富文本还原散落的字符串替换统一收敛到 ExpandContentFields 唯一出口,[IMG_URL] 占位符不再被业务代码旁路解析
|
||||
|
||||
::: warning 变更须知
|
||||
+ 2026-10-13:主键策略由雪花算法改为数据库自增——历史数据的 id 语义不变,但新增代码禁止依赖 `utility/id`(包已删除)。
|
||||
+ URL 全部去版本段——`/api/v1/*` 形式的旧链接失效,前端 baseURL 为 `/api`。
|
||||
+ 前端登录响应字段为 `access_token/refresh_token/expires_in/token_type`(下划线),与全局驼峰约定不同,这是 OAuth2 惯例,禁止"修正"。
|
||||
:::
|
||||
|
||||
## [3.9.0] - 2026-09-07
|
||||
|
||||
**OAuth2 令牌治理收口。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **令牌刷新**:/oauth2/token 持 refresh_token 轮换新令牌,旧 jti 即时拉黑
|
||||
- **令牌检测**:/oauth2/check/token 校验有效性
|
||||
- **令牌吊销**:/oauth2/remove/:token 指定令牌即时失效
|
||||
|
||||
### 优化
|
||||
|
||||
- 前端令牌刷新链路统一对接 OAuth2 路由;登录响应保持 OAuth2 惯例字段(access_token / refresh_token / expires_in / token_type)
|
||||
|
||||
|
||||
## [3.8.0] - 2026-07-26
|
||||
|
||||
**安全加固与防护增强。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **接口限流**:固定窗口限流中间件,登录/验证码入口独立更严阈值(authLimit),计数经共享缓存多实例一致
|
||||
- **受信代理**:api.proxyIps(支持 CIDR)内的代理才信任 X-Forwarded-For 首段 / X-Real-IP
|
||||
- **演示模式白名单精细化**:公开路径与读操作精确放行,写操作统一拦截提示
|
||||
- **健康检查**:/api/health 公开探测接口
|
||||
|
||||
### 优化
|
||||
|
||||
- 限流仅作用于 /api/ 路径,静态资源与文档页不受影响
|
||||
|
||||
|
||||
## [3.7.0] - 2026-06-13
|
||||
|
||||
**五方言驱动与整库迁移能力建成。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **五方言驱动**:MySQL / PostgreSQL / SQL Server / Oracle / SQLite 运行时切换,改配置 type/link 即换库
|
||||
- **五份方言 DDL**:resource/sql 定稿,与 MySQL 基准逐表对齐
|
||||
- **整库迁移器**:源库内省 → 中间表示 → 方言 DDL 渲染 → 分批搬运 → pgsql 序列修复,行数校验闭环
|
||||
- **迁移 CLI**:源/目标连接参数、-drop-target-first 清空目标、-dry-run 预演
|
||||
|
||||
|
||||
## [3.6.0] - 2026-05-01
|
||||
|
||||
**代码生成器上线,模块产出工业化。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **双入口**:HTTP 页面与 CLI(-tables / -preview / -batch)
|
||||
- **产出**:后端八件套(api/controller/logic/service + dao/index、dao/internal、entity、do)与前端页面五件
|
||||
- **幂等副作用**:同步创建菜单、权限节点、字典数据与路由注册
|
||||
- **字典自动创建**:按列注释枚举解析(支持 `1-正常` 与 `1=正常` 两种写法)
|
||||
- **覆盖保护**:缺失补生成、存在跳过,generator.overwrite 开启才覆盖
|
||||
|
||||
### 优化
|
||||
|
||||
- 生成代码统一 gofmt;前端模板以 [[]] 定界,规避 Vue 插值冲突
|
||||
|
||||
|
||||
## [3.5.0] - 2026-03-21
|
||||
|
||||
**运行监控体系上线。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **服务器监控**:运行时、内存、磁盘分平台采集,MySQL / Redis 连通检测
|
||||
- **缓存监控**:Redis INFO 解析展示,内存降级模式标识(mode=memory)
|
||||
- **监控接口**:/server/info、/cache/info,配合在线用户列表运行状态一目了然
|
||||
|
||||
|
||||
## [3.4.0] - 2026-02-05
|
||||
|
||||
**内置任务与在线用户治理。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **LogClean 内置任务**:每日 02:30 分批物理清理三张日志表(保留天数默认 90,任务参数可覆盖)
|
||||
- **在线用户模块**:登录登记 / 登出注销,在线列表与强制踢出(jti 拉黑防刷新复活)
|
||||
|
||||
### 优化
|
||||
|
||||
- CleanTemp 临时目录清理纳入调度统一管理(每日 03:30 触发)
|
||||
- 调度消费约定完善:同步/异步标记与三种执行策略协同
|
||||
|
||||
|
||||
## [3.3.0] - 2025-12-24
|
||||
|
||||
**数据驱动的定时任务调度系统。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **常驻调度器**:启动加载启用任务,Cron 表达式触发
|
||||
- **双执行形态**:HTTP 接口任务与本地处理器任务
|
||||
- **三种执行策略**:并行 / 单例 / 放弃,单例与放弃叠加多实例执行锁(job:lock:{id},共享缓存 SET NX、300s 兜底)
|
||||
- **任务日志**:执行时间、状态、耗时、错误详情完整留档
|
||||
- **任务操作**:立即执行、暂停、恢复、状态设置、调度器状态查询
|
||||
|
||||
|
||||
## [3.2.0] - 2025-11-11
|
||||
|
||||
**角色数据权限四档上线。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **data_scope 四档**:全部 / 本部门及以下 / 本部门 / 仅本人
|
||||
- **一行接线**:ApplyDataScope("dept_id") 声明即生效,作用于分页/列表/导出
|
||||
- **身份缓存**:300s 缓存含数据范围与部门,多角色取最宽松档位,角色变更主动失效
|
||||
|
||||
### 修复
|
||||
|
||||
- 未分配部门用户在"本部门"档位越权可见——身份加载层降级为仅本人
|
||||
|
||||
|
||||
## [3.1.0] - 2025-09-29
|
||||
|
||||
**租户治理与状态校验完善。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **状态/过期校验**:中间件拦截(60s 缓存),禁用与过期租户拒绝访问
|
||||
- **租户用户查询**:按租户维度检索用户列表
|
||||
- **平台数据绕过**:超管与租户级表中的平台数据(tenant_id=0)自动放行
|
||||
- **租户内分组唯一**:手机号/用户名等唯一性走分组唯一索引
|
||||
|
||||
|
||||
## [3.0.0] - 2025-08-18
|
||||
|
||||
**多租户架构与数据隔离建成,SaaS 能力就绪。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **全局钩子横切**:审计字段盖章、软删改写、租户隔离统一在 gdb 模型钩子层完成,dao.Ctx 是唯一查询入口
|
||||
- **9 张租户级表自动隔离**:Insert 自动填充 tenant_id 与审计字段,Select 自动附加 del_flag 与租户条件
|
||||
- **租户管理模块**:租户 CRUD、用户数统计
|
||||
- **事务化开户**:租户与初始管理员同一事务创建(code = T + 4 位 ID)
|
||||
- **用户上限**:tenant.max_user_num 校验,超限拒绝开户
|
||||
|
||||
### 优化
|
||||
|
||||
- 业务代码零侵入:不手写一行 del_flag / tenant_id 条件,横切逻辑全部下沉钩子层
|
||||
|
||||
|
||||
## [2.9.0] - 2025-07-06
|
||||
|
||||
**共享能力层沉淀,横切逻辑收口。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **base.go 共享能力层**:文件字段、富文本、枚举文本、唯一校验、事务、分块查询、树、临时清理八类横切能力统一沉淀
|
||||
- **CheckUnique 唯一性预检**:UX 快速报错,并发真值由数据库 uk_* 唯一索引兜底
|
||||
- **WithTrans 事务包裹**:错误自动回滚,事务内禁 HTTP/文件 IO,bcrypt 预计算
|
||||
- **BuildTree 泛型树**:平铺数据转树形,叶子 Children 预置空数组
|
||||
|
||||
### 优化
|
||||
|
||||
- 共享层导出函数上限 15 个,超出按能力拆分子包,防止能力层膨胀
|
||||
|
||||
|
||||
## [2.8.0] - 2025-05-24
|
||||
|
||||
**工具模块与标准示范补齐。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **example 案例模块**:完整示范七件套 + 导入导出 + 字典文本 + 文件字段的标准写法
|
||||
- **文件模板管理模块**:模板上传维护,按编码取用(getTemplateByCode)
|
||||
- **upload 上传模块**:统一上传入口与返回 URL 约定
|
||||
|
||||
|
||||
## [2.7.0] - 2025-04-12
|
||||
|
||||
**数据导入导出能力建成。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **Excel 导入**:excelize 驱动,表头映射导入,空行自动过滤
|
||||
- **Excel 导出**:标准化导出与文件下载,user / level / example 模块启用
|
||||
- **大数据量分批导出**:ChunkQuery 分批查询(默认 500 条/页)防内存溢出
|
||||
- **前端 xlsx 组件**:导入向导与导出按钮统一封装
|
||||
|
||||
### 修复
|
||||
|
||||
- 富文本跨域名图片占位符替换不完整
|
||||
|
||||
|
||||
## [2.6.0] - 2025-03-01
|
||||
|
||||
**文件上传体系与富文本持久化契约。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **两段式上传**:先落 temp 临时目录(扩展名白名单、单文件大小上限、图片魔数嗅探),表单保存时转正到按日期分子目录的正式位置
|
||||
- **文件字段统一处理**:SaveFileField / SaveFileFields / SaveMultiFileField,批量转正与 URL 补全
|
||||
- **富文本占位符契约**:入库 [IMG_URL] 占位、出库统一还原(LocalizeContentFields / ExpandContentFields 唯一出口),外站 URL 不处理规避 SSRF
|
||||
- **SVG 安全加固**:.svg 响应强制 attachment + nosniff,防存储型 XSS
|
||||
- **临时目录自动清理**:每日 03:30 清理超期 temp 日期目录(file.tempExpireDays 控制保留天数)
|
||||
|
||||
### 优化
|
||||
|
||||
- /upload/** 静态访问由 SetServerRoot("resource") 统一提供,上传目录按日期分子目录
|
||||
|
||||
|
||||
## [2.5.0] - 2025-01-17
|
||||
|
||||
**内容管理与行政区划能力就绪。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **文章与分类**:文章 CRUD(封面、图集、状态、点击量),分类树形无限级嵌套
|
||||
- **通知公告**:类型、发布状态、富文本内容
|
||||
- **友情链接**:图标、描述、启用/禁用
|
||||
- **行政区划**:省市县三级数据与树形查询,ResolveCityNames / ResolveCityCodes 编解码(用户模块地址字段接入)
|
||||
|
||||
### 优化
|
||||
|
||||
- 富文本编辑器全站统一接入;列表状态筛选与模糊搜索标准化
|
||||
|
||||
|
||||
## [2.4.0] - 2024-12-05
|
||||
|
||||
**字典、配置与参数三件套,基础数据标准化。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **字典管理**:字典与字典项两级维护,枚举显示名经 {field}Text 字典驱动(唯一真相,进程内缓存 300s)
|
||||
- **字典前端消费**:登录即可的查询接口与字典组件,下拉/徽标数据源统一
|
||||
- **配置管理**:配置与配置项两级维护,站点设置页一键读取与保存
|
||||
- **参数管理**:系统参数分类维护,请求级缓存
|
||||
- **字典缓存刷新**:refreshCache 接口即时生效
|
||||
|
||||
|
||||
## [2.3.0] - 2024-10-23
|
||||
|
||||
**操作审计与日志查询上线。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **操作日志中间件**:异步批量落库(100 条或 1 秒刷盘),password/salt 脱敏、响应截断、耗时与状态记录,失败降级日志、不阻塞业务
|
||||
- **日志类型体系**:新增/修改/删除/查询/导入/导出等 40+ 类型常量,logType 字符串声明驱动
|
||||
- **日志查询模块**:操作日志/登录日志分页、详情、软删与批量删除
|
||||
- **IP 归属地**:ip2region(xdb)自动填充归属地字段
|
||||
|
||||
### 优化
|
||||
|
||||
- 密码类字段响应自动剔除,日志参数统一脱敏
|
||||
|
||||
|
||||
## [2.2.0] - 2024-09-10
|
||||
|
||||
**组织架构与个人中心完善。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **部门/职级/岗位三模块**:部门树形无限级(parent_id 自关联)
|
||||
- **树形接口约定**:叶子节点 Children 预置空数组,前端免判空
|
||||
- **个人中心**:获取用户信息与菜单、修改密码(旧密码校验)、更新资料与头像
|
||||
- 用户列表按部门/角色筛选,禁止删除有子部门/用户的部门
|
||||
|
||||
|
||||
## [2.1.0] - 2024-07-29
|
||||
|
||||
**用户、角色与菜单权限体系落地。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **用户/角色/菜单三模块**:标准七件套(分页/列表/详情/新增/修改/删除/批量删除)
|
||||
- **RBAC 权限模型**:用户 → 角色 → 菜单权限节点(目录/菜单/按钮三级),按钮级控制
|
||||
- **超级管理员**:通配权限 *:*:*,权限校验单点入口
|
||||
- **角色保存权限**:重写角色-菜单关联并即时刷新缓存
|
||||
- **用户扩展**:重置密码、用户-角色多角色分配、用户名/手机号唯一校验
|
||||
- **gmeta 标签声明**:路由与权限经标签声明,包装层每请求判定
|
||||
- 前端用户/角色/菜单管理页,权限指令控制按钮可见性
|
||||
|
||||
|
||||
## [2.0.0] - 2024-06-16
|
||||
|
||||
**工程奠基版本:前后端分离骨架与认证闭环建立。**
|
||||
|
||||
### 新增
|
||||
|
||||
- **后端分层骨架**:api / controller / logic / service 四层 + dao/entity/do 数据访问链路,统一响应信封(code/msg/data)与 PageData 分页
|
||||
- **建表约定**:goframe_ 表前缀、del_flag 软删列、审计字段(create_user/create_time/update_user/update_time)
|
||||
- **登录认证**:用户名密码 + 图形验证码(TTF 渲染 + SVG 降级)
|
||||
- **JWT 双令牌**:access 2 小时 + refresh 7 天,刷新轮换、旧 jti 拉黑防刷新复活
|
||||
- **密码安全**:bcrypt 双重加盐加密
|
||||
- **登录日志**:成功/失败/退出全记录(IP、浏览器、耗时、失败原因)
|
||||
- **中间件链雏形**:CORS → Response → JWT → Demo 演示模式拦截
|
||||
- **前端工程**:Vite + Vue3 + TypeScript + Pinia + ElementPlus,登录页、主布局、axios 封装与动态路由守卫
|
||||
|
||||
@@ -85,7 +85,7 @@ data = append(data, []any{
|
||||
编码规范:{模块snake}_{字段snake}(user_status / job_execute_policy / example_status)
|
||||
公共字典:role_data_scope(数据范围)等不带模块前缀
|
||||
|
||||
例外:operation_log.type 存注解常量值(0-40/99),用静态表 LogTypeText
|
||||
例外:operation_log.type 存标签常量值(0-40/99),用静态表 LogTypeText
|
||||
(consts.LogTypeNames),不走字典——数值与 gmeta logType 绑定,改动会破坏存量日志
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 5.18 gmeta 注解系统总览
|
||||
# 5.18 gmeta 标签系统总览
|
||||
|
||||
:::tip 概述
|
||||
gmeta 注解是本项目的"声明即事实"机制:请求结构体上的一个 gmeta.Meta 标签同时驱动路由注册、权限校验、操作日志、OpenAPI 文档四件事。解析与分发在 internal/router/bind.go(反射绑定)与 meta/(路由元数据表)。
|
||||
gmeta 标签是本项目的"声明即事实"机制:请求结构体上的一个 gmeta.Meta 标签同时驱动路由注册、权限校验、操作日志、OpenAPI 文档四件事。解析与分发在 internal/router/bind.go(反射绑定)与 meta/(路由元数据表)。
|
||||
:::
|
||||
|
||||
## 一个标签,四份事实
|
||||
@@ -41,7 +41,7 @@ CreateUser=ctx 用户名
|
||||
37=归档 38=取消归档 39=绑定 40=解绑 99=其他
|
||||
```
|
||||
|
||||
gmeta `logType` 字符串(query/add/update/delete/import/export/reset/…)经 LogTypeMap 转枚举;展示中文经 LogTypeNames(logic 的 LogTypeText)——**该字段不走字典**(数值与注解绑定,改动破坏存量日志)。
|
||||
gmeta `logType` 字符串(query/add/update/delete/import/export/reset/…)经 LogTypeMap 转枚举;展示中文经 LogTypeNames(logic 的 LogTypeText)——**该字段不走字典**(数值与标签绑定,改动破坏存量日志)。
|
||||
|
||||
## 开关与配置
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ panic 兜底 + errorStack=false(生产减少堆栈序列化开销)
|
||||
assets 长缓存(带 content hash)
|
||||
|
||||
运行:
|
||||
列表虚拟滚动(超大列表场景,Element Plus virtualized)
|
||||
列表虚拟滚动(超大列表场景,ElementPlus virtualized)
|
||||
图片懒加载/压缩(上传侧控制尺寸)
|
||||
keep-alive 控制缓存页面数量(内存 vs 体验平衡)
|
||||
```
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
│ ├── Dockerfile # 多阶段构建:静态编译 → alpine 运行(非 root + HEALTHCHECK)
|
||||
│ ├── docker-compose.yml # 三服务编排:后端 + MySQL8 + Redis7(GF_ 注入配置)
|
||||
│ └── .env.example # compose 变量模板(复制为 .env,明文密钥不入库)
|
||||
├── ui/ # 前端工程(Vue3 + Element Plus)
|
||||
├── ui/ # 前端工程(Vue3 + ElementPlus)
|
||||
├── document/ # 项目文档(五方言 SQL 脚本、架构定稿、wiki 等)
|
||||
│ ├── mysql/ # MySQL 定稿 DDL(规范基准)
|
||||
│ ├── postgresql/ # PostgreSQL 定稿 DDL
|
||||
@@ -89,7 +89,7 @@ internal/
|
||||
│ ├── do/ # 数据对象 DO(gf gen dao 产物)
|
||||
│ └── hooks/ # 全局模型钩子(审计盖章/软删改写/租户隔离)
|
||||
├── router/ # 路由注册(router.go)+ gmeta 反射绑定(bind.go)
|
||||
│ └── meta/ # 路由元数据表(权限/日志注解即事实)
|
||||
│ └── meta/ # 路由元数据表(权限/日志标签即事实)
|
||||
├── service/ # 服务接口层(每模块一文件,手维护,勿运行 gf gen service)
|
||||
└── task/ # 定时任务处理器(init 自注册到 logic.RegisterJobHandler)
|
||||
├── task.go # 注册与参数辅助
|
||||
|
||||
@@ -52,7 +52,7 @@ ui/src/
|
||||
│ │ ├── designSetting.ts projectSetting.ts lockscreen.ts ossConfig.ts
|
||||
│ ├── mutation-types.ts # ACCESS_TOKEN 等存储键常量
|
||||
│ ├── index.ts types.ts plugins/
|
||||
├── styles/ # 全局样式与主题变量(Element Plus 变量覆盖)
|
||||
├── styles/ # 全局样式与主题变量(ElementPlus 变量覆盖)
|
||||
├── utils/
|
||||
│ ├── http/axios/ # HTTP 封装(VAxios/transform/checkStatus…)
|
||||
│ ├── auth.ts Storage.ts # 路径工具 / 本地存储封装
|
||||
|
||||
@@ -72,7 +72,7 @@ columns ← views/{域}/{模块}/columns.ts
|
||||
## 开发规约
|
||||
|
||||
+ 列表列用 columns.ts 声明式配置(勿在模板里手写 el-table-column)
|
||||
+ 复杂列用 render 函数(h + Element Plus 组件)
|
||||
+ 复杂列用 render 函数(h + ElementPlus 组件)
|
||||
+ 图片列 src 用后端 GetFileUrl 已补域名的字段(勿手拼)
|
||||
+ 枚举列展示 {field}Text(勿硬编码映射)
|
||||
+ 操作列按钮逐个加 v-permission(对齐 gmeta permission)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 9.1 前端工程概述
|
||||
|
||||
:::tip 概述
|
||||
前端为 Vue3 + TypeScript + Vite + Element Plus + Pinia 的标准工程化项目(ui/ 目录),采用 Composition API,核心机制为:动态菜单路由、指令级权限、三件套页面规范(api/columns/querySchemas)、统一封装的 axios。
|
||||
前端为 Vue3 + TypeScript + Vite + ElementPlus + Pinia 的标准工程化项目(ui/ 目录),采用 Composition API,核心机制为:动态菜单路由、指令级权限、三件套页面规范(api/columns/querySchemas)、统一封装的 axios。
|
||||
:::
|
||||
|
||||
## 技术栈
|
||||
@@ -11,7 +11,7 @@
|
||||
| Vue | ^3.4.27 | 核心框架(Composition API) |
|
||||
| TypeScript | ^5.x | 类型系统 |
|
||||
| Vite | ^5.x | 构建(多环境模式 dev/test/uat/prod) |
|
||||
| Element Plus | ^2.7.4 | UI 组件库 |
|
||||
| ElementPlus | ^2.7.4 | UI 组件库 |
|
||||
| Pinia | ^2.1.7 | 状态管理 |
|
||||
| Vue Router | ^4.3.2 | 路由(常量路由 + 动态菜单路由) |
|
||||
| axios | ^0.27.2 | HTTP(封装于 utils/http/axios,VAxios 类) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 9.14 样式与主题定制
|
||||
|
||||
:::tip 概述
|
||||
样式体系基于 Element Plus CSS 变量 + styles/ 全局覆盖:主题色、暗黑模式、水印、动画等经 designSetting/projectSetting 在线配置。定制优先走变量覆盖而非逐组件覆盖。
|
||||
样式体系基于 ElementPlus CSS 变量 + styles/ 全局覆盖:主题色、暗黑模式、水印、动画等经 designSetting/projectSetting 在线配置。定制优先走变量覆盖而非逐组件覆盖。
|
||||
:::
|
||||
|
||||
## 样式目录(src/styles/)
|
||||
@@ -10,22 +10,22 @@
|
||||
styles/
|
||||
├── index.less / index.scss 入口样式
|
||||
├── variables.* SCSS/Less 变量
|
||||
├── element/ Element Plus 变量覆盖
|
||||
├── element/ ElementPlus 变量覆盖
|
||||
├── public/ 公共样式
|
||||
└── ...
|
||||
```
|
||||
|
||||
main.ts 引入顺序:Element Plus 样式 → 变量覆盖 → 全局样式(覆盖生效)。
|
||||
main.ts 引入顺序:ElementPlus 样式 → 变量覆盖 → 全局样式(覆盖生效)。
|
||||
|
||||
## 主题定制机制
|
||||
|
||||
```text
|
||||
Element Plus 暴露 CSS 变量(--el-color-primary 等):
|
||||
ElementPlus 暴露 CSS 变量(--el-color-primary 等):
|
||||
styles/ 覆盖变量根值 → 全组件生效
|
||||
|
||||
运行时主题切换(designSetting store):
|
||||
主题色在线更换 → 动态更新 CSS 变量 / 主题类名
|
||||
暗黑模式:html 挂 dark 类 → Element Plus dark 变量集
|
||||
暗黑模式:html 挂 dark 类 → ElementPlus dark 变量集
|
||||
灰度/色弱:filter 类名
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ designSetting 开关 + 文案 → 布局层渲染水印(canvas/css)
|
||||
## 页面样式规约
|
||||
|
||||
```text
|
||||
1. 优先用 Element Plus 组件与 CSS 变量(勿直接写死颜色值)
|
||||
1. 优先用 ElementPlus 组件与 CSS 变量(勿直接写死颜色值)
|
||||
2. 页面 scoped 样式(<style scoped>);跨页公共样式进 styles/public
|
||||
3. 主题相关颜色用 var(--el-color-*)(随主题切换自动适配)
|
||||
4. 少用 deep 选择器覆盖(Element 升级易碎);确需覆盖集中在 element/ 目录
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
| 文件 | 行数规模 | 职责 |
|
||||
|------|---------|------|
|
||||
| `api/v1/example.go` | ~200 行 | 全部 Req/Res + gmeta 注解 |
|
||||
| `api/v1/example.go` | ~200 行 | 全部 Req/Res + gmeta 标签 |
|
||||
| `internal/controller/example.go` | ~90 行 | 薄层透传 |
|
||||
| `internal/service/example.go` | ~75 行 | 手维护接口三件套 |
|
||||
| `internal/logic/example.go` | ~200 行 | ModuleSpec 声明 + 委托 + 扩展方法 |
|
||||
|
||||
@@ -96,4 +96,4 @@ func (c *CXxx) 方法名(ctx context.Context, req *v1.XxxReq) (res *v1.XxxRes, e
|
||||
| `CUpload` | multipart 上传(`*ghttp.UploadFile` + `p:"file"` 标签) |
|
||||
| `CGenerator` | 工具类,Preview/Generate/BatchGenerate |
|
||||
|
||||
控制器不区分"标准/特殊"写法——统一薄层透传,差异全部体现在请求结构体的 gmeta 注解上。
|
||||
控制器不区分"标准/特殊"写法——统一薄层透传,差异全部体现在请求结构体的 gmeta 标签上。
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
```text
|
||||
1. 设计符合项目规范的业务表(统一审计列 / del_flag / uk_* 唯一索引 / 注释枚举)
|
||||
2. 产出并理解 dao/entity/do 四件(gf gen dao 或生成器)
|
||||
3. 编写 api/v1 请求响应结构体与 gmeta 注解(权限/日志/OpenAPI 一体)
|
||||
3. 编写 api/v1 请求响应结构体与 gmeta 标签(权限/日志/OpenAPI 一体)
|
||||
4. 用 ModuleSpec 声明式基座实现逻辑层(筛选/字典/文件字段/钩子)
|
||||
5. 完成薄层控制器 + 手维护 service 接口 + 路由注册
|
||||
6. 配置权限节点并完成前端 querySchemas/columns/api 三件套联调
|
||||
@@ -35,7 +35,7 @@
|
||||
○ internal/dao/internal/example.go dao 内部实现(勿手改)
|
||||
○ internal/model/entity/example.go 实体
|
||||
○ internal/model/do/example.go 数据对象 DO
|
||||
★ api/v1/example.go 全部 Req/Res 结构体 + gmeta 注解
|
||||
★ api/v1/example.go 全部 Req/Res 结构体 + gmeta 标签
|
||||
★ internal/controller/example.go 薄层控制器(转发 service)
|
||||
★ internal/service/example.go 手维护接口 + Register + 取用函数
|
||||
★ internal/logic/example.go 业务实现(ModuleSpec 声明 + 方法委托)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 3.7 服务注册与路由
|
||||
|
||||
:::tip 概述
|
||||
本项目没有传统的路由表文件逐条登记——路由由 Bind 反射绑定从 gmeta 注解自动生成。手工需要维护的只有两处:service 接口文件(手维护)和 router.go 的一行 Bind 注册(生成器自动写入)。
|
||||
本项目没有传统的路由表文件逐条登记——路由由 Bind 反射绑定从 gmeta 标签自动生成。手工需要维护的只有两处:service 接口文件(手维护)和 router.go 的一行 Bind 注册(生成器自动写入)。
|
||||
:::
|
||||
|
||||
## service 接口文件(手维护,真实代码摘自 internal/service/example.go)
|
||||
@@ -95,7 +95,7 @@ Bind(s, new(controller.CXxx)) 对每个导出方法:
|
||||
→ 调用业务方法 → response.Ok/Fail 信封写出
|
||||
```
|
||||
|
||||
::: tip 注解即事实
|
||||
::: tip 标签即事实
|
||||
权限校验与操作日志共用同一份路由元数据(meta 表),gmeta 标签是唯一真相。不存在"代码改了忘改路由表/权限表"的可能。
|
||||
:::
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# 1.1 项目介绍
|
||||
|
||||
:::tip 概述
|
||||
EasyGoAdmin 是企业级多租户后台管理基座,后端基于 GoFrame v2 框架,前端基于 Vue3 + Element Plus,完全前后端分离架构。内置完善的 RBAC 权限体系(权限颗粒度精细至按钮级别)、多租户数据隔离、角色行级数据权限,预置用户、角色、菜单、部门、岗位、职级、日志、字典、配置、参数、定时任务、代码生成器等基础功能模块,开箱即用。
|
||||
EasyGoAdmin 是企业级多租户后台管理基座,后端基于 GoFrame v2 框架,前端基于 Vue3 + ElementPlus,完全前后端分离架构。内置完善的 RBAC 权限体系(权限颗粒度精细至按钮级别)、多租户数据隔离、角色行级数据权限,预置用户、角色、菜单、部门、岗位、职级、日志、字典、配置、参数、定时任务、代码生成器等基础功能模块,开箱即用。
|
||||
:::
|
||||
|
||||
## 软件说明
|
||||
|
||||
基于 Go 1.27、GoFrame v2.10、Vue3、TypeScript、Vite、ElementPlus 等技术栈构建的企业级前后端分离后台管理系统,支持 MySQL、PostgreSQL、SQL Server、Oracle、SQLite 五种数据库,通过配置文件一键切换,并内置五方言整库迁移工具。
|
||||
|
||||
后端采用 Go 语言,基于 GoFrame v2 框架、gdb 数据库操作、gmeta 反射注解等主流技术栈;前端基于 Vue3、TypeScript、Vite 构建,采用 ElementPlus 框架,遵循前后端分离主流设计思想。
|
||||
后端采用 Go 语言,基于 GoFrame v2 框架、gdb 数据库操作、gmeta 反射标签等主流技术栈;前端基于 Vue3、TypeScript、Vite 构建,采用 ElementPlus 框架,遵循前后端分离主流设计思想。
|
||||
|
||||
系统采用完全前后端分离架构,前端通过 API 调用后端服务实现数据交互。25 张业务表落地 27 个业务模块,全部平铺实现(auth/index + system7 + data7 + content3 + monitor7 + tool4)。
|
||||
|
||||
@@ -55,17 +55,114 @@ EasyGoAdmin 是企业级多租户后台管理基座,后端基于 GoFrame v2
|
||||
|
||||
## 软件出处
|
||||
|
||||
+ 软件名称:EasyGoAdmin 前后端分离 GoFrame+ElementPlus 版本
|
||||
+ 软件名称:EasyGoAdmin前后端分离GoFrame+ElementPlus版本
|
||||
+ 软件作者:@小蚂蚁云团队
|
||||
+ 软件协议:Apache-2.0
|
||||
+ 官网网址:[https://www.easygoadmin.vip](https://www.easygoadmin.vip)
|
||||
+ Gitee 仓库:[https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue)
|
||||
+ 文档网址:[http://docs.goframe.elevue.easygoadmin.vip](http://docs.goframe.elevue.easygoadmin.vip/)
|
||||
+ 文档网址:[http://docs.goframe.elevue.easygoadmin.vip](http://docs.goframe.elevue.easygoadmin.vip)
|
||||
+ 演示地址:[http://manage.goframe.elevue.easygoadmin.vip](http://manage.goframe.elevue.easygoadmin.vip)
|
||||
|
||||
## 适用场景
|
||||
## 软件版本
|
||||
|
||||
| 场景 | 说明 |
|
||||
|------|------|
|
||||
| 企业内部管理系统 | RBAC 权限 + 部门树 + 数据权限,完整的组织架构管控 |
|
||||
| 多租户 SaaS 平台 | 租户隔离 + 开户事务 + 租户用户上限 + 过期管理 |
|
||||
| 快速交付项目底座 | 代码生成器一键产出 CRUD 全套代码,分钟级搭建业务模块 |
|
||||
| 多数据库历史项目 | 五方言支持 + 整库迁移器,跨库迁移有实测记录 |
|
||||
| 版本名称 | 说明 | 地址 |
|
||||
|:---------|:-----|:-----|
|
||||
| GoFrame+Layui混编版 | 基于 GoFrame、Layui 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_Layui) |
|
||||
| GoFrame+ElementPlus前后端分离版 | 基于 GoFrame v2、Vue3、ElementPlus 等技术栈(当前版本)| [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_EleVue) |
|
||||
| GoFrame+AntDesign前后端分离版 | 基于 GoFrame、Vue3、AntDesign 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_AntdVue) |
|
||||
| GoFrame+NaiveUI前后端分离版 | 基于 GoFrame、Vue3、NaiveUI 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_GoFrame_NaiveVue) |
|
||||
| Gin+Layui混编版 | 基于 Gin、Layui 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Gin_Layui) |
|
||||
| Gin+ElementPlus前后端分离版 | 基于 Gin、Vue3、ElementPlus 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Gin_EleVue) |
|
||||
| Gin+AntDesign前后端分离版 | 基于 Gin、Vue3、AntDesign 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Gin_AntdVue) |
|
||||
| Gin+NaiveUI前后端分离版 | 基于 Gin、Vue3、NaiveUI 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Gin_NaiveVue) |
|
||||
| Beego+Layui混编版 | 基于 Beego、Layui 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Beego_Layui) |
|
||||
| Beego+ElementPlus前后端分离版 | 基于 Beego、Vue3、ElementPlus 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Beego_EleVue) |
|
||||
| Beego+AntDesign前后端分离版 | 基于 Beego、Vue3、AntDesign 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Beego_AntdVue) |
|
||||
| Beego+NaiveUI前后端分离版 | 基于 Beego、Vue3、NaiveUI 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Beego_NaiveVue) |
|
||||
| Iris+Layui混编版 | 基于 Iris、Layui 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Iris_Layui) |
|
||||
| Iris+ElementPlus前后端分离版 | 基于 Iris、Vue3、ElementPlus 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Iris_EleVue) |
|
||||
| Iris+AntDesign前后端分离版 | 基于 Iris、Vue3、AntDesign 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Iris_AntdVue) |
|
||||
| Iris+NaiveUI前后端分离版 | 基于 Iris、Vue3、NaiveUI 等技术栈 | [Gitee地址](https://gitee.com/easygoadmin/EasyGoAdmin_Iris_NaiveVue) |
|
||||
|
||||
## 模块展示
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><img src="/demo/1.png"/></td>
|
||||
<td><img src="/demo/2.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/3.png"/></td>
|
||||
<td><img src="/demo/4.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/5.png"/></td>
|
||||
<td><img src="/demo/6.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/7.png"/></td>
|
||||
<td><img src="/demo/8.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/9.png"/></td>
|
||||
<td><img src="/demo/10.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/11.png"/></td>
|
||||
<td><img src="/demo/12.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/13.png"/></td>
|
||||
<td><img src="/demo/14.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/15.png"/></td>
|
||||
<td><img src="/demo/16.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/17.png"/></td>
|
||||
<td><img src="/demo/18.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/19.png"/></td>
|
||||
<td><img src="/demo/20.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/21.png"/></td>
|
||||
<td><img src="/demo/22.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/23.png"/></td>
|
||||
<td><img src="/demo/24.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/25.png"/></td>
|
||||
<td><img src="/demo/26.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/27.png"/></td>
|
||||
<td><img src="/demo/28.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/29.png"/></td>
|
||||
<td><img src="/demo/30.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/31.png"/></td>
|
||||
<td><img src="/demo/32.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/demo/33.png"/></td>
|
||||
<td><img src="/demo/34.png"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## 开源协议
|
||||
|
||||
开源软件遵循 [Apache 2.0 协议](https://www.apache.org/licenses/LICENSE-2.0.html)。
|
||||
允许商业使用,但务必保留包括但不限于开源团队、软件作者、版权说明等信息。
|
||||
|
||||
## 版权信息
|
||||
|
||||
版权所有 Copyright © 2026 [www.easygoadmin.vip](https://www.easygoadmin.vip) All rights reserved。
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
## 第三方依赖
|
||||
|
||||
```text
|
||||
本软件依赖众多开源组件(GoFrame、Element Plus、Excelize、golang-jwt 等),
|
||||
本软件依赖众多开源组件(GoFrame、ElementPlus、Excelize、golang-jwt 等),
|
||||
各依赖遵循其自身的开源协议。依赖的安全漏洞修复随版本演进提供,
|
||||
但及时升级由使用方决策。
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
## 为什么赞助
|
||||
|
||||
```text
|
||||
+ 持续维护:跟进 GoFrame/Vue/Element Plus 生态升级与安全补丁
|
||||
+ 持续维护:跟进 GoFrame/Vue/ElementPlus 生态升级与安全补丁
|
||||
+ 文档完善:保持文档与代码同步(本套 145 页开发者文档的编写与维护)
|
||||
+ 特性演进:多实例能力增强、导出增强、数据权限扩展档等规划项
|
||||
+ Issue 优先响应:赞助者问题优先排期
|
||||
|
||||
@@ -71,7 +71,7 @@ curl http://127.0.0.1:8000/api/user/page?pageNo=1&pageSize=3 \
|
||||
| `http://127.0.0.1:8000/swagger` | 本地托管 Redoc UI(免登录) |
|
||||
| `http://127.0.0.1:8000/api.json` | 原生 OpenAPI JSON(gmeta 补注册生成) |
|
||||
|
||||
gmeta 注解(method/path/summary/permission)会完整体现在文档中,接口与文档天然同步。
|
||||
gmeta 标签(method/path/summary/permission)会完整体现在文档中,接口与文档天然同步。
|
||||
|
||||
## 响应信封约定
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 2.3 前端服务启动
|
||||
|
||||
:::tip 概述
|
||||
前端为 Vue3 + TypeScript + Vite + Element Plus 工程(`ui/` 目录),通过 pnpm 安装依赖后一条命令启动开发服务器,接口代理指向后端 `:8000`。
|
||||
前端为 Vue3 + TypeScript + Vite + ElementPlus 工程(`ui/` 目录),通过 pnpm 安装依赖后一条命令启动开发服务器,接口代理指向后端 `:8000`。
|
||||
:::
|
||||
|
||||
## 安装依赖
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
```text
|
||||
□ 列表用 Page 容器 + Table(columns 配置) + pagination
|
||||
□ 复杂列用 render 函数(h + Element Plus 组件)
|
||||
□ 复杂列用 render 函数(h + ElementPlus 组件)
|
||||
□ 筛选用 querySchemas 配置(勿手写搜索区)
|
||||
□ 下拉选项优先字典驱动(getDictItemList)
|
||||
□ 上传用 Upload 组件(持 URL,后端转正)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 1.5 技术栈说明
|
||||
|
||||
:::tip 概述
|
||||
本项目以后端 GoFrame v2 + 前端 Vue3/Element Plus 为核心,全部依赖选型遵循"主流、稳定、长期维护"原则。本页给出完整的技术栈清单与关键依赖版本。
|
||||
本项目以后端 GoFrame v2 + 前端 Vue3/ElementPlus 为核心,全部依赖选型遵循"主流、稳定、长期维护"原则。本页给出完整的技术栈清单与关键依赖版本。
|
||||
:::
|
||||
|
||||
## 后端技术栈
|
||||
@@ -29,7 +29,7 @@
|
||||
| Vue | ^3.4.27 | 核心框架(Composition API) |
|
||||
| TypeScript | ^5.x | 类型系统 |
|
||||
| Vite | ^5.x | 构建工具(多环境模式) |
|
||||
| Element Plus | ^2.7.4 | UI 组件库 |
|
||||
| ElementPlus | ^2.7.4 | UI 组件库 |
|
||||
| Pinia | ^2.1.7 | 状态管理 |
|
||||
| Vue Router | ^4.3.2 | 路由(常量路由 + 动态菜单路由) |
|
||||
| axios | ^0.27.2 | HTTP 客户端(封装于 utils/http) |
|
||||
@@ -58,7 +58,7 @@
|
||||
## 架构模式一览
|
||||
|
||||
```text
|
||||
后端: 分层架构 + 声明式基座 + 全局钩子横切 + gmeta 反射注解
|
||||
后端: 分层架构 + 声明式基座 + 全局钩子横切 + gmeta 反射标签
|
||||
前端: 组合式 API + 动态路由 + 指令级权限 + querySchemas 声明式筛选
|
||||
通信: RESTful JSON + JWT Bearer + 统一响应信封
|
||||
(公开路由例外:/api/login、/api/captcha、/api/oauth2/token、/api/health 不带版本段)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
### 1. Go 语言高性能后端
|
||||
|
||||
基于 GoFrame v2 企业级框架,原生并发能力 + 静态编译单文件部署。中间件链、泛型基座、反射注解均以 Go 惯用法实现,无 PHP/Java 式框架侵入。
|
||||
基于 GoFrame v2 企业级框架,原生并发能力 + 静态编译单文件部署。中间件链、泛型基座、元数据标签均以 Go 惯用法实现,开箱即用、无框架侵入。
|
||||
|
||||
```text
|
||||
go build -o bin/admin-server.exe main.go # 单文件产物
|
||||
@@ -29,7 +29,7 @@ func (s *sJob) Page(ctx context.Context, req *v1.JobPageReq) (*v1.JobPageRes, er
|
||||
|
||||
差异进声明与钩子,写不进钩子就手写(合法逃生舱),基座永不出现"按模块分支"的代码。
|
||||
|
||||
### 3. gmeta 注解即事实
|
||||
### 3. gmeta 标签即事实
|
||||
|
||||
请求结构体上的一个 gmeta 标签同时驱动四件事:路由注册、权限校验、操作日志、OpenAPI 文档。杜绝"代码、路由表、权限表、文档"四处不一致的行业顽疾。
|
||||
|
||||
@@ -52,16 +52,15 @@ gmeta.Meta `method:"get" path:"/api/user/page" summary:"用户分页"
|
||||
|
||||
## 与常见方案的对比
|
||||
|
||||
| 维度 | EasyGoAdmin(GoFrame) | 传统 PHP 后台 | 通用 Go Admin 项目 |
|
||||
|------|----------------------|--------------|-------------------|
|
||||
| 部署形态 | 单二进制文件 | 运行时 + 依赖目录 | 单二进制文件 |
|
||||
| CRUD 开发量 | 声明式基座 + 生成器 | 基类继承 + 手写 | 多数需手写 |
|
||||
| 注解体系 | gmeta 反射(路由/权限/日志/OpenAPI 一体) | Attribute 注解 | 通常仅路由 |
|
||||
| 多租户 | 全局钩子自动隔离,9 张租户级表 | 基类手动处理 | 需自行集成 |
|
||||
| 数据权限 | 四档角色数据权限,一行声明接线 | 通常无或插件 | 部分支持 |
|
||||
| 多数据库 | 五方言 + 整库迁移器 | 通常 MySQL 为主 | 多数 1-2 种 |
|
||||
| 限流防护 | 固定窗口 + 认证入口独立阈值 + 受信代理 | 通常依赖扩展 | 部分支持 |
|
||||
| 在线用户 | 双令牌拉黑强退,防刷新复活 | Session 方案 | 部分支持 |
|
||||
| 维度 | EasyGoAdmin(GoFrame) | 通用 Go Admin 项目 |
|
||||
|------|----------------------|-------------------|
|
||||
| CRUD 开发量 | 声明式基座 + 生成器 | 多数需手写 |
|
||||
| 元数据体系 | gmeta 反射(路由/权限/日志/OpenAPI 一体) | 通常仅路由 |
|
||||
| 多租户 | 全局钩子自动隔离,9 张租户级表 | 需自行集成 |
|
||||
| 数据权限 | 四档角色数据权限,一行声明接线 | 部分支持 |
|
||||
| 多数据库 | 五方言 + 整库迁移器 | 多数 1-2 种 |
|
||||
| 限流防护 | 固定窗口 + 认证入口独立阈值 + 受信代理 | 部分支持 |
|
||||
| 在线用户 | 双令牌拉黑强退,防刷新复活 | 部分支持 |
|
||||
|
||||
## 工程纪律保障
|
||||
|
||||
@@ -77,4 +76,4 @@ gmeta.Meta `method:"get" path:"/api/user/page" summary:"用户分页"
|
||||
|
||||
+ 需要快速交付的软件公司:生成器 + 基座把 CRUD 开发压缩到分钟级
|
||||
+ 有 SaaS 需求的创业团队:租户隔离 + 开户事务 + 用户上限开箱即用
|
||||
+ 学习 Go 企业级开发的团队:分层、钩子、泛型、反射注解的真实工程样本
|
||||
+ 学习 Go 企业级开发的团队:分层、钩子、泛型、反射标签的真实工程样本
|
||||
|
||||