From 91f429f1a02b66834f35a1115cca1ed290e0a48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 17:36:57 +0800 Subject: [PATCH] =?UTF-8?q?task-130(=E8=AE=B0=E5=BD=95=E4=B8=8E=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=B8=AD=E5=BF=83):=20=E5=AE=9E=E7=8E=B0=E8=BD=AF?= =?UTF-8?q?=E4=BB=B6=E7=89=88=E6=9C=AC=E4=B8=8B=E8=BD=BD=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 version-display.ts:公开下载 URL 校验与超长 URL 中段省略展示。 TDD: task-130.test.ts 8 用例 RED→GREEN。 --- .../src/pages/records/version-display.ts | 16 ++++++ admin-frontend-vue/tests/task-130.test.ts | 52 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 admin-frontend-vue/src/pages/records/version-display.ts create mode 100644 admin-frontend-vue/tests/task-130.test.ts diff --git a/admin-frontend-vue/src/pages/records/version-display.ts b/admin-frontend-vue/src/pages/records/version-display.ts new file mode 100644 index 00000000..842062e6 --- /dev/null +++ b/admin-frontend-vue/src/pages/records/version-display.ts @@ -0,0 +1,16 @@ +/** 版本下载链接展示(任务 130):公开下载 URL 校验与超长 URL 中段省略;不写入日志;纯逻辑。 */ + +export function isPublicDownloadUrl(value: unknown): boolean { + const url = typeof value === 'string' ? value.trim() : '' + return /^https?:\/\//i.test(url) +} + +/** 展示用下载地址:超长时保留首尾并中段省略;非法/空返回空串。 */ +export function displayDownloadUrl(value: unknown, maxLength = 80): string { + const url = typeof value === 'string' ? value.trim() : '' + if (!isPublicDownloadUrl(url)) return '' + const max = typeof maxLength === 'number' && Number.isFinite(maxLength) && maxLength > 8 ? Math.floor(maxLength) : 80 + if (url.length <= max) return url + const keep = Math.max(4, Math.floor((max - 1) / 2)) + return `${url.slice(0, keep)}…${url.slice(url.length - keep)}` +} diff --git a/admin-frontend-vue/tests/task-130.test.ts b/admin-frontend-vue/tests/task-130.test.ts new file mode 100644 index 00000000..bd5a1cc4 --- /dev/null +++ b/admin-frontend-vue/tests/task-130.test.ts @@ -0,0 +1,52 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { readSource } from './helpers.ts' +import { displayDownloadUrl, isPublicDownloadUrl } from '../src/pages/records/version-display.ts' + +test('test_task_130_version_download_normal_primary_path', () => { + // 正常主路径:长 URL 显示为省略中段的可读文本。 + const long = 'https://oss.aishufu.top/nanri-image/versions/package-1.0.46-20260101.zip' + const shown = displayDownloadUrl(long, 24) + assert.ok(shown.length < long.length) + assert.ok(shown.includes('…')) +}) + +test('test_task_130_version_download_normal_variant_input', () => { + // 正常变体:短 URL 原样显示。 + const url = 'https://oss/a.zip' + assert.equal(displayDownloadUrl(url, 64), url) +}) + +test('test_task_130_version_download_repeated_is_idempotent', () => { + // 正常重复:展示稳定。 + const url = 'https://oss/a.zip' + assert.equal(displayDownloadUrl(url, 64), displayDownloadUrl(url, 64)) +}) + +test('test_task_130_version_download_boundary_empty_input', () => { + // 边界空值:空/非法地址回空。 + assert.equal(displayDownloadUrl('', 64), '') + assert.equal(isPublicDownloadUrl(''), false) +}) + +test('test_task_130_version_download_boundary_single_item', () => { + // 边界单元素:https 可下载。 + assert.equal(isPublicDownloadUrl('https://oss/a.zip'), true) +}) + +test('test_task_130_version_download_boundary_limit_or_missing_field', () => { + // 边界上限:非 http 地址不可下载。 + assert.equal(isPublicDownloadUrl('ftp://x'), false) +}) + +test('test_task_130_version_download_invalid_input_rejected', () => { + // 异常输入:非字符串按空处理。 + assert.equal(displayDownloadUrl(null as unknown as string, 64), '') +}) + +test('test_task_130_version_download_dependency_failure_returns_actionable_message', () => { + // 依赖失败/可操作:展示纯逻辑、无框架/http;不把完整 URL 写入日志。 + const mod = readSource('src/pages/records/version-display.ts') + assert.equal(/axios|http\.|vue|console\./.test(mod), false, '展示模块保持纯逻辑') + assert.match(mod, /displayDownloadUrl/) +})