游乐游手机版
首页/AI教程/文章详情

PHP转型AI与Golang实战:新增area接口及区域三级联动组件

时间:2026-08-15 14:25
这是一个系列 Blog。作者将以 PHP 全栈工程师的视角,借助 AI 工具(TRAE、claude code、codex、deepseek、豆包等),从零系统学习 Golang 语言开发,并最终完成 ai-go-admin(github | gitee)开源项目的制作(欢迎 star),全程进行实

这是一个系列 Blog。作者将以 PHP 全栈工程师的视角,借助 AI 工具(TRAE、claude code、codex、deepseek、豆包等),从零系统学习 Golang 语言开发,并最终完成 ai-go-admin(github | gitee)开源项目的制作(欢迎 star),全程进行实战记录与经验分享。

上一期我们完成了“管理员个人资料页面、管理员日志优化”,这一期的开发目标是:新增 area 接口,并实现区域三联动选择组件。

今天的主要开发工具依然是 TRAE IDE。

增加 area 接口

模型和迁移

这里直接从 BuildAdmin 中复制建表 SQL,再让 AI 协助生成模型和迁移文件。同时依旧按照之前的规范,将 AI GO ADMIN 系统自带的杂项模型统一放入 common.go,而不是拆分成多个独立文件,以避免项目初期就出现大量模型文件,影响代码结构的简洁性。提示词如下:

建立 area 表的迁移和模型:

迁移放在: @cmd/migrate/migrations/000002_common.up.sql模型放在: @internal/model/common.go

参考 SQL:

