test-stage-navigation.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>阶段导航状态测试工具</title>
  7. <style>
  8. * {
  9. margin: 0;
  10. padding: 0;
  11. box-sizing: border-box;
  12. }
  13. body {
  14. font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  15. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  16. min-height: 100vh;
  17. padding: 20px;
  18. }
  19. .container {
  20. max-width: 1200px;
  21. margin: 0 auto;
  22. background: white;
  23. border-radius: 16px;
  24. box-shadow: 0 20px 60px rgba(0,0,0,0.3);
  25. padding: 40px;
  26. }
  27. h1 {
  28. text-align: center;
  29. color: #333;
  30. margin-bottom: 10px;
  31. font-size: 32px;
  32. }
  33. .subtitle {
  34. text-align: center;
  35. color: #666;
  36. margin-bottom: 40px;
  37. font-size: 14px;
  38. }
  39. .control-panel {
  40. background: #f8f9fa;
  41. border-radius: 12px;
  42. padding: 24px;
  43. margin-bottom: 32px;
  44. }
  45. .control-group {
  46. margin-bottom: 20px;
  47. }
  48. .control-group label {
  49. display: block;
  50. font-weight: 600;
  51. margin-bottom: 8px;
  52. color: #333;
  53. }
  54. .stage-buttons {
  55. display: grid;
  56. grid-template-columns: repeat(4, 1fr);
  57. gap: 12px;
  58. }
  59. .stage-btn {
  60. padding: 12px 20px;
  61. border: 2px solid #ddd;
  62. background: white;
  63. border-radius: 8px;
  64. cursor: pointer;
  65. transition: all 0.3s;
  66. font-size: 14px;
  67. font-weight: 500;
  68. }
  69. .stage-btn:hover {
  70. transform: translateY(-2px);
  71. box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  72. }
  73. .stage-btn.active {
  74. background: #eb445a;
  75. color: white;
  76. border-color: #eb445a;
  77. }
  78. /* 导航栏预览 */
  79. .navigation-preview {
  80. background: white;
  81. border: 2px solid #e0e0e0;
  82. border-radius: 12px;
  83. padding: 24px;
  84. margin-bottom: 32px;
  85. }
  86. .preview-title {
  87. font-size: 14px;
  88. font-weight: 600;
  89. color: #666;
  90. margin-bottom: 16px;
  91. text-transform: uppercase;
  92. letter-spacing: 1px;
  93. }
  94. .stage-navigation {
  95. display: flex;
  96. align-items: center;
  97. justify-content: space-between;
  98. }
  99. .stage-item {
  100. display: flex;
  101. flex-direction: column;
  102. align-items: center;
  103. gap: 8px;
  104. cursor: pointer;
  105. transition: all 0.3s;
  106. }
  107. .stage-item:hover {
  108. transform: translateY(-2px);
  109. }
  110. .stage-circle {
  111. width: 48px;
  112. height: 48px;
  113. border-radius: 50%;
  114. display: flex;
  115. align-items: center;
  116. justify-content: center;
  117. font-weight: 600;
  118. font-size: 18px;
  119. border: 3px solid #ddd;
  120. background: white;
  121. color: #999;
  122. transition: all 0.3s;
  123. }
  124. .stage-item.completed .stage-circle {
  125. background: linear-gradient(135deg, #2dd36f 0%, #28ba62 100%);
  126. border-color: #2dd36f;
  127. color: white;
  128. box-shadow: 0 2px 8px rgba(45, 211, 111, 0.3);
  129. }
  130. .stage-item.active .stage-circle {
  131. background: linear-gradient(135deg, #eb445a 0%, #d33850 100%);
  132. border-color: #eb445a;
  133. color: white;
  134. transform: scale(1.2);
  135. box-shadow: 0 0 0 4px rgba(235, 68, 90, 0.2),
  136. 0 4px 12px rgba(235, 68, 90, 0.4);
  137. animation: pulse 2s infinite;
  138. }
  139. .stage-item.pending .stage-circle {
  140. background: white;
  141. border-color: #ddd;
  142. color: #999;
  143. }
  144. @keyframes pulse {
  145. 0%, 100% {
  146. box-shadow: 0 0 0 4px rgba(235, 68, 90, 0.2),
  147. 0 4px 12px rgba(235, 68, 90, 0.4);
  148. }
  149. 50% {
  150. box-shadow: 0 0 0 8px rgba(235, 68, 90, 0.1),
  151. 0 4px 16px rgba(235, 68, 90, 0.5);
  152. }
  153. }
  154. .stage-label {
  155. font-size: 13px;
  156. font-weight: 500;
  157. color: #999;
  158. }
  159. .stage-item.completed .stage-label {
  160. color: #2dd36f;
  161. font-weight: 600;
  162. }
  163. .stage-item.active .stage-label {
  164. color: #eb445a;
  165. font-weight: 700;
  166. }
  167. .stage-connector {
  168. flex: 1;
  169. height: 3px;
  170. background: #e0e0e0;
  171. margin: 0 12px;
  172. margin-bottom: 32px;
  173. transition: background 0.3s;
  174. }
  175. .stage-connector.completed {
  176. background: #2dd36f;
  177. }
  178. /* 测试结果 */
  179. .test-results {
  180. background: #f8f9fa;
  181. border-radius: 12px;
  182. padding: 24px;
  183. }
  184. .result-item {
  185. background: white;
  186. border-left: 4px solid #ddd;
  187. padding: 16px;
  188. margin-bottom: 12px;
  189. border-radius: 4px;
  190. }
  191. .result-item.success {
  192. border-color: #2dd36f;
  193. background: #f0fdf4;
  194. }
  195. .result-item.error {
  196. border-color: #eb445a;
  197. background: #fef2f2;
  198. }
  199. .result-item.info {
  200. border-color: #3b82f6;
  201. background: #eff6ff;
  202. }
  203. .result-header {
  204. display: flex;
  205. align-items: center;
  206. gap: 8px;
  207. margin-bottom: 8px;
  208. font-weight: 600;
  209. }
  210. .icon {
  211. width: 20px;
  212. height: 20px;
  213. }
  214. .btn {
  215. padding: 12px 24px;
  216. border: none;
  217. border-radius: 8px;
  218. font-size: 14px;
  219. font-weight: 600;
  220. cursor: pointer;
  221. transition: all 0.3s;
  222. margin-right: 12px;
  223. }
  224. .btn-primary {
  225. background: #667eea;
  226. color: white;
  227. }
  228. .btn-primary:hover {
  229. background: #5568d3;
  230. transform: translateY(-2px);
  231. box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
  232. }
  233. .btn-secondary {
  234. background: #6c757d;
  235. color: white;
  236. }
  237. .btn-secondary:hover {
  238. background: #5a6268;
  239. }
  240. .actions {
  241. margin-top: 24px;
  242. text-align: center;
  243. }
  244. </style>
  245. </head>
  246. <body>
  247. <div class="container">
  248. <h1>🎯 阶段导航状态测试工具</h1>
  249. <p class="subtitle">模拟项目详情页的阶段导航栏状态变化</p>
  250. <!-- 控制面板 -->
  251. <div class="control-panel">
  252. <div class="control-group">
  253. <label>选择当前项目阶段:</label>
  254. <div class="stage-buttons">
  255. <button class="stage-btn active" data-stage="order" onclick="setCurrentStage('order')">
  256. 订单分配
  257. </button>
  258. <button class="stage-btn" data-stage="requirements" onclick="setCurrentStage('requirements')">
  259. 确认需求
  260. </button>
  261. <button class="stage-btn" data-stage="delivery" onclick="setCurrentStage('delivery')">
  262. 交付执行
  263. </button>
  264. <button class="stage-btn" data-stage="aftercare" onclick="setCurrentStage('aftercare')">
  265. 售后归档
  266. </button>
  267. </div>
  268. </div>
  269. </div>
  270. <!-- 导航栏预览 -->
  271. <div class="navigation-preview">
  272. <div class="preview-title">导航栏预览</div>
  273. <div class="stage-navigation">
  274. <div class="stage-item" id="stage-order" onclick="testStageClick('order')">
  275. <div class="stage-circle">
  276. <span class="stage-number">1</span>
  277. <span class="checkmark" style="display:none;">✓</span>
  278. </div>
  279. <div class="stage-label">订单分配</div>
  280. </div>
  281. <div class="stage-connector" id="connector-1"></div>
  282. <div class="stage-item" id="stage-requirements" onclick="testStageClick('requirements')">
  283. <div class="stage-circle">
  284. <span class="stage-number">2</span>
  285. <span class="checkmark" style="display:none;">✓</span>
  286. </div>
  287. <div class="stage-label">确认需求</div>
  288. </div>
  289. <div class="stage-connector" id="connector-2"></div>
  290. <div class="stage-item" id="stage-delivery" onclick="testStageClick('delivery')">
  291. <div class="stage-circle">
  292. <span class="stage-number">3</span>
  293. <span class="checkmark" style="display:none;">✓</span>
  294. </div>
  295. <div class="stage-label">交付执行</div>
  296. </div>
  297. <div class="stage-connector" id="connector-3"></div>
  298. <div class="stage-item" id="stage-aftercare" onclick="testStageClick('aftercare')">
  299. <div class="stage-circle">
  300. <span class="stage-number">4</span>
  301. <span class="checkmark" style="display:none;">✓</span>
  302. </div>
  303. <div class="stage-label">售后归档</div>
  304. </div>
  305. </div>
  306. </div>
  307. <!-- 测试结果 -->
  308. <div class="test-results">
  309. <div class="preview-title">测试结果</div>
  310. <div id="results"></div>
  311. </div>
  312. <div class="actions">
  313. <button class="btn btn-primary" onclick="runAllTests()">🧪 运行全部测试</button>
  314. <button class="btn btn-secondary" onclick="clearResults()">🗑️ 清空结果</button>
  315. </div>
  316. </div>
  317. <script>
  318. let currentStage = 'order';
  319. const stages = ['order', 'requirements', 'delivery', 'aftercare'];
  320. const stageNames = {
  321. 'order': '订单分配',
  322. 'requirements': '确认需求',
  323. 'delivery': '交付执行',
  324. 'aftercare': '售后归档'
  325. };
  326. function setCurrentStage(stage) {
  327. currentStage = stage;
  328. // 更新按钮状态
  329. document.querySelectorAll('.stage-btn').forEach(btn => {
  330. btn.classList.toggle('active', btn.dataset.stage === stage);
  331. });
  332. updateNavigation();
  333. addResult('info', '阶段已切换', `当前阶段设置为:${stageNames[stage]}`);
  334. }
  335. function getStageStatus(stageId) {
  336. const currentIdx = stages.indexOf(currentStage);
  337. const idx = stages.indexOf(stageId);
  338. if (idx < currentIdx) return 'completed';
  339. if (idx === currentIdx) return 'active';
  340. return 'pending';
  341. }
  342. function updateNavigation() {
  343. stages.forEach((stageId, index) => {
  344. const item = document.getElementById(`stage-${stageId}`);
  345. const status = getStageStatus(stageId);
  346. // 移除所有状态类
  347. item.classList.remove('completed', 'active', 'pending');
  348. item.classList.add(status);
  349. // 更新图标显示
  350. const number = item.querySelector('.stage-number');
  351. const checkmark = item.querySelector('.checkmark');
  352. if (status === 'completed') {
  353. number.style.display = 'none';
  354. checkmark.style.display = 'block';
  355. } else {
  356. number.style.display = 'block';
  357. checkmark.style.display = 'none';
  358. }
  359. // 更新连接线
  360. if (index < stages.length - 1) {
  361. const connector = document.getElementById(`connector-${index + 1}`);
  362. const nextStatus = getStageStatus(stages[index + 1]);
  363. connector.classList.toggle('completed',
  364. nextStatus === 'completed' || nextStatus === 'active');
  365. }
  366. });
  367. }
  368. function testStageClick(stageId) {
  369. const status = getStageStatus(stageId);
  370. const stageName = stageNames[stageId];
  371. const currentName = stageNames[currentStage];
  372. if (status === 'pending') {
  373. addResult('error', '❌ 访问被阻止',
  374. `当前项目正在进行【${currentName}】阶段\n请完成当前阶段后再进入【${stageName}】`);
  375. } else {
  376. addResult('success', '✅ 访问成功',
  377. `允许访问【${stageName}】阶段(状态:${status === 'active' ? '进行中' : '已完成'})`);
  378. }
  379. }
  380. function addResult(type, title, message) {
  381. const results = document.getElementById('results');
  382. const item = document.createElement('div');
  383. item.className = `result-item ${type}`;
  384. item.innerHTML = `
  385. <div class="result-header">
  386. <span class="icon">${type === 'success' ? '✅' : type === 'error' ? '❌' : 'ℹ️'}</span>
  387. <span>${title}</span>
  388. </div>
  389. <div>${message}</div>
  390. `;
  391. results.insertBefore(item, results.firstChild);
  392. }
  393. function clearResults() {
  394. document.getElementById('results').innerHTML = '';
  395. }
  396. function runAllTests() {
  397. clearResults();
  398. addResult('info', '🧪 开始测试', '运行全部阶段访问测试...');
  399. // 测试场景1:order阶段
  400. setCurrentStage('order');
  401. setTimeout(() => {
  402. testStageClick('order');
  403. testStageClick('requirements');
  404. testStageClick('delivery');
  405. testStageClick('aftercare');
  406. // 测试场景2:requirements阶段
  407. setTimeout(() => {
  408. setCurrentStage('requirements');
  409. setTimeout(() => {
  410. testStageClick('order');
  411. testStageClick('requirements');
  412. testStageClick('delivery');
  413. testStageClick('aftercare');
  414. // 测试场景3:delivery阶段
  415. setTimeout(() => {
  416. setCurrentStage('delivery');
  417. setTimeout(() => {
  418. testStageClick('order');
  419. testStageClick('requirements');
  420. testStageClick('delivery');
  421. testStageClick('aftercare');
  422. // 测试场景4:aftercare阶段
  423. setTimeout(() => {
  424. setCurrentStage('aftercare');
  425. setTimeout(() => {
  426. testStageClick('order');
  427. testStageClick('requirements');
  428. testStageClick('delivery');
  429. testStageClick('aftercare');
  430. addResult('success', '✅ 测试完成', '所有测试场景执行完毕');
  431. }, 100);
  432. }, 500);
  433. }, 100);
  434. }, 500);
  435. }, 100);
  436. }, 500);
  437. }, 100);
  438. }
  439. // 初始化
  440. updateNavigation();
  441. </script>
  442. </body>
  443. </html>