No description
  • JavaScript 95.2%
  • HTML 2.4%
  • Vue 1.3%
  • Go 0.8%
  • CSS 0.3%
Find a file
2026-07-15 05:05:44 -04:00
.gitea/workflows feat: MaxCompute SQL查询 + SQL纠错 + Endpoint编辑 + JSON导入 2026-05-28 03:52:42 -04:00
.idea feat: MaxCompute SQL查询 + SQL纠错 + Endpoint编辑 + JSON导入 2026-05-28 03:52:42 -04:00
build refactor: Wails桌面应用打包+API请求适配 2026-07-07 21:25:59 -04:00
frontend perf: ExcelTable优化 - 参考旧版本虚拟滚动 2026-07-15 05:05:44 -04:00
frontend_dist fix: 最大化窗口保留标题栏+DiffView Monaco同步滚动+CheckView/InsertView 34px 2026-07-07 22:44:32 -04:00
handler feat: datamap改用ODPS SDK + 可搜索下拉框 + xxx环境替换 2026-06-01 04:47:10 -04:00
router feat: 单EXE Web服务模式 + 交接文档 2026-07-08 02:54:28 -04:00
service refactor: 前后端分离架构(Vue 3 + Naive UI + Vite) 2026-07-07 11:20:39 -04:00
static feat(odps): 取消进度条+查询中状态+微软雅黑字体+表头固定+行号自适应 2026-06-04 23:16:09 -04:00
templates feat: 密码门控+隐藏ABCode生码菜单+DDL页面完整实现 2026-07-07 20:51:36 -04:00
utils feat: MaxCompute SQL查询 + SQL纠错 + Endpoint编辑 + JSON导入 2026-05-28 03:52:42 -04:00
.gitignore chore: 清理误提交的二进制文件和备份 2026-07-07 11:21:01 -04:00
a.txt feat: MaxCompute SQL查询 + SQL纠错 + Endpoint编辑 + JSON导入 2026-05-28 03:52:42 -04:00
DataEngineerTools refactor: 前后端分离架构(Vue 3 + Naive UI + Vite) 2026-07-07 11:20:39 -04:00
DataEngineerTools-v1.60-c2c0101.7z fix: 修复参数弹窗执行按钮无响应 + build v1.61-c2c0101 2026-07-14 02:43:45 -04:00
DataEngineerTools-v1.61-6b23b9d.7z fix: 查询超时20分钟+loading不遮挡+表格优化+列宽可调 2026-07-14 22:33:09 -04:00
DataEngineerTools-v1.62-643482b.7z feat: 添加ExcelTable组件+测试页面(虚拟滚动/列宽拖动/排序/自由复制) 2026-07-14 22:56:13 -04:00
DataEngineerTools-v1.63-a7e30f6.7z perf: ExcelTable优化 - 参考旧版本虚拟滚动 2026-07-15 05:05:44 -04:00
DataEngineerTools.exe.gz refactor: 前后端分离架构(Vue 3 + Naive UI + Vite) 2026-07-07 11:20:39 -04:00
ddl.csv fix: Wails前端通过Middleware代理API请求解决跨域 2026-07-07 21:50:21 -04:00
go.mod refactor: Wails桌面应用打包+API请求适配 2026-07-07 21:25:59 -04:00
go.sum refactor: Wails桌面应用打包+API请求适配 2026-07-07 21:25:59 -04:00
HANDOVER.md docs: 完整项目交接文档 2026-07-09 10:51:12 +08:00
main.go fix: 查询超时20分钟+loading不遮挡+表格优化+列宽可调 2026-07-14 22:33:09 -04:00
mock_server fix(check): 自定义URL悬浮窗简化、历史按钮样式、SQL格式化按钮 2026-07-07 12:23:01 -04:00
mock_server.go feat: ODPS表格增强(列宽拖动/排序/筛选/复制) + bizdate默认昨天 2026-07-14 01:42:41 -04:00
odps_projects.json fix(format): 修复输入框无法输入 + 抽取common.js 2026-05-28 12:08:52 -04:00
README.md feat: MaxCompute SQL查询 + SQL纠错 + Endpoint编辑 + JSON导入 2026-05-28 03:52:42 -04:00

DataEngineerTools 开发文档

本文档面向后续新增需求的开发者,用于统一开发规范、文件组织、前端风格和后端架构约定。 如果有复杂到不能遵守规范的情况,也可以详细说明后,经过我的判断可以超出规范。


一、项目概述

