diff --git a/.env.dev b/.env.dev index 32ce03b..b31749e 100644 --- a/.env.dev +++ b/.env.dev @@ -1,11 +1,17 @@ # 开发环境 (dev):仅 vite dev --mode dev 加载;build 产物不读任何 .env.* # (.env.base/.env.ld/.env.prod 已删,线上由 /api/env-config?target=front 运行时下发)。 # ⚠️ VITE_* 仅本地开发生效。 -# API 走 /api 同源相对路径(vite proxy 转发到本地后端 8101), -# 规避后端 CAS 过滤器不回 CORS 头导致的跨域拦截;SSO/基础平台用真实环境 +# API 走 /api 同源相对路径(vite proxy 转发到本地后端 8102,见 vite.config.ts), +# 规避后端 CAS 过滤器不回 CORS 头导致的跨域拦截;SSO/基础平台用真实环境。 +# VITE_SERVICE_HOST 必须留空:host.config 的 applyConf 跳过空值 → 回落同源兜底(本地路径无上下文段 → ""); +# 填远程地址会绕过本地后端直连测试环境(临时联调远程时才改回) +# 主题通道(A 类免插件接入 §2):index.html 的 loader 与 vite.config.ts 的 /static 代理已就位, +# 本地 dev 的 /static/** 由代理兜到线上通道;联调本地通道源时用环境变量覆盖代理目标: +# YH_THEME_PROXY_TARGET=http://localhost:9527 npm run dev + VITE_BASE_HOST=http://base.yunhaixingtong.com VITE_SSO_HOST=http://sso.yunhaixingtong.com -VITE_SERVICE_HOST=http://base.yunhaixingtong.com/campushomework/ +VITE_SERVICE_HOST=http://base.yunhaixingtong.com/coursehomework VITE_ZIYUANKU_HOST=https://base.bestsch.com/BschZyk VITE_ZHUANXIANG_HOST=https://base.bestsch.com/BschZncpd VITE_IS_MOCK=false diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index cea668b..bacd929 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -19,7 +19,10 @@ jobs: options: --network infra-infra-net steps: - name: 安装 git / curl / zip(alpine) - run: apk add --no-cache git curl zip + run: | + # 统一走 aliyun 源:dl-cdn 时段性被拦会卡满 60s×2(2026-10-20 事故) + sed -i 's#dl-cdn.alpinelinux.org#mirrors.aliyun.com#g' /etc/apk/repositories + apk add --no-cache git curl zip # 内网 Gitea 无法访问 GitHub 拉 actions/checkout,手动 clone 本仓库 - name: 拉取源码(内网无 GitHub,手动 clone 本仓库) @@ -38,30 +41,36 @@ jobs: - name: 构建前端(node 容器) run: | set -e - docker rm -f frontbuild 2>/dev/null || true - docker run -d --name frontbuild -w /build node:20 sleep 3600 - docker cp "${PWD}/." frontbuild:/build/ - docker exec frontbuild sh -c ' + # 构建容器名必须全局唯一:runner 挂的是宿主 docker.sock,容器名在整个 daemon 上共享 + # 命名空间。固定名会在多仓/多条 workflow 并发时互相 docker rm -f 掉对方正在构建的 + # 容器,表现为无编译报错的 exit 137(SIGKILL,2026-10-21 实测复现)。 + # GITHUB_RUN_ID 实例级唯一,再拼时间戳兜底。 + BUILD_CONTAINER="frontbuild-${GITHUB_RUN_ID:-0}-$(date +%s)" + echo "BUILD_CONTAINER=${BUILD_CONTAINER}" + docker rm -f "$BUILD_CONTAINER" 2>/dev/null || true + docker run -d --name "$BUILD_CONTAINER" -w /build node:20 sleep 3600 + docker cp "${PWD}/." "$BUILD_CONTAINER":/build/ + docker exec "$BUILD_CONTAINER" sh -c ' set -e cd /build if [ -f .npmrc ]; then sed -i "/SASS_BINARY_PATH/d" .npmrc; fi + # 国内镜像源:内网直连 registry.npmjs.org 跨境极慢(实测 npm install 12 分 46 秒 / 754 包) + npm config set registry https://registry.npmmirror.com npm ci npm run build ' echo "=== dist 产物 ===" - docker exec frontbuild sh -c 'ls -la /build/dist/ | head -20' + docker exec "$BUILD_CONTAINER" sh -c 'ls -la /build/dist/ | head -20' # 从容器 cp dist 到宿主工作目录 - docker cp frontbuild:/build/dist ./dist - docker rm -f frontbuild + docker cp "$BUILD_CONTAINER":/build/dist ./dist + docker rm -f "$BUILD_CONTAINER" echo "BUILD CHECK OK" - # 打包 dist → zip(vite outDir 已简化为直出 dist/,无中间层;进入 dist 打包, - # zip 根目录直接是 index.html/css/js。此前 outDir=dist/base 时曾误打 dist/ 整层, - # zip 根只有 base/ 目录,projman 前端发布校验报「zip 根目录缺少 html 文件」) + # 打包 dist → zip(进入 dist 目录打包,zip 根目录直接是 html/css/js 文件) - name: 打包产物 run: | TAG=$(echo "$GITHUB_SHA" | cut -c1-8) - ZIP_FILE="notice-front-${TAG}.zip" + ZIP_FILE="coursehomework-front-${TAG}.zip" cd dist && zip -r "../${ZIP_FILE}" . && cd .. echo "ZIP_FILE=${ZIP_FILE}" >> "$GITHUB_ENV" echo "TAG=${TAG}" >> "$GITHUB_ENV" @@ -73,7 +82,9 @@ jobs: NEXUS_USER: ${{ secrets.NEXUS_USER }} NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} run: | + set -e NEXUS_URL="http://nexus.yunhaixingtong.com:8081/repository/front-hosted/${ZIP_FILE}" + # -f:HTTP >=400 时 curl 以非零退出,仓库不存在/认证失败必须让 job 变红,否则建档的是不存在的 URL curl -sSf -X PUT \ -u "${NEXUS_USER}:${NEXUS_PASSWORD}" \ --upload-file "${ZIP_FILE}" \ @@ -84,7 +95,8 @@ jobs: # 通知 projman:webhook 收到后建档(type=front, status=pending),部署由用户在「前端发布」Tab 手动触发 - name: 通知 projman 建档 run: | + set -e curl -sSf -X POST "http://192.168.10.160:8090/projman/api/deploy/webhook" \ -H "Content-Type: application/json" \ -H "X-Deploy-Token: ${{ secrets.DEPLOY_TOKEN }}" \ - -d "{\"app\":\"notice\",\"front\":\"front\",\"tag\":\"${TAG}\",\"sha\":\"${GITHUB_SHA}\",\"message\":\"${COMMIT_MSG}\",\"nexusUrl\":\"${NEXUS_URL}\"}" + -d "{\"app\":\"coursehomework\",\"front\":\"front\",\"tag\":\"${TAG}\",\"sha\":\"${GITHUB_SHA}\",\"message\":\"${COMMIT_MSG}\",\"nexusUrl\":\"${NEXUS_URL}\"}" diff --git a/.gitignore b/.gitignore index 6ccf44d..6eef18f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,10 @@ yarn.lock # 改动前本地备份(版本迭代时人工留存,不进版本库) .backup/ + +# 备份 / 临时文件(旧版图标集 icons.css.bak 等不入库) +*.bak +*.orig + +# AI 工作目录(记忆/技能,不是缓存,勿删,但不入库) +.workbuddy/ diff --git a/bug检测与修复.md b/bug检测与修复.md index 69360d8..a66b683 100644 --- a/bug检测与修复.md +++ b/bug检测与修复.md @@ -73,17 +73,19 @@ | B-03 | `HomeworkStatisticsVo` 前端声明 5 个幻影字段,后端从未返回 → 统计页 4 张卡片恒为 0/0%/空表 | **P0** | `/stats` 作业统计 | 已修复(前端降级)+ 后端补字段 | | B-04 | `HomeworkVo` 前端声明 `progress` 字段,后端从未返回 → 「全部作业」页 3 列进度恒为「—」 | **P0** | `/homeworklist` 全部作业 | 已修复(前端降级)+ 后端补字段 | | B-05 | `HomeworkDetailVo` 前端声明 `receiveText`,后端从未返回 → 详情页「接收班级」恒显示「全部班级」 | **P1** | `/homeworklist/detail` | 已修复(后端补字段 + 前端兜底) | -| B-06 | `TeacherHomeworks.vue` 4 个行操作函数重复声明 | **P1** | `/list` 我布置的 | 已修复 | -| B-07 | `TeacherHomeworks.vue` `moreActions` Map 每次重渲染累积、永不回收 | **P1** | `/list` 我布置的 | 已修复 | +| ~~B-06~~ | ~~`TeacherHomeworks.vue` 4 个行操作函数重复声明~~ | — | `/list` 我布置的 | **误报已撤回**(见 §6) | +| ~~B-07~~ | ~~`TeacherHomeworks.vue` `moreActions` Map 每次重渲染累积~~ | — | `/list` 我布置的 | **误报已撤回**(见 §6) | | B-08 | `NewHomework.vue` 编辑回显与班级树加载存在竞态,导致「全部班级」勾选态误判 | **P1** | `/list/new` 发作业 | 已修复 | | B-09 | `src/api/index.ts` 引用未定义的 `GlobalFetch()`,且 baseURL 硬编码远程域名 | **P2** | 潜在全局 auto-import 污染 | 已修复 | -| B-10 | 7 个死组件 + 1 个 `index copy.vue` 残留,`auto-import` 扫描目录存在误引入风险 | **P2** | 构建体积/可维护性 | 已记录(不删除) | +| B-10 | 死组件/死文件残留(`index copy.vue`、`alova-vant.ts` 等),`auto-import` 扫描目录存在误引入风险 | **P2** | 构建体积/可维护性 | 已记录(不删除) | | B-11 | `.backup/` 未纳入 `.gitignore`,污染 `git status` | **P2** | 版本管理 | 已修复 | | B-12 | `routes.ts` 出现仅换行符差异的伪改动 | **P2** | 版本管理噪音 | 已记录 | | B-13 | `baseApi.setRole` 指向后端不存在的 `/api/base/SetRole`,真实环境每次跨角色路由切换都会 404 | **P2** | 控制台噪音 | 已记录(设计如此) | -| B-14 | `vue-tsc` 在 Node 24 下崩溃(`Search string not found: "/supportedTSExtensions = .*(?=;)/"`),类型门禁实际失效 | **P1** | 全部 TS 代码 | 已记录(需换 Node 18/20 或升级 vue-tsc) | -| C-01 | 生产构建通过(39.66s,exit 0) | — | — | 通过 | -| C-02 | TS 类型检查**无法执行**(见 B-14) | — | — | 阻塞 | +| B-14 | `vue-tsc` 崩溃(`Search string not found: "/supportedTSExtensions = .*(?=;)/"`),类型门禁实际失效 | **P1** | 全部 TS 代码 | 已定位真因:TS 5.9.3 ↔ vue-tsc 1.8.27 版本不兼容(**与 Node 无关**) | +| **B-15** | **API 层全链路无类型**:`new Method()` 泛型误用(`Method` 的泛型实为 AlovaGenerics)→ `send()` 退化 `unknown` | **P0(根因)** | 全部接口调用 | 已修复(4 个 api 模块) | +| C-01 | 生产构建通过(~40s,exit 0) | — | — | 通过 | +| C-02 | TS 类型检查(临时降级 TS 5.2.2 后执行) | — | — | 通过(课程作业模块 0 错误) | +| C-06 | 后端编译 `mvn -o -q compile` | — | — | 通过 | | C-05~C-07 | V2 端点 28 个 + 通知 3 个 + V1 冻结端点路径/动词与后端一致 | — | — | 通过 | | C-08/C-09 | `BasePageResult` 六字段、`pageIndex` 从 1 起前后端一致 | — | — | 通过 | | C-10~C-14 | V2 作业/学生/矩阵/版本/通知 VO 字段与后端逐一对应 | — | — | 通过 | @@ -92,6 +94,8 @@ **最严重的三条(P0)本质是同一个病根**:前端契约(`types/*.ts`)比后端实际返回**多声明的字段**,被 TypeScript 视为可选(`?:`),又被 `vue-tsc` 崩溃掩盖,于是「编译通过、构建成功、mock 模式下一切正常」——**只有连真实后端才会表现为静默的空值/功能失效**。mock(`homeworkapi.ts`)为了让页面「跑得起来」,主动补齐了这些后端并不存在的字段,进一步掩盖了问题。 +而**这一切之所以能长期逃逸,根因是 B-15**:API 层用 `new Method()` 传错了泛型(`Method` 的泛型实为 `AlovaGenerics`),使 `send()` 退化为 `unknown`,所有 `res.xxx` 字段访问都失去类型检查。修复 B-15 后(`vue-tsc` 错误 162 → 78、课程作业模块清零),同类问题即可在编译期被拦截。 + --- ## 2. 缺陷详情与修复方案 @@ -197,16 +201,22 @@ --- -### B-06 / B-07 【P1】`TeacherHomeworks.vue` 重复声明与无界缓存 +### ~~B-06 / B-07~~ 【误报,已撤回】`TeacherHomeworks.vue` 重复声明与无界缓存 -**证据链** +> ⚠️ **本项为初稿误报,实际不存在,无需修复。** 保留原文仅作记录,复核结论见 §6。 -- `viewDetail / viewSubmissions / toGrade / edit` 四个函数在 ` + + <%- title %> diff --git a/package.json b/package.json index f324a24..d22b223 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "pdfjs-dist": "^4.10.38", "pinia": "^2.1.4", "sass": "^1.64.1", - "view-ui-plus": "^1.3.16", + "view-ui-plus": "1.3.24", "vite-plugin-mock": "2.9.6", "vue": "^3.4.19", "vue-router": "4", diff --git a/src/App.vue b/src/App.vue index d0515dd..cd638f1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,14 +1,36 @@ @@ -106,48 +228,73 @@ onMounted(async () => {