CREATE TABLE `area`(`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',`pid` int UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级ID',`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',`level` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT '等级',`code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '行政区划代码',`zip` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '邮编',PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '省份地区表' ROW_FORMAT = DYNAMIC;

AI 生成好的模型如下。它大概是看到其他模型都定义了 TableName 方法,所以这里也顺手补上了,这个处理是正确的:

// Area 省份地区模型type Area struct {IDuint `gorm:"comment:ID;primarykey;autoIncrement" json:"id"`Pid uint `gorm:"comment:上级ID;not null;default:0;index" json:"pid"`Namestring `gorm:"comment:名称;type:varchar(64);not null;default:''" json:"name"`Level uint8`gorm:"comment:等级;not null;default:0;index" json:"level"`Codestring `gorm:"comment:行政区划代码;type:varchar(32);not null;default:''" json:"code"`Zip string `gorm:"comment:邮编;type:varchar(32);not null;default:''" json:"zip"`}// TableName 指定 Area 模型表名func (Area) TableName() string {return "areas"}

迁移 SQL 如下:

-- ===== areas 省份地区表 =====CREATE TABLE IF NOT EXISTS "__PREFIX__areas" ("id"bigserial PRIMARY KEY,"pid" bigint NOT NULL DEFAULT 0,"name"varchar(64) NOT NULL DEFAULT '',"level" smallint NOT NULL DEFAULT 0,"code"varchar(32) NOT NULL DEFAULT '',"zip" varchar(32) NOT NULL DEFAULT '');CREATE INDEX IF NOT EXISTS "__PREFIX__idx_areas_pid" ON "__PREFIX__areas" ("pid");CREATE INDEX IF NOT EXISTS "__PREFIX__idx_areas_level" ON "__PREFIX__areas" ("level");COMMENT ON TABLE "__PREFIX__areas" IS '省份地区数据表';COMMENT ON COLUMN "__PREFIX__areas"."id" IS 'ID';COMMENT ON COLUMN "__PREFIX__areas"."pid" IS '上级ID';COMMENT ON COLUMN "__PREFIX__areas"."name" IS '名称';COMMENT ON COLUMN "__PREFIX__areas"."level" IS '等级';COMMENT ON COLUMN "__PREFIX__areas"."code" IS '行政区划代码';COMMENT ON COLUMN "__PREFIX__areas"."zip" IS '邮编';

这份迁移里并不包含具体的省、市、区数据,因为这类地区数据量非常大,直接内置在框架中并不合适。后续会通过单独的 SQL 文件提供,开发者按需下载和导入即可。这里先给出一个种子数据示例:

INSERT INTO areas VALUES (1, 0, '北京市', 1, '110000', '100000');INSERT INTO areas VALUES (2, 1, '北京市', 2, '110100', '100000');INSERT INTO areas VALUES (3, 2, '东城区', 3, '110101', '100010');INSERT INTO areas VALUES (4, 2, '西城区', 3, '110102', '100032');INSERT INTO areas VALUES (5, 2, '朝阳区', 3, '110105', '100020');INSERT INTO areas VALUES (6, 2, '丰台区', 3, '110106', '100071');

目前系统中的省份地区数据还没有同步到最新版本,但这未必是坏事。把背后的设计逻辑想清楚后,你会发现:权威数据源已经找到了,后续更新方案也已经明确,现在只是暂时没有执行而已。真正落地时,现有数据中的每一条记录都非常关键。

  1. 不能删:一旦删除,ID 不但需要重新排序,而且所有依赖该 ID 的关联数据都会失去关联
  2. 不能直接修改区域名称等字段:一旦改动,同样可能影响已有的业务关联

这时你可能会说,现在还是一个新项目,并不存在历史关联数据。可问题在于,还要再往后想一步:这次改完之后,未来省市区数据如果再次更新怎么办?

更稳妥的解决方案,其实只能是增加记录状态标记。后续新增一个 status 字段,把那些“删除、改名”的地区数据统一标记为过时状态,这样既不会影响已有关联数据,前端省份区域选择组件也可以在读取时自动忽略过时数据;至于新增区域,直接插入到末尾即可。也就是说,这次看似“偷懒”,其实是在为后续地区数据规范化更新提前铺路。

增加 area 接口

这里直接让 AI 参考 @../ba238/app/api/controller/Ajax.php 中的 area 方法,分析其内部的 get_area 函数,然后在本项目中实现 @internal/handler/common/util.goarea 接口。

最终代码如下。用大白话来说,就是根据传入的 provincecity 参数,动态获取对应的下级区域数据:

// Area 用于获取省、市、区地区数据func Area(c *gin.Context) {city := c.DefaultQuery("city", "")province := c.DefaultQuery("province", "")pid := 0level := 1if province != "" {pid, _ = strconv.Atoi(province)level = 2if city != "" {pid, _ = strconv.Atoi(city)level = 3}}areas, err := repoCommon.NewAreaRepository().FindByPidAndLevel(c.Request.Context(), pid, level)if err != nil {httpx.Fail(c, httpx.WithMessage("地区数据查询失败"))return}httpx.Success(c, httpx.WithData(areas))}

一开始,AI 其实没有把对应的仓储层一并创建出来,而是直接在控制器里写了 GORM 查询语句,把数据查询逻辑塞进了控制器。后面我只补充了一句提示词,问题就很快解决了:建立 area 对应的仓储层,并改为通过仓储发起查询,创建位置放在 @internal/repository/common/

增加 area 选择三联动公共组件

刚刚才完成 area 接口,趁着上下文还在,继续让 AI 接着实现区域三联动组件:参考 @../ba238/web/src/components/baInput/index.vuetype=city 的实现方式,完成本项目的 @web/src/components/agInput/components/areaSelect.vue 组件。

是的,这里是把原本参考代码中的一个 type 逻辑,单独抽离成独立组件。到目前为止,我们封装的输入类组件已经包括:areaSelectagUploadarrayiconSelectremoteSelect 这五种,它们都属于组件库里没有直接提供、但后台管理系统中又比较常用的场景。像 el-input 这种基础组件就没必要二次封装了。AI 时代里,过度封装带来的理解成本,本质上也是在浪费 token。当然,后续还是会提供一个统一入口的 agInput/index.vue 组件,通过传入 type 直接渲染对应输入框,主要服务于动态表单场景,平常开发并不会强制使用。

写这段 blog 的同时,AI 那边也把组件做完了。组件本身没有太多特殊逻辑,核心就是使用了 el-cascader 来实现省市区三级联动,样式效果就是本文开篇图片里的展示。

组件中还加了一个节点缓存功能,用来缓存已经请求过的地区节点数据。我看到 AI 使用了 reactive 包裹这份缓存数据,但其实完全没必要,因为这部分数据并不会直接参与模板渲染,也不是 computed/watch 的响应式依赖,直接用普通对象就够了,于是让它去掉:

有道理。nodeCache 只做数据暂存,不在模板中渲染,也不作为响应式依赖被 computed/watch 消费,用普通对象即可。同理 lastLazy 也可以简化。

然后 AI 还给绑定值写了一个 set

const selectedValue = computed({get: () => props.modelValue ?? [],set: (val) => emit('update:modelValue', val ?? []),})

但与此同时,它又在 el-cascader 上额外写了 onChange 事件,并在里面再次执行 emit('update:modelValue', val ?? [])。这显然是重复处理了,除非特定场景确实需要额外触发 emit,否则就是多余代码,所以也让它改掉。

今天 AI 的表现确实有点一般。总共没多少行代码,而且基本都是前端逻辑,结果还是频繁出小问题。

增加重置表单的公共函数

这部分本身并不复杂,主要是记录一个容易忽略但很实用的细节:表单的初始值,也就是“重置后恢复到的值”,是通过 formRef.value.setInitialValues() 来设置的;如果没有手动设置,那么系统会将表单第一次渲染时的绑定值,默认作为初始值。

/** * el-form 表单重置 * @param formEl */export const resetForm = (formEl?: FormInstance | null) => {// resetFields 对该表单项进行重置,将其值重置为初始值并移除校验结果typeof formEl?.resetFields == 'function' && formEl.resetFields()}

来源:https://juejin.cn/post/7670736047493070874
上一篇Computer Use离线内网部署与AI自愈元素EXE打包RPA方案 下一篇浏览器端多语言音色迁移实践:OpenVoice V2 ONNX与WebGPU部署
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
CAD零基础入门教程:坐标输入、图层管理与基础绘图命令
AI教程 · 2026-09-01

CAD零基础入门教程:坐标输入、图层管理与基础绘图命令

本文面向CAD零基础学习者,系统讲解坐标输入、图层管理与基础绘图命令的核心用法。通过分步实操与常见问题排查,帮助新手建立精确绘图习惯,掌握规范出图的基础能力。

CAD从入门到项目交付:绘图、标注、图块与实战工作流
AI教程 · 2026-09-01

CAD从入门到项目交付:绘图、标注、图块与实战工作流

掌握CAD的核心在于建立“画得准、标得清、复用快、交付稳”的工作流。本文提供从环境设置、高频命令组合、标注规范、图块标准化到项目分阶段交付的完整路径,帮助初学者避免常见返工陷阱,独立完成可检查、可复用、可打印的工程图纸。

Claude Code 登录指南:个人、Teams 与企业账号区分与授权步骤
AI教程 · 2026-09-01

Claude Code 登录指南:个人、Teams 与企业账号区分与授权步骤

本文详细解析 Claude Code 登录前的账号类型区分方法,涵盖个人订阅、Teams 席位与企业 Enterprise 席位的授权路径差异。提供终端登录命令、环境变量排查及常见异常处理步骤,帮助用户快速完成正确授权并避免登录路径混淆。

Claude Code 文件修改前的权限模式配置与命令审批指南
AI教程 · 2026-09-01

Claude Code 文件修改前的权限模式配置与命令审批指南

本文详细介绍Claude Code在修改文件前的权限模式配置方法,包括defaultMode可选值、permissions allow与deny规则设置、多层级配置文件管理以及 status验证技巧,帮助开发者安全高效地使用AI编程助手。

Claude Code接入VS Code后先测扩展和终端命令
AI教程 · 2026-09-01

Claude Code接入VS Code后先测扩展和终端命令

在VS Code中接入Claude Code后,建议优先验证扩展面板与集成终端两条入口。本文提供标准检查顺序、关键命令与常见故障排查路径,帮助你快速确认环境就绪,避免后续开发受阻。