DataEngineerTools 是一个面向数据工程师的内部辅助工具集,基于 Go 1.25 + Gin 构建。
所有静态资源和 HTML 模板通过 embed.FS 打包进二进制,部署只需一个可执行文件,无需外部文件目录。

  • 监听端口:8080
  • 技术栈Go + Gin后端+ Vue 3CDN 引入,前端)+ HTML/CSS原生
  • 部署方式go build 产物单文件部署

二、核心约束(必须遵守)

⚠️ 以下是本项目最重要的硬性规范,新增任何需求都必须遵守。

一个需求 = 一套文件,命名一一对应

层次 文件数量 命名规则 示例
前端页面 1 个 HTML templates/{name}.html templates/ddl.html
后端 Handler 1 个文件 handler/{name}_handler.go handler/ddl_handler.go
后端 Service 1 个文件 service/{name}_service.go service/ddl_service.go
路由注册 router/router.go 中统一添加

禁止 为同一个需求创建多个 Handler 文件或多个 Service 文件,也禁止拆分多个 HTML 页面。

简单需求可以纯前端实现

  • 如果需求不涉及后端数据处理(如文本 Diff、纯计算工具可以只创建 HTML不创建 Handler 和 Service
  • 路由中仅注册页面 GET 路由即可:
    r.GET("/diff", func(c *gin.Context) { c.HTML(http.StatusOK, "diff.html", nil) })
    

CSS / JS 可以多文件

  • static/css/static/js/ 下可以创建多个文件,供各页面按需引入
  • static/css/common.css全局公共样式,不要在里面写页面专属样式
  • 页面专属样式写在对应 HTML 的 <style> 标签内

三、目录结构

DataEngineerTools/
├── main.go                   # 入口embed 打包并启动
├── go.mod
├── router/
│   └── router.go             # 统一路由注册 + 依赖组装(唯一组装点)
├── handler/                  # HTTP 层,每个需求一个文件
│   ├── check_handler.go
│   ├── format_handler.go
│   ├── ddl_handler.go
│   └── abcode_handler.go
├── service/                  # 业务逻辑层,每个需求一个文件
│   ├── check_service.go
│   ├── format_service.go
│   ├── ddl_service.go
│   └── abcode_service.go
├── utils/
│   └── abcode/               # 独立算法包,不依赖 HTTP 层
│       ├── packet.go         # 协议层
│       └── codec.go          # 视觉层
├── templates/                # Gin HTML 模板embed 打包)
│   ├── common.html           # 公共组件(侧边栏 sidebar
│   ├── index.html            # 首页导航
│   └── {name}.html           # 各需求页面
└── static/                   # 前端静态资源embed 打包)
    ├── css/
    │   └── common.css        # 全局公共样式
    ├── js/                   # 各页面专属 JS可选
    └── lib/                  # 第三方库(只读,勿修改)
        ├── vue.global.js
        ├── highlight.min.js
        ├── all.min.css       # Font Awesome 图标
        └── ...

四、新增需求开发流程

步骤一:判断是否需要后端

需求类型 是否需要后端
纯文本处理、格式转换(无需外部数据) 纯前端即可
需要调用外部 API / 访问文件系统 / 复杂算法 需要后端

步骤二:创建文件(仅有后端时)

# 创建 Service业务逻辑
touch service/{name}_service.go

# 创建 HandlerHTTP 层)
touch handler/{name}_handler.go

步骤三:创建前端页面

touch templates/{name}.html

参考 templates/format.html 作为最简单的模板起点。

步骤四:注册路由(router/router.go

// 1. 页面路由
r.GET("/{name}", func(c *gin.Context) { c.HTML(http.StatusOK, "{name}.html", nil) })

// 2. 初始化 Service 和 Handler如有后端
{name}Service := service.New{Name}Service()
{name}Handler := handler.New{Name}Handler({name}Service)

// 3. API 路由(如有后端)
api.POST("/{name}/action", {name}Handler.SomeAction)

步骤五:更新侧边栏(templates/common.html

sidebar-menu 区域添加导航项:

<a href="/{name}" class="menu-item" id="nav-{name}">
    <div class="menu-icon"><i class="fas fa-icon-name"></i></div>
    <div class="menu-text">功能名称</div>
</a>

同时在 common.html 底部的 JS 中添加高亮判断:

} else if (path.includes("{name}")) {
    document.getElementById("nav-{name}").classList.add("active");
}

五、后端开发规范

5.1 Handler 职责边界

Handler 只负责

  1. 绑定入参(c.ShouldBindJSON
  2. 调用 Service 方法
  3. 返回 HTTP 响应(c.JSON

Handler 不允许包含任何业务逻辑。

func (h *DDLHandler) ParseDDL(c *gin.Context) {
    var request map[string]string
    if err := c.ShouldBindJSON(&request); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "无效的JSON格式"})
        return
    }
    // 业务逻辑全部委托 Service
    csv := h.ddlService.ParseDDLToCSV(request["ddl"])
    c.JSON(http.StatusOK, gin.H{"csv": csv})
}

5.2 Service 职责边界

Service 只负责:业务逻辑、算法、外部调用。
Service 不允许导入 github.com/gin-gonic/gin,入参出参均为纯 Go 类型

5.3 构造函数 + 依赖注入

// Service
type {Name}Service struct { /* 依赖字段 */ }
func New{Name}Service() *{Name}Service { return &{Name}Service{...} }

// Handler
type {Name}Handler struct { {name}Service *service.{Name}Service }
func New{Name}Handler(s *service.{Name}Service) *{Name}Handler { return &{Name}Handler{{name}Service: s} }

5.4 错误处理规范

  • 参数绑定失败 → 400 Bad Request + {"error": "描述"}
  • 业务处理失败 → 500 Internal Server Error + {"error": "描述"}
  • 特殊情况:若前端需要统一用响应体的字段判断结果(不依赖 HTTP 状态码),可返回 200 OK + {"message": "错误描述"},但需在代码注释中说明原因

5.5 并发安全

  • Service 中若有内存共享状态(如历史记录缓存),必须使用 sync.RWMutex
  • 读操作用 RLock() / RUnlock(),写操作用 Lock() / Unlock()
  • 对外暴露共享数据时,返回拷贝而非原始引用

5.6 请求体大小限制

接收文件或大数据时,必须在 Handler 中限制请求体大小:

c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 50<<20) // 50MB

