Просмотр исходного кода

fix(Dashboard): CSS grid violations, teacher API null guards, progress fallback, improved changelog parser

- Replace CSS grid-template-columns with flexbox in .td-quick-actions and .td-today-stats
- Add null guards in loadTeacherData() for all response properties after Promise.all catch
- Handle missing taskCompletionRate gracefully with parseFloat fallback
- Replace simplified Markdown parser with block-level parser supporting code blocks, lists, headings, bold/italic/code/links
- Fix closing brace formatting that caused build failure
Xiaogang Liao 2 месяцев назад
Родитель
Сommit
68f83e7bcd
1 измененных файлов с 79 добавлено и 16 удалено
  1. 79 16
      cfc-web/src/views/Dashboard.vue

+ 79 - 16
cfc-web/src/views/Dashboard.vue

@@ -551,25 +551,88 @@ export default {
       fetch(process.env.BASE_URL + 'CHANGELOG.md?t=' + Date.now()).then(function(res) {
       fetch(process.env.BASE_URL + 'CHANGELOG.md?t=' + Date.now()).then(function(res) {
         if (!res.ok) throw new Error('Not found')
         if (!res.ok) throw new Error('Not found')
         return res.text()
         return res.text()
-      }).then(function(text) {
-        // 解析 Markdown 标题
-        var html = text
-        // 还原标题层级
-        html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>')
-        html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>')
-        html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>')
-        // 处理列表
-        html = html.replace(/^- (.+)$/gm, '<li>$1</li>')
-        html = html.replace(/(<li>.*<\/li>\n?)+/g, '<ul>$&</ul>')
-        // 换行转 br
-        html = html.replace(/\n\n/g, '</p><p class="cl-item">')
-        html = '<p class="cl-item">' + html + '</p>'
-        this.changelogContent = html
+      }).then((function(text) {
+        var html = ''
+        var lines = text.split('\n')
+        var inCodeBlock = false
+        var listBuffer = ''
+        var inList = false
+
+        function flushList() {
+          if (inList) {
+            html += '<ul>' + listBuffer + '</ul>'
+            listBuffer = ''
+            inList = false
+          }
+        }
+
+        for (var i = 0; i < lines.length; i++) {
+          var line = lines[i]
+
+          if (line.match(/^```/)) {
+            flushList()
+            if (inCodeBlock) {
+              html += '</code></pre>'
+              inCodeBlock = false
+            } else {
+              html += '<pre><code>'
+              inCodeBlock = true
+            }
+            continue
+          }
+          if (inCodeBlock) {
+            html += this._escapeHtml(line) + '\n'
+            continue
+          }
+
+          if (line.match(/^### /)) {
+            flushList()
+            html += '<h3>' + this._parseInline(line.replace(/^### /, '')) + '</h3>'
+            continue
+          }
+          if (line.match(/^## /)) {
+            flushList()
+            html += '<h2>' + this._parseInline(line.replace(/^## /, '')) + '</h2>'
+            continue
+          }
+          if (line.match(/^# /)) {
+            flushList()
+            html += '<h1>' + this._parseInline(line.replace(/^# /, '')) + '</h1>'
+            continue
+          }
+
+          if (line.match(/^\- /)) {
+            inList = true
+            listBuffer += '<li>' + this._parseInline(line.replace(/^\- /, '')) + '</li>\n'
+            continue
+          }
+
+          if (line.trim() === '') {
+            flushList()
+            continue
+          }
+
+          flushList()
+          html += '<p class="cl-item">' + this._parseInline(line) + '</p>\n'
+        }
+        flushList()
+        this.changelogContent = html || '<p class="cl-empty">暂无变更日志</p>'
         this.changelogLoading = false
         this.changelogLoading = false
-      }.bind(this)).catch(function() {
+      }).bind(this)).catch((function() {
         this.changelogContent = '<p class="cl-empty">暂无变更日志</p>'
         this.changelogContent = '<p class="cl-empty">暂无变更日志</p>'
         this.changelogLoading = false
         this.changelogLoading = false
-      }.bind(this))
+      }).bind(this))
+    },
+    _parseInline(text) {
+      text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
+      text = text.replace(/\*(.+?)\*/g, '<em>$1</em>')
+      text = text.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank">$1</a>')
+      text = text.replace(/`(.+?)`/g, '<code style="background:#F1F5F9;padding:2px 4px;border-radius:3px;font-size:13px">$1</code>')
+      text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+      return text
+    },
+    _escapeHtml(text) {
+      return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
     }
     }
   }
   }
 }
 }