const { createApp, ref, computed, onMounted } = Vue;
createApp({
setup() {
const apiBase = ref(window.location.origin || "http://localhost:8000");
// Douyin State
const shareText = ref('');
const douyinLoading = ref(false);
const douyinRecords = ref([]);
let douyinTimer = null;
// Douyin Summary State
const showSummaryDialog = ref(false);
const summaryLoading = ref(false);
const summaryText = ref('');
// Simple Markdown Parser (Zero Dependency)
const simpleMarkdown = (text) => {
if (!text) return '';
let lines = text.split('\n');
let html = '';
let inList = false;
// Helper: Parse inline styles
const parseInline = (str) => {
return str
.replace(/\*\*(.*?)\*\*/g, '$1') // Bold
.replace(/`(.*?)`/g, '$1'); // Code
};
for (let line of lines) {
let trimmed = line.trim();
if (!trimmed) continue;
// Headers
if (trimmed.startsWith('### ')) {
if (inList) { html += ''; inList = false; }
html += `
${parseInline(trimmed)}
`; } } if (inList) html += ''; return html; }; const renderedSummary = computed(() => { if (!summaryText.value) return ''; try { return simpleMarkdown(summaryText.value); } catch (e) { console.error("Simple markdown error:", e); return summaryText.value; } }); // Methods const startParsing = async () => { if (!shareText.value.trim()) return; douyinLoading.value = true; try { const response = await axios.post(apiBase.value + '/api/parse', { text: shareText.value }); if (response.data.id || (response.data.ids && response.data.ids.length > 0)) { shareText.value = ''; fetchDouyinRecords(); if (typeof ElementPlus !== 'undefined') { const count = response.data.ids ? response.data.ids.length : 1; ElementPlus.ElMessage.success(`成功提交 ${count} 个解析任务`); } } } catch (error) { console.error('Error:', error); if (typeof ElementPlus !== 'undefined') ElementPlus.ElMessage.error('解析请求失败'); } finally { douyinLoading.value = false; } }; const fetchDouyinRecords = async (isManual) => { try { const response = await axios.get(apiBase.value + '/api/records'); const newRecords = response.data; douyinRecords.value = newRecords.map(newRec => { const oldRec = douyinRecords.value.find(r => r.id === newRec.id); return { ...newRec, expanded: oldRec ? oldRec.expanded : false, showOriginal: oldRec ? oldRec.showOriginal : false }; }); if (isManual === true || (isManual && isManual.type === 'click')) { if (typeof ElementPlus !== 'undefined') ElementPlus.ElMessage.success('列表已刷新'); } } catch (error) { console.error('Error fetching records:', error); if (isManual === true || (isManual && isManual.type === 'click')) { if (typeof ElementPlus !== 'undefined') ElementPlus.ElMessage.error('刷新失败'); } } }; const deleteRecord = async (id) => { if (!confirm('确定要删除这条记录吗?')) return; try { await axios.delete(apiBase.value + `/api/records/${id}`); fetchDouyinRecords(); if (typeof ElementPlus !== 'undefined') ElementPlus.ElMessage.success('删除成功'); } catch (error) { console.error('Error deleting:', error); if (typeof ElementPlus !== 'undefined') ElementPlus.ElMessage.error('删除失败'); } }; const openSummaryDialog = () => { showSummaryDialog.value = true; if (!summaryText.value) { fetchDouyinSummary(); } }; const handleSummaryClose = () => { showSummaryDialog.value = false; }; const fetchDouyinSummary = async () => { if (summaryLoading.value) return; summaryText.value = ""; summaryLoading.value = true; try { const response = await fetch(apiBase.value + "/api/douyin/summary", { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ids: []}) }); if (!response.body) return; const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const {done, value} = await reader.read(); if (done) break; const chunk = decoder.decode(value, {stream: true}); summaryText.value += chunk; } } catch (e) { console.error(e); summaryText.value += "\n(总结过程出错: " + e.message + ")"; } finally { summaryLoading.value = false; } }; const statusColor = (status) => { switch(status) { case 'COMPLETED': return '#10b981'; case 'FAILED': return '#ef4444'; case 'PROCESSING': return '#3b82f6'; default: return '#9ca3af'; } }; const statusType = (status) => { switch(status) { case 'COMPLETED': return 'success'; case 'FAILED': return 'danger'; case 'PROCESSING': return 'primary'; default: return 'info'; } }; const formatDate = (dateStr) => { if (!dateStr) return ''; return new Date(dateStr).toLocaleString(); }; onMounted(() => { fetchDouyinRecords(); if (douyinTimer) clearInterval(douyinTimer); douyinTimer = setInterval(() => { fetchDouyinRecords(); }, 3000); }); return { shareText, douyinLoading, douyinRecords, startParsing, fetchDouyinRecords, deleteRecord, statusColor, statusType, formatDate, showSummaryDialog, summaryLoading, summaryText, renderedSummary, openSummaryDialog, handleSummaryClose, fetchDouyinSummary }; } }).use(ElementPlus).mount("#app");