六、前端开发规范

6.1 整体页面结构模板

所有功能页面遵循统一的 HTML 骨架:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据服务工具集 - {功能名称}</title>

    <!-- Vue 3必须 -->
    <script src="/lib/vue.global.js"></script>

    <!-- 代码高亮(按需引入) -->
    <link rel="stylesheet" href="/lib/atom-one-dark.min.css">
    <script src="/lib/highlight.min.js"></script>

    <!-- Font Awesome 图标(必须) -->
    <link rel="stylesheet" href="/lib/all.min.css">

    <!-- 公共样式(必须) -->
    <link rel="stylesheet" href="/css/common.css">

    <style>
        /* 当前页面专属样式写这里 */
    </style>
</head>
<body>
<div id="app" class="app-layout">

    <!-- 公共侧边栏(必须) -->
    [[template "sidebar"]]

    <div class="main-content">
        <!-- 页面主体内容 -->
    </div>
</div>

<!-- 暗色模式切换按钮(必须复制此段) -->
<div class="theme-toggle" id="themeToggle">
    <svg class="sun-icon" viewBox="0 0 24 24"><path d="M12 17C14.7614 17 17 14.7614 17 12C17 9.23858 14.7614 7 12 7C9.23858 7 7 9.23858 7 12C7 14.7614 9.23858 17 12 17Z"/><path d="M12 1V3M12 21V23M23 12H21M3 12H1M20.07 4.93L18.66 6.34M5.34 17.66L3.93 19.07M20.07 19.07L18.66 17.66M5.34 6.34L3.93 4.93"/></svg>
    <svg class="moon-icon" viewBox="0 0 24 24"><path d="M21 12.79C20.8427 14.4922 20.2039 16.1144 19.1582 17.4668C18.1126 18.8192 16.7035 19.8458 15.0957 20.4265C13.4879 21.0073 11.7472 21.1181 10.0806 20.7461C8.41394 20.3741 6.88989 19.5345 5.67879 18.3234C4.46769 17.1123 3.62814 15.5883 3.25612 13.9216C2.8841 12.2549 2.99495 10.5143 3.57568 8.90647C4.15642 7.29864 5.18304 5.88953 6.53544 4.84389C7.88783 3.79826 9.51004 3.15941 11.212 3C9.81902 4.80958 9.15354 7.02094 9.3534 9.23622C9.55325 11.4515 10.6038 13.5001 12.2976 14.9111C13.9914 16.3221 16.1884 16.9999 18.412 16.8061C20.6356 16.6123 22.6903 15.5653 24 14"/></svg>
</div>

<script>
    // 暗色模式逻辑(必须复制此段)
    document.addEventListener('DOMContentLoaded', function() {
        if (localStorage.getItem('darkMode') === 'true') {
            document.body.classList.add('dark-mode');
        }
        document.getElementById('themeToggle').addEventListener('click', function() {
            document.body.classList.toggle('dark-mode');
            localStorage.setItem('darkMode', document.body.classList.contains('dark-mode'));
        });
    });
