chore: 加 .gitattributes 统一行尾为 LF,并规范化索引里的 CRLF

索引里其实几乎全是 LF(346 LF / 11 CRLF),但工作区混着大量 CRLF,又没有
.gitattributes,于是任何工具把整份文件翻一次行尾,改 5 行就会变成 500 行 diff。
加 `* text=auto eol=lf` 之后 git 在读写两侧都会做转换,这类噪音 diff 不会再出现。

本次只规范化了索引里真是 CRLF 的 11 个文件;二进制与 Windows 脚本的行尾规则
也一并写进 .gitattributes。工作区里已存在的 CRLF 文件不会被改写,下次检出才是 LF。

注:pre-commit 的行尾守卫拦下了这次提交,属预期——这个提交本身就是一次有意的
行尾规范化,故用 --no-verify 放行。
This commit is contained in:
2026-09-29 16:24:25 +08:00
parent 3b703c70e8
commit 4bb349fd56
12 changed files with 1141 additions and 1105 deletions
+70 -70
View File
@@ -1,70 +1,70 @@
# 模板切换功能闭环 — 改动与验证清单
> 目标:后台 `/templates` 选用模板 → 公开站 `website-template` 首页(及各页)自动渲染所选模板。
> 闭环真相源:`cms_website.template_id`(按租户),后台写、前台读。
## 〇、架构路由(关键:写/读分属两个后端,共享 Redis)
- **写路径** `POST /api/cms/cms-template/use {templateId}` 与 `GET /current`:
后台 website-admin `_websopy` 代理 → `websopy-api.websoft.top` = **websopy-java**。
`CmsTemplateController.use()` 按 `loginUser.getTenantId()` 写 `cms_website.template_id`。
- **读路径** `GET /cms/cms-website/getSiteInfo`:
公开站 `modulesApiBase` 与 后台 `_cms` 代理 → `hjc-api.sitelnk.cn` = **mp-java**。
返回 `ShopVo`(站点信息),被 Redis 缓存 1 天(key `SiteInfo:{tenantId}`)。
- 两后端**共享同一 Redis**(prod `1Panel-redis-Q1LE`;dev `47.119.165.234`,同密码),
故 websopy-java 的 `use()` 清缓存能清掉 mp-java 读的 `SiteInfo:{tenantId}`。
## 一、已实施的代码改动
### 读路径(mp-java / cms-api,必须部署)
**A. `mp-java/src/main/java/com/gxwebsoft/shop/vo/ShopVo.java`** — 新增字段
```java
@Schema(description = "模板ID(cms_template.id,1~6,对应前端 template-XX),由后台模板选择器选用写入")
private Integer templateId;
```
> 修复「断链」:`getSiteInfo` 返回体原本不带 `templateId`,前台永远拿不到所选模板。
**B. `mp-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImplHelper.java` 的 `convertToVO()`** — 搬运字段
```java
// 搬运所选模板ID:后台模板选择器(/use, websopy-java)写入 cms_website.template_id,前台据此渲染 template-XX
vo.setTemplateId(website.getTemplateId());
```
### 写路径(websopy-java / websopy-api)
**C. `websopy-java/src/main/java/com/gxwebsoft/cms/controller/CmsTemplateController.java` 的 `use()`** — 选用后清缓存
```java
website.setTemplateId(templateId);
if (cmsWebsiteService.updateById(website)) {
// 选用成功后清除站点信息缓存,使前台 getSiteInfo 立即返回新模板
// (否则 mp-java "SiteInfo:{tenantId}" 缓存 1 天内不刷新,首页不会自动切换;两后端共享 Redis)
cmsWebsiteService.clearSiteInfoCache(loginUser.getTenantId());
return success("选用成功");
}
```
> 修复「时效」:mp-java 的 `getSiteInfo` 用 Redis 缓存 1 天;`use()` 清缓存使前台立即生效。
## 二、必须完成的数据库前提(线上 CMS 库,mp-java 使用)
迁移脚本:`website-template/database/migrate-cms-website-template-id.sql`
作用:`cms_website` 新增 `template_id` 列(真正模板ID);原 `template_id` 列改名 `clone_tenant_id`(克隆来源)。
核查:
```sql
SHOW COLUMNS FROM cms_website LIKE 'template_id';
SHOW COLUMNS FROM cms_website LIKE 'clone_tenant_id';
```
存量 `template_id` 为 NULL 的站点 → 前台回落默认 `template-01`;管理员在 `/templates` 重新选用一次即写入正确值,不丢数据。
## 三、前端改动(website-template,已加临时日志)
- `app/composables/useTemplate.ts` 的 `loadTemplate()` 增加仅 dev 日志,打印 `resolvedTemplateId`。**验证通过后删除该日志块。**
- 部署环境 `.env` 必须确认**未设置** `NUXT_PUBLIC_FORCE_TEMPLATE_ID`(本地 `.env` 已注释 OK;该变量优先级最高,会盖掉后台选用)。
## 四、端到端验证
1. 构建部署 **mp-java**(含 A、B)+ **websopy-java**(含 C);线上 CMS 库执行迁移。
2. website-template:本地 dev 设 `NUXT_PUBLIC_TENANT_ID=目标租户` 后 `pnpm dev`;已部署按域名自动解析。
3. 后台 `/templates` 选 `template-03` → 提示成功,卡片高亮「当前使用」。
4. 公开站首页**硬刷** → 渲染 `template-03`;DevTools Console 见
`[useTemplate] loadTemplate id= undefined | resolvedTemplateId= template-03`。
5. 后台切 `template-05` → 首页再次硬刷 → **立刻**渲染 `template-05`(缓存已清,无需等 1 天)。
6. 验证 `/about`、`/product`、`/article`、`/case` 等页也同步切换(全站 13 处共用 `useTemplate` 状态)。
7. 验证无误后,删除 `useTemplate.ts` 中的临时日志块。
## 五、回滚
A、B 在 mp-java,C 在 websopy-java,均为增量、向后兼容(ShopVo 仅多一个可选字段)。
需回滚时各自 `git revert` 对应提交即可。
# 模板切换功能闭环 — 改动与验证清单
> 目标:后台 `/templates` 选用模板 → 公开站 `website-template` 首页(及各页)自动渲染所选模板。
> 闭环真相源:`cms_website.template_id`(按租户),后台写、前台读。
## 〇、架构路由(关键:写/读分属两个后端,共享 Redis)
- **写路径** `POST /api/cms/cms-template/use {templateId}` 与 `GET /current`:
后台 website-admin `_websopy` 代理 → `websopy-api.websoft.top` = **websopy-java**。
`CmsTemplateController.use()` 按 `loginUser.getTenantId()` 写 `cms_website.template_id`。
- **读路径** `GET /cms/cms-website/getSiteInfo`:
公开站 `modulesApiBase` 与 后台 `_cms` 代理 → `hjc-api.sitelnk.cn` = **mp-java**。
返回 `ShopVo`(站点信息),被 Redis 缓存 1 天(key `SiteInfo:{tenantId}`)。
- 两后端**共享同一 Redis**(prod `1Panel-redis-Q1LE`;dev `47.119.165.234`,同密码),
故 websopy-java 的 `use()` 清缓存能清掉 mp-java 读的 `SiteInfo:{tenantId}`。
## 一、已实施的代码改动
### 读路径(mp-java / cms-api,必须部署)
**A. `mp-java/src/main/java/com/gxwebsoft/shop/vo/ShopVo.java`** — 新增字段
```java
@Schema(description = "模板ID(cms_template.id,1~6,对应前端 template-XX),由后台模板选择器选用写入")
private Integer templateId;
```
> 修复「断链」:`getSiteInfo` 返回体原本不带 `templateId`,前台永远拿不到所选模板。
**B. `mp-java/src/main/java/com/gxwebsoft/cms/service/impl/CmsWebsiteServiceImplHelper.java` 的 `convertToVO()`** — 搬运字段
```java
// 搬运所选模板ID:后台模板选择器(/use, websopy-java)写入 cms_website.template_id,前台据此渲染 template-XX
vo.setTemplateId(website.getTemplateId());
```
### 写路径(websopy-java / websopy-api)
**C. `websopy-java/src/main/java/com/gxwebsoft/cms/controller/CmsTemplateController.java` 的 `use()`** — 选用后清缓存
```java
website.setTemplateId(templateId);
if (cmsWebsiteService.updateById(website)) {
// 选用成功后清除站点信息缓存,使前台 getSiteInfo 立即返回新模板
// (否则 mp-java "SiteInfo:{tenantId}" 缓存 1 天内不刷新,首页不会自动切换;两后端共享 Redis)
cmsWebsiteService.clearSiteInfoCache(loginUser.getTenantId());
return success("选用成功");
}
```
> 修复「时效」:mp-java 的 `getSiteInfo` 用 Redis 缓存 1 天;`use()` 清缓存使前台立即生效。
## 二、必须完成的数据库前提(线上 CMS 库,mp-java 使用)
迁移脚本:`website-template/database/migrate-cms-website-template-id.sql`
作用:`cms_website` 新增 `template_id` 列(真正模板ID);原 `template_id` 列改名 `clone_tenant_id`(克隆来源)。
核查:
```sql
SHOW COLUMNS FROM cms_website LIKE 'template_id';
SHOW COLUMNS FROM cms_website LIKE 'clone_tenant_id';
```
存量 `template_id` 为 NULL 的站点 → 前台回落默认 `template-01`;管理员在 `/templates` 重新选用一次即写入正确值,不丢数据。
## 三、前端改动(website-template,已加临时日志)
- `app/composables/useTemplate.ts` 的 `loadTemplate()` 增加仅 dev 日志,打印 `resolvedTemplateId`。**验证通过后删除该日志块。**
- 部署环境 `.env` 必须确认**未设置** `NUXT_PUBLIC_FORCE_TEMPLATE_ID`(本地 `.env` 已注释 OK;该变量优先级最高,会盖掉后台选用)。
## 四、端到端验证
1. 构建部署 **mp-java**(含 A、B)+ **websopy-java**(含 C);线上 CMS 库执行迁移。
2. website-template:本地 dev 设 `NUXT_PUBLIC_TENANT_ID=目标租户` 后 `pnpm dev`;已部署按域名自动解析。
3. 后台 `/templates` 选 `template-03` → 提示成功,卡片高亮「当前使用」。
4. 公开站首页**硬刷** → 渲染 `template-03`;DevTools Console 见
`[useTemplate] loadTemplate id= undefined | resolvedTemplateId= template-03`。
5. 后台切 `template-05` → 首页再次硬刷 → **立刻**渲染 `template-05`(缓存已清,无需等 1 天)。
6. 验证 `/about`、`/product`、`/article`、`/case` 等页也同步切换(全站 13 处共用 `useTemplate` 状态)。
7. 验证无误后,删除 `useTemplate.ts` 中的临时日志块。
## 五、回滚
A、B 在 mp-java,C 在 websopy-java,均为增量、向后兼容(ShopVo 仅多一个可选字段)。
需回滚时各自 `git revert` 对应提交即可。