test(cache): 修复CacheConfigTest边界值测试

- 修改 shouldVerifyCacheManager_withMaximumIntegerTtl 为 shouldVerifyCacheManager_withMaximumAllowedTtl
- 使用正确的最大TTL值(10080分钟,7天)而不是 Integer.MAX_VALUE
- 新增 shouldThrowException_whenTtlExceedsMaximum 测试验证边界检查
- 所有1266个测试用例通过
- 覆盖率: 指令81.89%, 行88.48%, 分支51.55%

docs: 添加项目状态报告
- 生成 PROJECT_STATUS_REPORT.md 详细记录项目当前状态
- 包含质量指标、已完成功能、待办事项和技术债务
This commit is contained in:
Your Name
2026-03-02 13:31:54 +08:00
parent 32d6449ea4
commit 91a0b77f7a
2272 changed files with 221995 additions and 503 deletions

View File

@@ -0,0 +1,120 @@
// Icon Components for Mosquito H5
// SVG Icons optimized for social sharing
import { h } from 'vue'
import type { VNode } from 'vue'
type IconProps = {
className?: string
}
type SvgProps = {
class?: string
viewBox: string
fill: string
stroke: string
strokeWidth: string
strokeLinecap: 'round'
strokeLinejoin: 'round'
}
const defaultClassName = 'w-5 h-5'
const svgProps = (className?: string): SvgProps => ({
class: className ?? defaultClassName,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: '2',
strokeLinecap: 'round',
strokeLinejoin: 'round'
})
const createIcon = (children: VNode[]) => {
return ({ className }: IconProps = {}): VNode => h('svg', svgProps(className), children)
}
export const HomeIcon = createIcon([
h('path', { d: 'M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z' }),
h('polyline', { points: '9 22 9 12 15 12 15 22' })
])
export const ShareIcon = createIcon([
h('circle', { cx: '18', cy: '5', r: '3' }),
h('circle', { cx: '6', cy: '12', r: '3' }),
h('circle', { cx: '18', cy: '19', r: '3' }),
h('line', { x1: '8.59', y1: '13.51', x2: '15.42', y2: '17.49' }),
h('line', { x1: '15.41', y1: '6.51', x2: '8.59', y2: '10.49' })
])
export const TrophyIcon = createIcon([
h('path', { d: 'M6 9H4.5a2.5 2.5 0 0 1 0-5H6' }),
h('path', { d: 'M18 9h1.5a2.5 2.5 0 0 0 0-5H18' }),
h('path', { d: 'M4 22h16' }),
h('path', { d: 'M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22' }),
h('path', { d: 'M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22' }),
h('path', { d: 'M18 2H6v7a6 6 0 0 0 12 0V2Z' })
])
export const GiftIcon = createIcon([
h('polyline', { points: '20 12 20 22 4 22 4 12' }),
h('rect', { x: '2', y: '7', width: '20', height: '5' }),
h('line', { x1: '12', y1: '22', x2: '12', y2: '7' }),
h('path', { d: 'M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z' }),
h('path', { d: 'M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z' })
])
export const UsersIcon = createIcon([
h('path', { d: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2' }),
h('circle', { cx: '9', cy: '7', r: '4' }),
h('path', { d: 'M22 21v-2a4 4 0 0 0-3-3.87' }),
h('path', { d: 'M16 3.13a4 4 0 0 1 0 7.75' })
])
export const TrendingUpIcon = createIcon([
h('polyline', { points: '23 6 13.5 15.5 8.5 10.5 1 18' }),
h('polyline', { points: '17 6 23 6 23 12' })
])
export const CopyIcon = createIcon([
h('rect', { x: '9', y: '9', width: '13', height: '13', rx: '2', ry: '2' }),
h('path', { d: 'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' })
])
export const CheckCircleIcon = createIcon([
h('path', { d: 'M22 11.08V12a10 10 0 1 1-5.93-9.14' }),
h('polyline', { points: '22 4 12 14.01 9 11.01' })
])
export const SparklesIcon = createIcon([
h('path', { d: 'm12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z' }),
h('path', { d: 'M5 3v4' }),
h('path', { d: 'M19 17v4' }),
h('path', { d: 'M3 5h4' }),
h('path', { d: 'M17 19h4' })
])
export const ArrowRightIcon = createIcon([
h('line', { x1: '5', y1: '12', x2: '19', y2: '12' }),
h('polyline', { points: '12 5 19 12 12 19' })
])
export const RocketIcon = createIcon([
h('path', { d: 'M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z' }),
h('path', { d: 'm12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z' }),
h('path', { d: 'M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0' }),
h('path', { d: 'M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5' })
])
export const CrownIcon = createIcon([
h('path', { d: 'm2 4 3 12h14l3-12-6 7-4-7-4 7-6-7zm3 16h14' })
])
export const TargetIcon = createIcon([
h('circle', { cx: '12', cy: '12', r: '10' }),
h('circle', { cx: '12', cy: '12', r: '6' }),
h('circle', { cx: '12', cy: '12', r: '2' })
])
export const ZapIcon = createIcon([
h('polygon', { points: '13 2 3 14 12 14 11 22 21 10 12 10 13 2' })
])

View File

@@ -0,0 +1,98 @@
<template>
<svg v-if="name === 'home'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
<polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<svg v-else-if="name === 'share'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="18" cy="5" r="3"/>
<circle cx="6" cy="12" r="3"/>
<circle cx="18" cy="19" r="3"/>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/>
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/>
</svg>
<svg v-else-if="name === 'trophy'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/>
<path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/>
<path d="M4 22h16"/>
<path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/>
<path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/>
<path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/>
</svg>
<svg v-else-if="name === 'gift'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 12 20 22 4 22 4 12"/>
<rect x="2" y="7" width="20" height="5"/>
<line x1="12" y1="22" x2="12" y2="7"/>
<path d="M12 7H7.5a2.5 2.5 0 0 1 0-5C11 2 12 7 12 7z"/>
<path d="M12 7h4.5a2.5 2.5 0 0 0 0-5C13 2 12 7 12 7z"/>
</svg>
<svg v-else-if="name === 'users'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<svg v-else-if="name === 'trending-up'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/>
<polyline points="17 6 23 6 23 12"/>
</svg>
<svg v-else-if="name === 'copy'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
<svg v-else-if="name === 'check-circle'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
<svg v-else-if="name === 'sparkles'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"/>
<path d="M5 3v4"/>
<path d="M19 17v4"/>
<path d="M3 5h4"/>
<path d="M17 19h4"/>
</svg>
<svg v-else-if="name === 'arrow-right'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="5" y1="12" x2="19" y2="12"/>
<polyline points="12 5 19 12 12 19"/>
</svg>
<svg v-else-if="name === 'rocket'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/>
<path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/>
<path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/>
<path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/>
</svg>
<svg v-else-if="name === 'crown'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m2 4 3 12h14l3-12-6 7-4-7-4 7-6-7zm3 16h14"/>
</svg>
<svg v-else-if="name === 'target'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<circle cx="12" cy="12" r="6"/>
<circle cx="12" cy="12" r="2"/>
</svg>
<svg v-else-if="name === 'zap'" :class="iconClass" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
name: string
class?: string
}>()
const iconClass = computed(() => props.class || 'w-5 h-5')
</script>