</script>
</body>
</html>

6.2 设计风格Design Token

所有颜色、间距必须使用 CSS 变量,禁止硬编码颜色值:

CSS 变量 亮色值 暗色值 用途
--primary #6366F1 #818CF8 主色调(按钮、高亮、标题)
--secondary #10B981 #34D399 辅助色
--background #F8FAFC 0F172A 页面背景
--surface #FFFFFF #1E293B 卡片/面板背景
--text-primary #1E293B #F1F5F9 主要文字
--text-secondary #64748B #94A3B8 次要文字、说明
/* ✅ 正确 */
color: var(--primary);
background: var(--surface);

/* ❌ 错误 */
color: #6366F1;
background: #FFFFFF;

6.3 字体规范

用途 字体
界面文字 'Inter', system-ui, sans-serif
代码 / 输入框 / 结果展示 'JetBrains Mono', monospace

6.4 暗色模式适配

  • 所有颜色使用 CSS 变量(自动适配)
  • 暗色专属样式使用 .dark-mode 前缀覆盖:
.dark-mode .panel {
    box-shadow: 0 8px 24px -6px rgba(0, 0, 0, 0.2);
}
  • 暗色偏好存储在 localStorage.getItem('darkMode'),页面初始化时读取

6.5 通用布局组件(直接复用 common.css

类名 用途
.app-layout 根容器Flex 横向布局(侧边栏 + 主内容)
.main-content 主内容区,自动留出侧边栏宽度
.panel 卡片容器,白色圆角阴影
.panel-header 面板标题区(含 h1 和描述 p
.input-container 带边框圆角的输入区域focus 时显示主色边框
.btn .btn-primary 主操作按钮
.btn-copy 复制按钮(半透明主色背景)
.history-list 历史记录列表容器
.history-item 历史记录单项
.loading-spinner 圆形加载动画
.status-bar 底部状态栏

6.6 布局模式

左右分栏(主要布局):左侧输入区 + 右侧结果区,参考 check.html / ddl.html

.original-container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr; /* 三列均分 */
    gap: 24px;
    height: calc(100vh - 48px);
}

单列居中(简单工具):参考 format.html

.format-numbers-container {
    max-width: 1000px;
    margin: 0 auto;
}

6.7 Vue 3 使用规范

  • 使用 CDN 引入的 vue.global.js(无需构建工具)
  • 使用 Options API 风格(与现有页面保持一致)
  • 模板分隔符为 [[ ]]Gin 已配置,避免与 Vue {{ }} 冲突)
<div id="app">
    <!-- Vue 模板使用 {{ }} -->
    <p>{{ message }}</p>
</div>
<script>
    const { createApp } = Vue;
    createApp({
        data() {
            return { message: 'Hello' }
        }
    }).mount('#app');
</script>

注意Gin 模板层(服务端渲染)使用 [[ ]]Vue 模板层(客户端渲染)使用 {{ }},二者不冲突。

6.8 API 请求规范

前端统一使用 fetch 发送请求:

// POST JSON
const res = await fetch('/api/{name}/action', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
});
const data = await res.json();

6.9 图标库

使用 Font Awesome 6(已打包在 /lib/all.min.css),图标列表参考 fontawesome.com/icons

<i class="fas fa-database"></i>   <!-- 实心图标 -->
<i class="far fa-copy"></i>       <!-- 线框图标 -->

七、现有功能模块一览

功能名称 路由 是否有后端 文件
首页导航 / templates/index.html
数据服务查询 /check check_handler.go / check_service.go
SQL 格式化工具 /format format_handler.go / format_service.go
DDL 解析工具 /ddl ddl_handler.go / ddl_service.go
ABCode 生码 /abcode-encode abcode_handler.go / abcode_service.go
ABCode 解码 /abcode-decode 同上
文档比对Diff /diff templates/diff.html

八、主要依赖

依赖包 用途
github.com/gin-gonic/gin HTTP Web 框架
github.com/klauspost/compress/zstd Zstandard 压缩
github.com/klauspost/reedsolomon Reed-Solomon 纠错编码
github.com/pquerna/otp TOTP 动态口令
golang.org/x/crypto PBKDF2 密钥派生

九、待办 / 未完成功能

以下功能已在首页导航或侧边栏展示,但路由和实现尚未完成,后续开发时参考本文档规范补全:

功能 规划路由 说明
并发测试 /concurrent 模拟多线程并发请求数据服务
数据转换工具 /insert 数据转 INSERT 语句MySQL/Hologres/MaxCompute
SQL 查询工具 /sql JDBC 直连执行 SQLMySQL/PostgreSQL