fix(ui): 重构 topics.html Vue 应用结构
- 完全重写 script 部分,确保 methods 和 mounted 正确闭包 - 修复 Vue 表达式未解析的问题 - 添加调试日志 - 确保移动端和桌面端都能正确挂载
This commit is contained in:
+100
-16
@@ -181,42 +181,126 @@
|
|||||||
</div>
|
</div>
|
||||||
<script src="/static/vue/vue.global.js"></script>
|
<script src="/static/vue/vue.global.js"></script>
|
||||||
<script src="/static/element-plus/index.full.min.js"></script>
|
<script src="/static/element-plus/index.full.min.js"></script>
|
||||||
<script>
|
|
||||||
const TopicsApp = {
|
<script>
|
||||||
data() { return { isLoggedIn: false, isAdmin: false, currentUser: { username: '' }, topics: [], filterStatus: '', selectedTopicIds: [], loadingTable: false } },
|
const TopicsApp = {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage: 'topics',
|
||||||
|
isLoggedIn: false,
|
||||||
|
isAdmin: false,
|
||||||
|
currentUser: null,
|
||||||
|
loadingTable: false,
|
||||||
|
selectedTopicIds: [],
|
||||||
|
filterStatus: '',
|
||||||
|
stats: { total: 0, pending: 0, review: 0, ready: 0, published: 0, today: 0 },
|
||||||
|
topics: []
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filteredTopics() {
|
filteredTopics() {
|
||||||
console.log('[DEBUG] filteredTopics called, filterStatus:', this.filterStatus, 'topics count:', this.topics.length);
|
if (!this.topics || !this.topics.length) { return []; }
|
||||||
if (!this.topics.length) { console.log('[DEBUG] topics is empty'); return []; }
|
if (!this.filterStatus) { return this.topics; }
|
||||||
if (!this.filterStatus) { console.log('[DEBUG] no filter, return all'); return this.topics; }
|
return this.topics.filter(t => t.status === this.filterStatus);
|
||||||
const result = this.topics.filter(t => t.status === this.filterStatus);
|
|
||||||
console.log('[DEBUG] filtered result count:', result.length);
|
|
||||||
return result;
|
|
||||||
},
|
},
|
||||||
countByStatus() { return (status) => this.topics.filter(t => t.status === status).length; }
|
countByStatus() {
|
||||||
|
return (status) => this.topics.filter(t => t.status === status).length;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchTopics() {
|
async fetchTopics() {
|
||||||
this.loadingTable = true;
|
this.loadingTable = true;
|
||||||
console.log('[DEBUG] fetchTopics called');
|
|
||||||
try {
|
try {
|
||||||
const token = localStorage.getItem('authToken');
|
const token = localStorage.getItem('authToken');
|
||||||
const response = await fetch('/api/topics', { headers: { 'Authorization': 'Bearer ' + token } });
|
const response = await fetch('/api/topics', { headers: { 'Authorization': 'Bearer ' + token } });
|
||||||
if (!response.ok) throw new Error('获取失败');
|
if (!response.ok) throw new Error('获取失败');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.topics = data || [];
|
this.topics = data || [];
|
||||||
|
this.loadingTable = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('获取选题失败:', error);
|
console.log('获取选题失败,使用模拟数据');
|
||||||
this.$message.error('获取选题失败,使用模拟数据');
|
this.$message.error('获取选题失败,使用模拟数据');
|
||||||
this.topics = [
|
this.topics = [
|
||||||
{ id: 'A01', title: '可持续发展趋势分析', field: '环保', status: '待处理', compliance_score: 85, created_at: '2026-04-27 10:30', generated_at: null, published_at: null },
|
{ id: 'A01', title: '可持续发展趋势分析', field: '环保', status: '待处理', compliance_score: 85, created_at: '2026-04-27 10:30', generated_at: null, published_at: null },
|
||||||
{ id: 'B02', title: 'AI 在内容创作中的应用', field: '科技', status: '待审查', compliance_score: 92, created_at: '2026-04-27 11:15', generated_at: '2026-04-27 11:45', published_at: null },
|
{ id: 'B02', title: 'AI 在内容创作中的应用', field: '科技', status: '待审查', compliance_score: 92, created_at: '2026-04-27 11:15', generated_at: '2026-04-27 11:45', published_at: null },
|
||||||
{ id: 'C03', title: '数字化转型案例研究', field: '商业', status: '待发布', compliance_score: 78, created_at: '2026-04-27 12:00', generated_at: '2026-04-27 12:30', published_at: '2026-04-27 13:00' }
|
{ id: 'C03', title: '数字化转型案例研究', field: '商业', status: '待发布', compliance_score: 78, created_at: '2026-04-27 12:00', generated_at: '2026-04-27 12:30', published_at: '2026-04-27 13:00' }
|
||||||
];
|
];
|
||||||
|
this.loadingTable = false;
|
||||||
}
|
}
|
||||||
const app = Vue.createApp(TopicsApp);
|
},
|
||||||
app.use(ElementPlus);
|
refreshAll() { this.$message.info('执行批量刷新'); },
|
||||||
app.mount('#app');
|
async triggerGenerateSelected() {
|
||||||
</script>
|
if (!this.selectedTopicIds.length) return;
|
||||||
|
this.$message.success('批量创作已启动');
|
||||||
|
this.selectedTopicIds = [];
|
||||||
|
await this.fetchTopics();
|
||||||
|
},
|
||||||
|
async triggerOptimizeSelected() {
|
||||||
|
if (!this.selectedTopicIds.length) return;
|
||||||
|
this.$message.success('批量优化已启动');
|
||||||
|
this.selectedTopicIds = [];
|
||||||
|
await this.fetchTopics();
|
||||||
|
},
|
||||||
|
openPreview(topic) { this.$message.info('预览:' + topic.title); },
|
||||||
|
async createTopic(topic) {
|
||||||
|
if (topic.status === '待处理') {
|
||||||
|
this.$message.success('开始创作:' + topic.title);
|
||||||
|
await this.fetchTopics();
|
||||||
|
} else { this.$message.info('仅待处理选题可创作'); }
|
||||||
|
},
|
||||||
|
async optimizeTopic(topic) {
|
||||||
|
if (topic.status === '待审查') {
|
||||||
|
this.$message.success('开始优化:' + topic.title);
|
||||||
|
await this.fetchTopics();
|
||||||
|
} else { this.$message.info('仅待审查选题可优化'); }
|
||||||
|
},
|
||||||
|
async handlePublish(topic) { this.$message.success('发布:' + topic.title); await this.fetchTopics(); },
|
||||||
|
deleteTopic(id) {
|
||||||
|
this.$confirm('确定删除?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
|
||||||
|
.then(async () => { this.$message.success('删除成功'); await this.fetchTopics(); }).catch(() => {});
|
||||||
|
},
|
||||||
|
handleLogout() { localStorage.removeItem('authToken'); window.location.href = '/'; },
|
||||||
|
redirectToPage(page) { window.location.href = page.startsWith('/') ? page : '/' + page; },
|
||||||
|
formatDate(dateStr) {
|
||||||
|
if (!dateStr) return '-';
|
||||||
|
try {
|
||||||
|
return new Date(dateStr.replace(' ', 'T')).toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||||
|
hour: '2-digit', minute: '2-digit'
|
||||||
|
});
|
||||||
|
} catch (e) { return dateStr; }
|
||||||
|
},
|
||||||
|
getStatusType(status) {
|
||||||
|
const map = { '待处理': 'warning', '待审查': 'danger', '待发布': 'success', '已发布': 'info' };
|
||||||
|
return map[status] || 'primary';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
console.log('[DEBUG] TopicsApp mounted');
|
||||||
|
const token = localStorage.getItem('authToken');
|
||||||
|
console.log('[DEBUG] Token exists:', !!token);
|
||||||
|
if (!token) { window.location.href = '/'; return; }
|
||||||
|
// 解析 URL filter 参数
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const filter = urlParams.get('filter');
|
||||||
|
console.log('[DEBUG] URL filter:', filter);
|
||||||
|
if (filter) { this.filterStatus = filter; }
|
||||||
|
fetch('/api/auth/me', { headers: { 'Authorization': 'Bearer ' + token } })
|
||||||
|
.then(response => response.ok ? response.json() : Promise.reject())
|
||||||
|
.then(data => {
|
||||||
|
console.log('[DEBUG] Auth success, user:', data.user);
|
||||||
|
this.currentUser = data.user;
|
||||||
|
this.isAdmin = data.user.role === 'admin';
|
||||||
|
this.isLoggedIn = true;
|
||||||
|
this.fetchTopics();
|
||||||
|
})
|
||||||
|
.catch(() => { localStorage.removeItem('authToken'); window.location.href = '/'; });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const app = Vue.createApp(TopicsApp);
|
||||||
|
app.use(ElementPlus);
|
||||||
|
app.mount('#app');
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user