chore: 清理旧测试基础设施与废弃文件

- 移除 everything-is-suitable-test/ 旧测试框架
- 移除根目录 test-automation/、test-data-manager/、test-monitoring/
- 移除根目录 scripts/ 旧部署/测试脚本
- 移除 everything-is-suitable-uniapp/src/utils/httpClient.ts、tokenManager.ts
- 移除根目录旧配置文件(jest.config.js、package.json、tsconfig.json 等)
- 移除临时测试文件(test-*.ts、test-*.html、playwright-diagnose-*.js)
This commit is contained in:
张翔
2026-04-29 21:18:21 +08:00
parent a39b4388f3
commit 039fbe4f4c
1545 changed files with 2 additions and 223201 deletions
@@ -1,195 +0,0 @@
import appConfig from '../../config'
import type { ApiResult } from '../types/api'
export enum ErrorType {
NETWORK_ERROR = 'NETWORK_ERROR',
TIMEOUT_ERROR = 'TIMEOUT_ERROR',
BUSINESS_ERROR = 'BUSINESS_ERROR',
AUTH_ERROR = 'AUTH_ERROR',
TOKEN_EXPIRED = 'TOKEN_EXPIRED',
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}
export interface ApiError {
type: ErrorType
code: number
message: string
detail?: any
}
export interface RequestConfig {
url: string
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
data?: any
params?: any
headers?: Record<string, string>
timeout?: number
needAuth?: boolean
}
class HttpClient {
private baseURL: string
private defaultTimeout: number = 10000
private tokenKey: string = 'auth_token'
constructor() {
this.baseURL = appConfig.baseURL
}
async request<T>(config: RequestConfig): Promise<ApiResult<T>> {
const { url, method, data, params, headers = {}, timeout = this.defaultTimeout, needAuth = true } = config
const requestUrl = this.buildUrl(url, params)
const requestHeaders = this.buildHeaders(headers, needAuth)
return new Promise((resolve, reject) => {
uni.request({
url: requestUrl,
method,
data,
header: requestHeaders,
timeout,
success: (response: any) => {
try {
const result = this.handleResponse<T>(response)
resolve(result)
} catch (error) {
reject(error)
}
},
fail: (error: any) => {
reject(this.handleError(error))
}
})
})
}
async get<T>(url: string, params?: any, options?: { needAuth?: boolean }): Promise<ApiResult<T>> {
return this.request<T>({ url, method: 'GET', params, ...options })
}
async post<T>(url: string, data?: any, options?: { needAuth?: boolean }): Promise<ApiResult<T>> {
return this.request<T>({ url, method: 'POST', data, ...options })
}
async put<T>(url: string, data?: any, options?: { needAuth?: boolean }): Promise<ApiResult<T>> {
return this.request<T>({ url, method: 'PUT', data, ...options })
}
async delete<T>(url: string, params?: any, options?: { needAuth?: boolean }): Promise<ApiResult<T>> {
return this.request<T>({ url, method: 'DELETE', params, ...options })
}
private buildUrl(url: string, params?: any): string {
let fullUrl = url.startsWith('http') ? url : `${this.baseURL}${url}`
if (params) {
const queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join('&')
fullUrl += `?${queryString}`
}
return fullUrl
}
private buildHeaders(headers: Record<string, string>, needAuth: boolean): Record<string, string> {
const requestHeaders: Record<string, string> = {
'Content-Type': 'application/json',
...headers
}
if (needAuth) {
const token = this.getToken()
if (token) {
requestHeaders['Authorization'] = `Bearer ${token}`
}
}
return requestHeaders
}
private handleResponse<T>(response: any): ApiResult<T> {
const { statusCode, data } = response
if (statusCode === 200) {
return data as ApiResult<T>
} else if (statusCode === 401) {
throw {
type: ErrorType.AUTH_ERROR,
code: 401,
message: '认证失败,请重新登录'
} as ApiError
} else if (statusCode === 400 || statusCode === 500) {
const errorMessage = data?.message || '请求失败'
throw {
type: ErrorType.BUSINESS_ERROR,
code: statusCode,
message: errorMessage
} as ApiError
} else {
throw {
type: ErrorType.UNKNOWN_ERROR,
code: statusCode,
message: '未知错误'
} as ApiError
}
}
private handleError(error: any): ApiError {
if (error.errMsg) {
if (error.errMsg.includes('timeout')) {
return {
type: ErrorType.TIMEOUT_ERROR,
code: 0,
message: '请求超时,请稍后重试'
}
} else if (error.errMsg.includes('fail')) {
return {
type: ErrorType.NETWORK_ERROR,
code: 0,
message: '网络连接失败,请检查网络设置'
}
}
}
if (error.type) {
return error as ApiError
}
return {
type: ErrorType.UNKNOWN_ERROR,
code: 0,
message: error.message || '未知错误'
}
}
private getToken(): string | null {
try {
return uni.getStorageSync(this.tokenKey) || null
} catch (error) {
return null
}
}
setToken(token: string): void {
try {
uni.setStorageSync(this.tokenKey, token)
} catch (error) {
console.error('设置Token失败:', error)
}
}
removeToken(): void {
try {
uni.removeStorageSync(this.tokenKey)
} catch (error) {
console.error('删除Token失败:', error)
}
}
}
const httpClient = new HttpClient()
export default httpClient
export { HttpClient }
@@ -1,93 +0,0 @@
import type { ApiError, ErrorType } from './httpClient'
const TOKEN_KEY = 'auth_token'
const REFRESH_TOKEN_KEY = 'refresh_token'
const TOKEN_EXPIRY_KEY = 'token_expiry'
class TokenManager {
setToken(token: string, expiresIn?: number): void {
try {
uni.setStorageSync(TOKEN_KEY, token)
if (expiresIn !== undefined) {
const expiryTime = Date.now() + expiresIn * 1000
uni.setStorageSync(TOKEN_EXPIRY_KEY, expiryTime)
}
} catch (error) {
console.error('设置Token失败:', error)
}
}
getToken(): string | null {
try {
const token = uni.getStorageSync(TOKEN_KEY)
if (token === null || token === undefined) {
return null
}
return token
} catch (error) {
console.error('获取Token失败:', error)
return null
}
}
removeToken(): void {
try {
uni.removeStorageSync(TOKEN_KEY)
uni.removeStorageSync(TOKEN_EXPIRY_KEY)
} catch (error) {
console.error('删除Token失败:', error)
}
}
setRefreshToken(refreshToken: string): void {
try {
uni.setStorageSync(REFRESH_TOKEN_KEY, refreshToken)
} catch (error) {
console.error('设置刷新Token失败:', error)
}
}
getRefreshToken(): string | null {
try {
const refreshToken = uni.getStorageSync(REFRESH_TOKEN_KEY)
if (refreshToken === null || refreshToken === undefined) {
return null
}
return refreshToken
} catch (error) {
console.error('获取刷新Token失败:', error)
return null
}
}
removeRefreshToken(): void {
try {
uni.removeStorageSync(REFRESH_TOKEN_KEY)
} catch (error) {
console.error('删除刷新Token失败:', error)
}
}
isTokenExpired(): boolean {
try {
const expiryTime = uni.getStorageSync(TOKEN_EXPIRY_KEY)
if (expiryTime === null || expiryTime === undefined) {
return false
}
return Date.now() >= expiryTime
} catch (error) {
console.error('检查Token过期失败:', error)
return false
}
}
clearAll(): void {
this.removeToken()
this.removeRefreshToken()
}
}
const tokenManager = new TokenManager()
export default tokenManager
export { TokenManager }
@@ -1,14 +0,0 @@
import lunarUtils from './src/utils/lunarUtils'
const testDates = [
{ year: 2025, month: 1, day: 18 },
{ year: 2025, month: 1, day: 19 },
{ year: 2025, month: 1, day: 20 },
{ year: 2025, month: 1, day: 21 },
{ year: 2025, month: 1, day: 22 }
]
testDates.forEach(date => {
const lunarDate = lunarUtils.solarToLunar(date.year, date.month, date.day)
console.log(`${date.year}-${date.month}-${date.day} => ${lunarDate.yearStr} ${lunarDate.monthStr}${lunarDate.dayStr}`)
})
@@ -1,13 +0,0 @@
import lunarUtils from './src/utils/lunarUtils'
const today = new Date(2026, 0, 20)
const lunarDate = lunarUtils.solarToLunar(
today.getFullYear(),
today.getMonth() + 1,
today.getDate()
)
console.log('公历日期:', today.toISOString().split('T')[0])
console.log('农历日期:', lunarDate.yearStr, lunarDate.monthStr, lunarDate.dayStr)
console.log('生肖:', lunarDate.zodiac.name)
console.log('闰月:', lunarDate.isLeapMonth ? '是' : '否')
@@ -1,14 +0,0 @@
import lunarUtils from './src/utils/lunarUtils'
const testDates = [
{ year: 2026, month: 1, day: 18 },
{ year: 2026, month: 1, day: 19 },
{ year: 2026, month: 1, day: 20 },
{ year: 2026, month: 1, day: 21 },
{ year: 2026, month: 1, day: 22 }
]
testDates.forEach(date => {
const lunarDate = lunarUtils.solarToLunar(date.year, date.month, date.day)
console.log(`${date.year}-${date.month}-${date.day} => ${lunarDate.yearStr} ${lunarDate.monthStr}${lunarDate.dayStr}`)
})
@@ -1,529 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AIGC 小程序环境验证</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 24px;
font-weight: 600;
color: #2C180C;
margin-bottom: 20px;
border-bottom: 2px solid #C41E3A;
padding-bottom: 10px;
}
.section {
margin-bottom: 40px;
}
.section-title {
font-size: 18px;
font-weight: 500;
color: #2C180C;
margin-bottom: 16px;
}
.checklist {
list-style: none;
}
.checklist-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #E6E1DC;
}
.checklist-item:last-child {
border-bottom: none;
}
.checkbox {
width: 20px;
height: 20px;
border: 2px solid #C41E3A;
border-radius: 4px;
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
}
.checkbox.checked {
background-color: #C41E3A;
}
.checkbox.checked::after {
content: '✓';
color: white;
font-size: 14px;
font-weight: bold;
}
.checklist-text {
flex: 1;
font-size: 14px;
color: #2C180C;
}
.status {
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.status.pass {
background-color: #16A38A;
color: white;
}
.status.fail {
background-color: #EF4444;
color: white;
}
.button {
background-color: #C41E3A;
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
margin-right: 12px;
margin-bottom: 12px;
}
.button:hover {
background-color: #A81A30;
}
.button:active {
transform: scale(0.95);
}
.button.secondary {
background-color: #717B7A;
}
.button.secondary:hover {
background-color: #5A6362;
}
.preview-frame {
width: 100%;
height: 600px;
border: 2px solid #E6E1DC;
border-radius: 8px;
margin-bottom: 20px;
background-color: #FAF9F6;
}
.device-simulator {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 20px;
}
.device-item {
border: 1px solid #E6E1DC;
border-radius: 8px;
padding: 16px;
text-align: center;
cursor: pointer;
transition: all 0.15s ease;
}
.device-item:hover {
border-color: #C41E3A;
background-color: rgba(196, 30, 58, 0.05);
}
.device-item.active {
border-color: #C41E3A;
background-color: rgba(196, 30, 58, 0.1);
}
.device-icon {
width: 48px;
height: 48px;
margin: 0 auto 12px;
background-color: #C41E3A;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
}
.device-name {
font-size: 14px;
font-weight: 500;
color: #2C180C;
margin-bottom: 4px;
}
.device-spec {
font-size: 12px;
color: #717B7A;
}
.summary {
background-color: #FAF9F6;
border-radius: 8px;
padding: 20px;
margin-top: 20px;
}
.summary-title {
font-size: 16px;
font-weight: 600;
color: #2C180C;
margin-bottom: 12px;
}
.summary-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
}
.summary-stat {
background-color: white;
border-radius: 8px;
padding: 16px;
text-align: center;
}
.summary-stat-value {
font-size: 32px;
font-weight: 600;
color: #C41E3A;
}
.summary-stat-label {
font-size: 12px;
color: #717B7A;
margin-top: 4px;
}
.progress-bar {
width: 100%;
height: 8px;
background-color: #E6E1DC;
border-radius: 4px;
overflow: hidden;
margin-top: 12px;
}
.progress-fill {
height: 100%;
background-color: #16A38A;
transition: width 0.3s ease;
}
</style>
</head>
<body>
<div class="container">
<h1>AIGC 小程序环境验证</h1>
<div class="section">
<h2 class="section-title">设备模拟器</h2>
<div class="device-simulator">
<div class="device-item active" onclick="selectDevice('iphone-se')">
<div class="device-icon">📱</div>
<div class="device-name">iPhone SE</div>
<div class="device-spec">375 × 667</div>
</div>
<div class="device-item" onclick="selectDevice('iphone-12')">
<div class="device-icon">📱</div>
<div class="device-name">iPhone 12</div>
<div class="device-spec">390 × 844</div>
</div>
<div class="device-item" onclick="selectDevice('iphone-14')">
<div class="device-icon">📱</div>
<div class="device-name">iPhone 14</div>
<div class="device-spec">393 × 852</div>
</div>
<div class="device-item" onclick="selectDevice('ipad')">
<div class="device-icon">📱</div>
<div class="device-name">iPad</div>
<div class="device-spec">768 × 1024</div>
</div>
<div class="device-item" onclick="selectDevice('desktop')">
<div class="device-icon">🖥️</div>
<div class="device-name">桌面端</div>
<div class="device-spec">1920 × 1080</div>
</div>
</div>
<iframe class="preview-frame" id="previewFrame" src="http://localhost:8081/#/pages/aigc/index"></iframe>
</div>
<div class="section">
<h2 class="section-title">小程序环境检查清单</h2>
<ul class="checklist" id="miniprogramChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">页面在H5环境正常加载</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">所有样式在小程序中正确渲染</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">rpx单位正确转换为像素</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">flex布局在小程序中正常工作</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">grid布局在小程序中正常工作</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">所有颜色值精确显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">字体在小程序中正确加载</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">图标在小程序中正确显示</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">交互效果检查清单</h2>
<ul class="checklist" id="interactionChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">点击事件在小程序中正常触发</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">hover效果在小程序中正常显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">active效果在小程序中正常显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">过渡动画在小程序中流畅播放</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">状态切换在小程序中正常工作</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">所有交互反馈及时准确</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">响应式适配检查清单</h2>
<ul class="checklist" id="responsiveChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">移动端布局完整显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">平板端布局完整显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">桌面端布局完整显示</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">断点切换流畅无闪烁</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">字体大小自适应准确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">间距比例保持一致</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">验证操作</h2>
<button class="button" onclick="runFullVerification()">运行完整验证</button>
<button class="button secondary" onclick="exportReport()">导出验证报告</button>
<button class="button secondary" onclick="openPixsoDesign()">打开设计稿</button>
<button class="button secondary" onclick="refreshPreview()">刷新预览</button>
</div>
<div class="summary">
<h2 class="summary-title">验证总结</h2>
<div class="summary-stats">
<div class="summary-stat">
<div class="summary-stat-value" id="totalChecks">20</div>
<div class="summary-stat-label">总检查项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="passedChecks">20</div>
<div class="summary-stat-label">通过项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="failedChecks">0</div>
<div class="summary-stat-label">失败项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="passRate">100%</div>
<div class="summary-stat-label">通过率</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 100%;"></div>
</div>
</div>
</div>
<script>
let currentDevice = 'iphone-se';
function selectDevice(device) {
currentDevice = device;
document.querySelectorAll('.device-item').forEach(item => {
item.classList.remove('active');
});
event.currentTarget.classList.add('active');
const frame = document.getElementById('previewFrame');
const deviceSizes = {
'iphone-se': { width: '375px', height: '667px' },
'iphone-12': { width: '390px', height: '844px' },
'iphone-14': { width: '393px', height: '852px' },
'ipad': { width: '768px', height: '1024px' },
'desktop': { width: '100%', height: '800px' }
};
const size = deviceSizes[device];
frame.style.width = size.width;
frame.style.height = size.height;
}
function runFullVerification() {
alert('完整验证已启动!\n\n正在检查:\n- 小程序环境兼容性\n- 视觉效果还原度\n- 交互功能完整性\n- 响应式布局适配\n\n验证完成: 100% 匹配');
}
function exportReport() {
const report = {
timestamp: new Date().toISOString(),
device: currentDevice,
miniprogramChecks: {
total: 8,
passed: 8,
failed: 0,
passRate: '100%'
},
interactionChecks: {
total: 6,
passed: 6,
failed: 0,
passRate: '100%'
},
responsiveChecks: {
total: 6,
passed: 6,
failed: 0,
passRate: '100%'
},
overall: {
total: 20,
passed: 20,
failed: 0,
passRate: '100%'
},
conclusion: '所有检查项均通过,AIGC页面在小程序环境中完美呈现,与设计稿达到100%匹配度。'
};
const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'aigc-miniprogram-verification-report.json';
a.click();
URL.revokeObjectURL(url);
}
function openPixsoDesign() {
window.open('https://pixso.cn/app/design/8teaTOeN2QkeggcAJdfjMw?item-id=2:582', '_blank');
}
function refreshPreview() {
const frame = document.getElementById('previewFrame');
frame.src = frame.src;
}
window.addEventListener('load', () => {
selectDevice('iphone-se');
});
</script>
</body>
</html>
@@ -1,603 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AIGC 页面像素级对比验证</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 24px;
font-weight: 600;
color: #2C180C;
margin-bottom: 20px;
border-bottom: 2px solid #C41E3A;
padding-bottom: 10px;
}
.section {
margin-bottom: 40px;
}
.section-title {
font-size: 18px;
font-weight: 500;
color: #2C180C;
margin-bottom: 16px;
}
.checklist {
list-style: none;
}
.checklist-item {
display: flex;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #E6E1DC;
}
.checklist-item:last-child {
border-bottom: none;
}
.checkbox {
width: 20px;
height: 20px;
border: 2px solid #C41E3A;
border-radius: 4px;
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
}
.checkbox.checked {
background-color: #C41E3A;
}
.checkbox.checked::after {
content: '✓';
color: white;
font-size: 14px;
font-weight: bold;
}
.checklist-text {
flex: 1;
font-size: 14px;
color: #2C180C;
}
.status {
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.status.pass {
background-color: #16A38A;
color: white;
}
.status.fail {
background-color: #EF4444;
color: white;
}
.color-palette {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 16px;
}
.color-item {
border: 1px solid #E6E1DC;
border-radius: 8px;
padding: 12px;
}
.color-preview {
width: 100%;
height: 60px;
border-radius: 4px;
margin-bottom: 8px;
border: 1px solid rgba(0, 0, 0, 0.1);
}
.color-info {
font-size: 12px;
color: #717B7A;
}
.color-name {
font-weight: 500;
color: #2C180C;
margin-bottom: 4px;
}
.spacing-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.spacing-item {
border: 1px solid #E6E1DC;
border-radius: 8px;
padding: 12px;
}
.spacing-visual {
background-color: #C41E3A;
height: 20px;
border-radius: 2px;
margin-bottom: 8px;
}
.spacing-info {
font-size: 12px;
color: #717B7A;
}
.spacing-name {
font-weight: 500;
color: #2C180C;
margin-bottom: 4px;
}
.typography-item {
border: 1px solid #E6E1DC;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
}
.typography-preview {
margin-bottom: 12px;
color: #2C180C;
}
.typography-info {
font-size: 12px;
color: #717B7A;
}
.typography-spec {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.typography-spec-item {
background-color: #FAF9F6;
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
color: #2C180C;
}
.button {
background-color: #C41E3A;
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
margin-right: 12px;
margin-bottom: 12px;
}
.button:hover {
background-color: #A81A30;
}
.button:active {
transform: scale(0.95);
}
.button.secondary {
background-color: #717B7A;
}
.button.secondary:hover {
background-color: #5A6362;
}
.summary {
background-color: #FAF9F6;
border-radius: 8px;
padding: 20px;
margin-top: 20px;
}
.summary-title {
font-size: 16px;
font-weight: 600;
color: #2C180C;
margin-bottom: 12px;
}
.summary-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
}
.summary-stat {
background-color: white;
border-radius: 8px;
padding: 16px;
text-align: center;
}
.summary-stat-value {
font-size: 32px;
font-weight: 600;
color: #C41E3A;
}
.summary-stat-label {
font-size: 12px;
color: #717B7A;
margin-top: 4px;
}
.progress-bar {
width: 100%;
height: 8px;
background-color: #E6E1DC;
border-radius: 4px;
overflow: hidden;
margin-top: 12px;
}
.progress-fill {
height: 100%;
background-color: #16A38A;
transition: width 0.3s ease;
}
</style>
</head>
<body>
<div class="container">
<h1>AIGC 页面像素级对比验证</h1>
<div class="section">
<h2 class="section-title">视觉元素还原检查清单</h2>
<ul class="checklist" id="visualChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">布局结构与设计稿完全一致</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">颜色值精确匹配(误差<1px)</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">字体样式完全一致</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">间距尺寸精确匹配</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">阴影效果一致</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">边框样式精确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">圆角半径准确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">图标样式精确还原</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">交互状态还原检查清单</h2>
<ul class="checklist" id="interactionChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">正常状态显示正确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">悬停状态效果一致</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">点击状态反馈准确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">禁用状态样式正确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">选中状态高亮准确</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">状态切换动画流畅</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">响应式设计检查清单</h2>
<ul class="checklist" id="responsiveChecklist">
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">移动端布局完整</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">平板端布局适配</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">桌面端布局完整</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">断点切换流畅</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">字体大小自适应</span>
<span class="status pass">通过</span>
</li>
<li class="checklist-item">
<div class="checkbox checked"></div>
<span class="checklist-text">间距比例保持</span>
<span class="status pass">通过</span>
</li>
</ul>
</div>
<div class="section">
<h2 class="section-title">颜色规范验证</h2>
<div class="color-palette">
<div class="color-item">
<div class="color-preview" style="background-color: rgba(250, 249, 246, 255);"></div>
<div class="color-name">背景色</div>
<div class="color-info">rgba(250, 249, 246, 255)</div>
</div>
<div class="color-item">
<div class="color-preview" style="background-color: rgba(255, 255, 255, 255);"></div>
<div class="color-name">表面色</div>
<div class="color-info">rgba(255, 255, 255, 255)</div>
</div>
<div class="color-item">
<div class="color-preview" style="background-color: rgba(44, 24, 16, 255);"></div>
<div class="color-name">主文本色</div>
<div class="color-info">rgba(44, 24, 16, 255)</div>
</div>
<div class="color-item">
<div class="color-preview" style="background-color: rgba(113, 113, 122, 255);"></div>
<div class="color-name">次要文本色</div>
<div class="color-info">rgba(113, 113, 122, 255)</div>
</div>
<div class="color-item">
<div class="color-preview" style="background-color: rgba(196, 30, 58, 255);"></div>
<div class="color-name">主题色</div>
<div class="color-info">rgba(196, 30, 58, 255)</div>
</div>
<div class="color-item">
<div class="color-preview" style="background-color: rgba(2, 9, 16, 0.13);"></div>
<div class="color-name">边框色</div>
<div class="color-info">rgba(2, 9, 16, 0.13)</div>
</div>
</div>
</div>
<div class="section">
<h2 class="section-title">间距规范验证</h2>
<div class="spacing-grid">
<div class="spacing-item">
<div class="spacing-visual" style="width: 8px;"></div>
<div class="spacing-name">极小间距</div>
<div class="spacing-info">8px (4rpx)</div>
</div>
<div class="spacing-item">
<div class="spacing-visual" style="width: 16px;"></div>
<div class="spacing-name">小间距</div>
<div class="spacing-info">16px (8rpx)</div>
</div>
<div class="spacing-item">
<div class="spacing-visual" style="width: 32px;"></div>
<div class="spacing-name">中间距</div>
<div class="spacing-info">32px (16rpx)</div>
</div>
<div class="spacing-item">
<div class="spacing-visual" style="width: 48px;"></div>
<div class="spacing-name">大间距</div>
<div class="spacing-info">48px (24rpx)</div>
</div>
<div class="spacing-item">
<div class="spacing-visual" style="width: 64px;"></div>
<div class="spacing-name">超大间距</div>
<div class="spacing-info">64px (32rpx)</div>
</div>
</div>
</div>
<div class="section">
<h2 class="section-title">字体规范验证</h2>
<div class="typography-item">
<div class="typography-preview" style="font-size: 32px; font-weight: 600;">日历数字</div>
<div class="typography-info">
<div class="typography-spec">
<span class="typography-spec-item">32px</span>
<span class="typography-spec-item">600 weight</span>
<span class="typography-spec-item">Inter</span>
</div>
</div>
</div>
<div class="typography-item">
<div class="typography-preview" style="font-size: 28px; font-weight: 500;">2026年1月</div>
<div class="typography-info">
<div class="typography-spec">
<span class="typography-spec-item">28px</span>
<span class="typography-spec-item">500 weight</span>
<span class="typography-spec-item">Inter</span>
</div>
</div>
</div>
<div class="typography-item">
<div class="typography-preview" style="font-size: 24px; font-weight: 500;">日一二三四五六</div>
<div class="typography-info">
<div class="typography-spec">
<span class="typography-spec-item">24px</span>
<span class="typography-spec-item">500 weight</span>
<span class="typography-spec-item">Inter</span>
</div>
</div>
</div>
<div class="typography-item">
<div class="typography-preview" style="font-size: 20px; font-weight: 400;">农历日期</div>
<div class="typography-info">
<div class="typography-spec">
<span class="typography-spec-item">20px</span>
<span class="typography-spec-item">400 weight</span>
<span class="typography-spec-item">Microsoft YaHei</span>
</div>
</div>
</div>
</div>
<div class="section">
<h2 class="section-title">验证操作</h2>
<button class="button" onclick="runFullVerification()">运行完整验证</button>
<button class="button secondary" onclick="exportReport()">导出验证报告</button>
<button class="button secondary" onclick="openPixsoDesign()">打开设计稿</button>
</div>
<div class="summary">
<h2 class="summary-title">验证总结</h2>
<div class="summary-stats">
<div class="summary-stat">
<div class="summary-stat-value" id="totalChecks">20</div>
<div class="summary-stat-label">总检查项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="passedChecks">20</div>
<div class="summary-stat-label">通过项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="failedChecks">0</div>
<div class="summary-stat-label">失败项</div>
</div>
<div class="summary-stat">
<div class="summary-stat-value" id="passRate">100%</div>
<div class="summary-stat-label">通过率</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 100%;"></div>
</div>
</div>
</div>
<script>
function runFullVerification() {
alert('完整验证已启动!\n\n正在检查:\n- 视觉元素还原\n- 交互状态实现\n- 响应式布局适配\n- 像素级精度\n\n验证完成: 100% 匹配');
}
function exportReport() {
const report = {
timestamp: new Date().toISOString(),
visualChecks: {
total: 8,
passed: 8,
failed: 0,
passRate: '100%'
},
interactionChecks: {
total: 6,
passed: 6,
failed: 0,
passRate: '100%'
},
responsiveChecks: {
total: 6,
passed: 6,
failed: 0,
passRate: '100%'
},
overall: {
total: 20,
passed: 20,
failed: 0,
passRate: '100%'
},
conclusion: '所有检查项均通过,实现效果与设计稿达到100%匹配度。'
};
const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'aigc-verification-report.json';
a.click();
URL.revokeObjectURL(url);
}
function openPixsoDesign() {
window.open('https://pixso.cn/app/design/8teaTOeN2QkeggcAJdfjMw?item-id=2:582', '_blank');
}
</script>
</body>
</html>
@@ -1,307 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>暗黑模式切换测试</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 20px;
transition: background-color 0.3s, color 0.3s;
}
.light-mode {
background-color: #F9FAFB;
color: #333333;
}
.dark-mode {
background-color: #1E1E1E;
color: #E0E0E0;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 20px;
background: linear-gradient(135deg, #C7A27C 0%, #E8D5B5 100%);
border-radius: 12px;
color: #FFFFFF;
}
.dark-mode .header {
background: linear-gradient(135deg, #5B9BD5 0%, #2D2D2D 100%);
}
.card {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 12px;
padding: 20px;
margin-bottom: 16px;
transition: all 0.3s ease;
}
.dark-mode .card {
background-color: #2D2D2D;
border-color: #404040;
}
.card:hover {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.dark-mode .card:hover {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
font-weight: 500;
}
.btn-primary {
background-color: #C7A27C;
color: #FFFFFF;
}
.dark-mode .btn-primary {
background-color: #5B9BD5;
}
.btn-primary:hover {
transform: scale(1.02);
opacity: 0.9;
}
.btn-primary:active {
transform: scale(0.98);
}
.icon {
width: 48px;
height: 48px;
cursor: pointer;
transition: transform 0.2s ease;
}
.icon:hover {
transform: scale(1.1);
}
.icon:active {
transform: scale(0.9);
}
.status {
padding: 12px;
border-radius: 8px;
margin-bottom: 16px;
font-weight: 500;
}
.status-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.dark-mode .status-success {
background-color: #1e4620;
color: #d4edda;
border-color: #2d5a30;
}
.status-error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.dark-mode .status-error {
background-color: #5a1e24;
color: #f8d7da;
border-color: #7a2a32;
}
.test-section {
margin-top: 20px;
}
.test-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
border-bottom: 1px solid #E5E7EB;
}
.dark-mode .test-item {
border-bottom-color: #404040;
}
.test-item:last-child {
border-bottom: none;
}
.color-swatch {
width: 40px;
height: 40px;
border-radius: 8px;
border: 2px solid #E5E7EB;
}
.dark-mode .color-swatch {
border-color: #404040;
}
</style>
</head>
<body class="light-mode">
<div class="container">
<div class="header">
<h1 style="margin: 0;">暗黑模式切换测试</h1>
<svg class="icon" @click="toggleTheme" id="theme-icon" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
</svg>
</div>
<div id="status" class="status status-success" style="display: none;">
主题切换成功!
</div>
<div class="card">
<h2>当前主题状态</h2>
<div class="test-section">
<div class="test-item">
<span>主题模式</span>
<strong id="current-theme">浅色模式</strong>
</div>
<div class="test-item">
<span>背景颜色</span>
<div class="color-swatch" id="bg-color"></div>
</div>
<div class="test-item">
<span>文字颜色</span>
<div class="color-swatch" id="text-color"></div>
</div>
<div class="test-item">
<span>卡片背景</span>
<div class="color-swatch" id="card-bg"></div>
</div>
</div>
</div>
<div class="card">
<h2>测试说明</h2>
<p>点击右上角的月亮图标可以切换暗黑模式。</p>
<p>切换后,页面的所有元素应该立即更新为暗黑主题。</p>
<p>主题设置会自动保存,下次打开时会恢复上次选择的主题。</p>
</div>
<div class="card">
<h2>功能测试</h2>
<div class="test-section">
<button class="btn btn-primary" onclick="testThemeSwitch()">测试主题切换</button>
<button class="btn btn-primary" onclick="testLocalStorage()">测试本地存储</button>
<button class="btn btn-primary" onclick="testCSSVariables()">测试CSS变量</button>
</div>
</div>
</div>
<script>
let currentTheme = 'light';
function toggleTheme() {
currentTheme = currentTheme === 'light' ? 'dark' : 'light';
applyTheme(currentTheme);
showStatus('success', `已切换到${currentTheme === 'dark' ? '深色' : '浅色'}模式`);
}
function applyTheme(theme) {
const body = document.body;
const themeIcon = document.getElementById('theme-icon');
const currentThemeText = document.getElementById('current-theme');
const bgColor = document.getElementById('bg-color');
const textColor = document.getElementById('text-color');
const cardBg = document.getElementById('card-bg');
if (theme === 'dark') {
body.classList.remove('light-mode');
body.classList.add('dark-mode');
currentThemeText.textContent = '深色模式';
bgColor.style.backgroundColor = '#1E1E1E';
textColor.style.backgroundColor = '#E0E0E0';
cardBg.style.backgroundColor = '#2D2D2D';
} else {
body.classList.remove('dark-mode');
body.classList.add('light-mode');
currentThemeText.textContent = '浅色模式';
bgColor.style.backgroundColor = '#F9FAFB';
textColor.style.backgroundColor = '#333333';
cardBg.style.backgroundColor = '#FFFFFF';
}
localStorage.setItem('theme-mode', theme);
}
function showStatus(type, message) {
const status = document.getElementById('status');
status.className = `status status-${type}`;
status.textContent = message;
status.style.display = 'block';
setTimeout(() => {
status.style.display = 'none';
}, 3000);
}
function testThemeSwitch() {
toggleTheme();
showStatus('success', '主题切换测试通过!');
}
function testLocalStorage() {
const savedTheme = localStorage.getItem('theme-mode');
if (savedTheme === currentTheme) {
showStatus('success', '本地存储测试通过!');
} else {
showStatus('error', '本地存储测试失败!');
}
}
function testCSSVariables() {
const computedStyle = getComputedStyle(document.body);
const bgColor = computedStyle.backgroundColor;
if (currentTheme === 'dark' && bgColor.includes('30') || currentTheme === 'light' && bgColor.includes('250')) {
showStatus('success', 'CSS变量测试通过!');
} else {
showStatus('error', 'CSS变量测试失败!');
}
}
document.getElementById('theme-icon').addEventListener('click', toggleTheme);
window.addEventListener('load', () => {
const savedTheme = localStorage.getItem('theme-mode') || 'light';
currentTheme = savedTheme;
applyTheme(savedTheme);
});
</script>
</body>
</html>
@@ -1,16 +0,0 @@
import lunarUtils from './src/utils/lunarUtils'
const testDates = [
{ year: 2025, month: 1, day: 28 },
{ year: 2025, month: 1, day: 29 },
{ year: 2025, month: 1, day: 30 },
{ year: 2026, month: 2, day: 16 },
{ year: 2026, month: 2, day: 17 },
{ year: 2026, month: 2, day: 18 }
]
console.log('=== 农历年切换测试 ===')
testDates.forEach(date => {
const lunarDate = lunarUtils.solarToLunar(date.year, date.month, date.day)
console.log(`${date.year}-${date.month}-${date.day} => ${lunarDate.yearStr} ${lunarDate.monthStr}${lunarDate.dayStr}`)
})