'commit'
This commit is contained in:
202
static/js/douyin.js
Normal file
202
static/js/douyin.js
Normal file
@@ -0,0 +1,202 @@
|
||||
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, '<strong>$1</strong>') // Bold
|
||||
.replace(/`(.*?)`/g, '<code style="background:#f1f5f9; padding:2px 4px; border-radius:4px;">$1</code>'); // Code
|
||||
};
|
||||
|
||||
for (let line of lines) {
|
||||
let trimmed = line.trim();
|
||||
if (!trimmed) continue;
|
||||
|
||||
// Headers
|
||||
if (trimmed.startsWith('### ')) {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<h3 style="margin-top:16px; margin-bottom:8px; font-weight:bold; font-size:1.1em;">${parseInline(trimmed.substring(4))}</h3>`;
|
||||
}
|
||||
// Lists
|
||||
else if (trimmed.startsWith('- ') || /^\d+\./.test(trimmed)) {
|
||||
if (!inList) { html += '<ul style="padding-left:20px; margin:0;">'; inList = true; }
|
||||
let content = trimmed.replace(/^(- |\d+\. )/, '');
|
||||
html += `<li style="margin-bottom:4px;">${parseInline(content)}</li>`;
|
||||
}
|
||||
// Paragraphs
|
||||
else {
|
||||
if (inList) { html += '</ul>'; inList = false; }
|
||||
html += `<p style="margin-bottom:8px;">${parseInline(trimmed)}</p>`;
|
||||
}
|
||||
}
|
||||
if (inList) html += '</ul>';
|
||||
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");
|
||||
Reference in New Issue
Block a user