初始化鸿蒙应用展示平台项目 - 前后端分离架构
This commit is contained in:
965
templates/admin_wiki.html
Executable file
965
templates/admin_wiki.html
Executable file
@@ -0,0 +1,965 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Wiki 管理{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- 引入相关CSS和JS -->
|
||||
<link href="{{ url_for('static', filename='libs/quill/quill.snow.css') }}" rel="stylesheet">
|
||||
<script src="{{ url_for('static', filename='libs/highlight/highlight.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/highlight/languages/javascript.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/highlight/languages/python.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/highlight/languages/bash.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/highlight/languages/xml.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='libs/quill/quill.min.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'admin_nav.html' %}
|
||||
<div class="admin-wiki-container">
|
||||
<h1 class="page-title">添加 Wiki 条目</h1>
|
||||
|
||||
<div class="add-entry-section">
|
||||
<h2>添加新条目</h2>
|
||||
<form id="addEntryForm" class="entry-form" enctype="multipart/form-data">
|
||||
<div class="wiki-editor-container">
|
||||
<div class="wiki-editor-sidebar">
|
||||
<div class="form-group">
|
||||
<label for="title">标题</label>
|
||||
<input type="text" id="title" name="title" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="version">版本</label>
|
||||
<input type="text" id="version" name="version" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>条目类型</label>
|
||||
<select id="wiki-type" class="form-control" required>
|
||||
<option value="">选择条目类型</option>
|
||||
<!-- 动态加载的选项将在这里生成 -->
|
||||
</select>
|
||||
<div id="selected-category-display" class="mt-2 text-muted"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wiki-editor-main">
|
||||
<div class="form-group">
|
||||
<label for="content">内容</label>
|
||||
<div id="content-editor" class="editor"></div>
|
||||
<input type="hidden" id="content" name="content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary">添加条目</button>
|
||||
<!-- 隐藏的分类字段 -->
|
||||
<input type="hidden" id="first-level" name="first_level">
|
||||
<input type="hidden" id="second-level" name="second_level">
|
||||
<input type="hidden" id="third-level" name="third_level">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 新增样式 */
|
||||
.wiki-editor-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.wiki-editor-sidebar {
|
||||
width: 250px;
|
||||
background: #f9fafb;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.wiki-editor-main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.wiki-editor-sidebar .form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wiki-editor-sidebar .form-group label {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.wiki-editor-sidebar .form-group input,
|
||||
.wiki-editor-sidebar .form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
[data-theme="dark"] .wiki-editor-sidebar {
|
||||
background: #1f2937;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .wiki-editor-sidebar .form-group input,
|
||||
[data-theme="dark"] .wiki-editor-sidebar .form-group select {
|
||||
background: #111827;
|
||||
border-color: #374151;
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media (max-width: 768px) {
|
||||
.wiki-editor-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.wiki-editor-sidebar {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 容器布局 */
|
||||
.admin-wiki-container {
|
||||
margin-left: 250px;
|
||||
padding: 20px;
|
||||
min-height: 100vh;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.admin-wiki-container {
|
||||
margin-left: 0;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 二级导航栏样式 */
|
||||
.wiki-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
margin: -20px -20px 20px -20px;
|
||||
padding: 15px 20px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
background: linear-gradient(120deg, #3b82f6, #2563eb);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.wiki-nav {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
border-radius: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
color: #3b82f6;
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
color: #3b82f6;
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.nav-item i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 编辑器样式 */
|
||||
.editor {
|
||||
height: 400px;
|
||||
margin-bottom: 20px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.ql-toolbar.ql-snow {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.ql-container.ql-snow {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
/* 表单样式 */
|
||||
.add-entry-section {
|
||||
background: #fff;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.add-entry-section h2 {
|
||||
margin: 0 0 20px 0;
|
||||
font-size: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.entry-form {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="file"] {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wiki-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #007AFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #f8f9fa;
|
||||
color: #333;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
[data-theme="dark"] .wiki-header {
|
||||
background: rgba(26, 26, 26, 0.9);
|
||||
border-bottom-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .wiki-nav {
|
||||
border-bottom-color: #333;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .nav-item {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .nav-item:hover {
|
||||
color: #3b82f6;
|
||||
background: rgba(59, 130, 246, 0.15);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .nav-item.active {
|
||||
color: #3b82f6;
|
||||
background: rgba(59, 130, 246, 0.15);
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media (max-width: 768px) {
|
||||
.wiki-header {
|
||||
position: static;
|
||||
margin: -15px -15px 15px -15px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.admin-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.wiki-nav {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0 0 30px 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.entry-count {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .page-title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .entry-count {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.image-upload-container {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.image-upload-area {
|
||||
border: 2px dashed #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.image-upload-area:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.image-input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload-placeholder {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.upload-placeholder i {
|
||||
font-size: 32px;
|
||||
margin-bottom: 10px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.upload-placeholder p {
|
||||
margin: 5px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.upload-hint {
|
||||
font-size: 14px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.image-preview-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||
gap: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 1;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.preview-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.preview-remove {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 12px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.preview-remove:hover {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
[data-theme="dark"] .image-upload-area {
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .image-upload-area:hover {
|
||||
border-color: #3b82f6;
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .preview-item {
|
||||
background: #1f2937;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .upload-placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .upload-placeholder i {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.custom-modal {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
z-index: 1000;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.custom-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 999;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-modal-content {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.custom-modal-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .custom-modal {
|
||||
background: #2c2c2c;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="customModalOverlay" class="custom-modal-overlay">
|
||||
<div class="custom-modal">
|
||||
<div id="customModalContent" class="custom-modal-content"></div>
|
||||
<div class="custom-modal-actions">
|
||||
<button id="customModalConfirm" class="btn-primary">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('=== 页面加载完成,开始初始化分类选择 ===');
|
||||
|
||||
// 获取关键元素
|
||||
const wikiTypeSelect = document.getElementById('wiki-type');
|
||||
const selectedCategoryDisplay = document.getElementById('selected-category-display');
|
||||
const firstLevelInput = document.getElementById('first-level');
|
||||
const secondLevelInput = document.getElementById('second-level');
|
||||
const thirdLevelInput = document.getElementById('third-level');
|
||||
|
||||
// 详细的元素存在性检查
|
||||
console.log('元素检查:', {
|
||||
wikiTypeSelect: !!wikiTypeSelect,
|
||||
selectedCategoryDisplay: !!selectedCategoryDisplay,
|
||||
firstLevelInput: !!firstLevelInput,
|
||||
secondLevelInput: !!secondLevelInput,
|
||||
thirdLevelInput: !!thirdLevelInput
|
||||
});
|
||||
|
||||
// 如果任何关键元素缺失,立即退出
|
||||
if (!wikiTypeSelect || !selectedCategoryDisplay ||
|
||||
!firstLevelInput || !secondLevelInput || !thirdLevelInput) {
|
||||
console.error('未找到必要的页面元素,分类加载终止');
|
||||
return;
|
||||
}
|
||||
|
||||
// 分类加载函数
|
||||
async function loadWikiCategories() {
|
||||
try {
|
||||
const response = await fetch('/admin/wiki/categories', {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('获取分类失败:', response.statusText);
|
||||
return;
|
||||
}
|
||||
|
||||
const categories = await response.json();
|
||||
console.log('获取到的分类数据:', categories);
|
||||
|
||||
// 按一级分类分组
|
||||
const groupedCategories = {};
|
||||
categories.forEach(category => {
|
||||
const { first_level, second_level, third_level } = category;
|
||||
|
||||
if (!groupedCategories[first_level]) {
|
||||
groupedCategories[first_level] = {};
|
||||
}
|
||||
|
||||
if (!groupedCategories[first_level][second_level]) {
|
||||
groupedCategories[first_level][second_level] = [];
|
||||
}
|
||||
|
||||
groupedCategories[first_level][second_level].push(third_level);
|
||||
});
|
||||
|
||||
const wikiTypeSelect = document.getElementById('wiki-type');
|
||||
wikiTypeSelect.innerHTML = ''; // 清空现有选项
|
||||
|
||||
// 动态生成分类选项
|
||||
Object.entries(groupedCategories).forEach(([firstLevel, secondLevels]) => {
|
||||
const firstLevelOptgroup = document.createElement('optgroup');
|
||||
firstLevelOptgroup.label = firstLevel;
|
||||
|
||||
Object.entries(secondLevels).forEach(([secondLevel, thirdLevels]) => {
|
||||
thirdLevels.forEach(thirdLevel => {
|
||||
const option = document.createElement('option');
|
||||
option.value = `${firstLevel} - ${secondLevel} - ${thirdLevel}`;
|
||||
option.textContent = `${firstLevel} - ${secondLevel} - ${thirdLevel}`;
|
||||
firstLevelOptgroup.appendChild(option);
|
||||
});
|
||||
});
|
||||
|
||||
wikiTypeSelect.appendChild(firstLevelOptgroup);
|
||||
});
|
||||
|
||||
console.log('分类数据处理完成');
|
||||
} catch (error) {
|
||||
console.error('加载分类时发生错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理分类选择的函数
|
||||
function handleCategorySelection() {
|
||||
console.log('handleCategorySelection 被调用');
|
||||
|
||||
// 确保选择了有效选项
|
||||
if (wikiTypeSelect.selectedIndex < 0) {
|
||||
console.warn('未选择有效选项');
|
||||
|
||||
selectedCategoryDisplay.textContent = '请选择分类';
|
||||
|
||||
// 清空隐藏字段
|
||||
firstLevelInput.value = '';
|
||||
secondLevelInput.value = '';
|
||||
thirdLevelInput.value = '';
|
||||
|
||||
selectedCategoryDisplay.style.color = '#6b7280';
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedOption = wikiTypeSelect.options[wikiTypeSelect.selectedIndex];
|
||||
console.log('选中的选项:', selectedOption);
|
||||
|
||||
// 安全地解析选择的分类
|
||||
try {
|
||||
// 直接使用 value 属性,不再假设使用下划线分隔
|
||||
const categoryParts = selectedOption.value.split(' - ');
|
||||
|
||||
// 检查分类是否完整
|
||||
if (categoryParts.length !== 3) {
|
||||
throw new Error('分类格式不正确');
|
||||
}
|
||||
|
||||
const [firstLevel, secondLevel, thirdLevel] = categoryParts;
|
||||
console.log('解析后的分类:', { firstLevel, secondLevel, thirdLevel });
|
||||
|
||||
// 验证分类不为空
|
||||
if (!firstLevel || !secondLevel || !thirdLevel) {
|
||||
throw new Error('分类不能为空');
|
||||
}
|
||||
|
||||
// 更新隐藏字段
|
||||
firstLevelInput.value = firstLevel;
|
||||
secondLevelInput.value = secondLevel;
|
||||
thirdLevelInput.value = thirdLevel;
|
||||
|
||||
// 更新显示的分类信息
|
||||
const displayText = `${firstLevel} - ${secondLevel} - ${thirdLevel}`;
|
||||
selectedCategoryDisplay.textContent = displayText;
|
||||
|
||||
// 样式增强
|
||||
selectedCategoryDisplay.style.color = '#3b82f6';
|
||||
selectedCategoryDisplay.style.fontWeight = '600';
|
||||
selectedCategoryDisplay.style.fontSize = '0.875rem';
|
||||
|
||||
} catch (error) {
|
||||
console.error('分类选择错误:', error);
|
||||
|
||||
// 重置显示
|
||||
selectedCategoryDisplay.textContent = '分类选择错误';
|
||||
selectedCategoryDisplay.style.color = '#dc3545';
|
||||
|
||||
// 清空隐藏字段
|
||||
firstLevelInput.value = '';
|
||||
secondLevelInput.value = '';
|
||||
thirdLevelInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 添加 change 事件监听器
|
||||
wikiTypeSelect.addEventListener('change', handleCategorySelection);
|
||||
|
||||
// 调用分类加载函数
|
||||
loadWikiCategories();
|
||||
|
||||
// 额外的调试函数
|
||||
function debugCategoryLoading() {
|
||||
console.log('=== 分类加载调试 ===');
|
||||
fetch('/admin/wiki/categories', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('完整响应对象:', response);
|
||||
console.log('响应状态:', response.status);
|
||||
console.log('响应状态文本:', response.statusText);
|
||||
|
||||
// 记录所有响应头
|
||||
console.log('响应头:');
|
||||
for (let [key, value] of response.headers.entries()) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('=== 分类数据详细信息 ===');
|
||||
console.log('是否成功:', data.success);
|
||||
console.log('分类总数:', data.total_count);
|
||||
console.log('分类详情:', data.categories);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('分类加载调试失败:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 立即执行调试
|
||||
debugCategoryLoading();
|
||||
});
|
||||
|
||||
// 在页面加载时,默认选择第一个选项
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const wikiTypeSelect = document.getElementById('wiki-type');
|
||||
if (wikiTypeSelect && wikiTypeSelect.options.length > 0) {
|
||||
// 选择第一个 option
|
||||
wikiTypeSelect.selectedIndex = 0;
|
||||
// 触发 change 事件以更新分类显示
|
||||
wikiTypeSelect.dispatchEvent(new Event('change'));
|
||||
}
|
||||
});
|
||||
|
||||
// 自定义弹窗函数
|
||||
function showCustomModal(options) {
|
||||
const overlay = document.getElementById('customModalOverlay');
|
||||
const content = document.getElementById('customModalContent');
|
||||
const confirmBtn = document.getElementById('customModalConfirm');
|
||||
|
||||
// 设置内容
|
||||
content.innerHTML = `
|
||||
<h3>${options.title || '提示'}</h3>
|
||||
<p>${options.text || ''}</p>
|
||||
`;
|
||||
|
||||
// 设置样式
|
||||
content.parentElement.style.backgroundColor = options.type === 'success' ? '#e6f3e6' : '#f8d7da';
|
||||
confirmBtn.style.backgroundColor = options.type === 'success' ? '#28a745' : '#dc3545';
|
||||
|
||||
// 显示弹窗
|
||||
overlay.style.display = 'block';
|
||||
|
||||
// 确认按钮事件
|
||||
const handleConfirm = () => {
|
||||
overlay.style.display = 'none';
|
||||
confirmBtn.removeEventListener('click', handleConfirm);
|
||||
|
||||
// 执行关闭回调
|
||||
if (options.didClose) {
|
||||
options.didClose();
|
||||
}
|
||||
};
|
||||
|
||||
confirmBtn.addEventListener('click', handleConfirm);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Quill 工具栏配置
|
||||
const toolbarOptions = [
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
['blockquote', 'code-block'],
|
||||
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
|
||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||
[{ 'script': 'sub'}, { 'script': 'super' }],
|
||||
[{ 'indent': '-1'}, { 'indent': '+1' }],
|
||||
[{ 'direction': 'rtl' }],
|
||||
[{ 'color': [] }, { 'background': [] }],
|
||||
[{ 'font': [] }],
|
||||
[{ 'align': [] }],
|
||||
['clean'],
|
||||
['link', 'image', 'video']
|
||||
];
|
||||
|
||||
// 确保编辑器容器存在
|
||||
const editorContainer = document.getElementById('content-editor');
|
||||
const hiddenContentInput = document.getElementById('content');
|
||||
|
||||
if (!editorContainer || !hiddenContentInput) {
|
||||
console.error('富文本编辑器的必要元素未找到');
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化 Quill 编辑器
|
||||
const editor = new Quill('#content-editor', {
|
||||
modules: {
|
||||
toolbar: {
|
||||
container: toolbarOptions,
|
||||
handlers: {
|
||||
// 自定义链接处理
|
||||
link: function(value) {
|
||||
if (value) {
|
||||
const range = this.quill.getSelection();
|
||||
if (range) {
|
||||
let url = prompt('请输入链接URL:');
|
||||
if (url) {
|
||||
if (!/^https?:\/\//i.test(url)) {
|
||||
url = 'http://' + url;
|
||||
}
|
||||
this.quill.format('link', url);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.quill.format('link', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
syntax: {
|
||||
highlight: (text) => hljs.highlightAuto(text).value
|
||||
}
|
||||
},
|
||||
theme: 'snow'
|
||||
});
|
||||
|
||||
// 同步编辑器内容到隐藏输入框
|
||||
editor.on('text-change', function() {
|
||||
// 将编辑器内容转换为 JSON 格式
|
||||
const content = editor.getContents();
|
||||
hiddenContentInput.value = JSON.stringify(content);
|
||||
});
|
||||
|
||||
// 调试:检查编辑器是否正确初始化
|
||||
console.log('Quill 编辑器初始化:', {
|
||||
editor: !!editor,
|
||||
container: editorContainer,
|
||||
hiddenInput: hiddenContentInput
|
||||
});
|
||||
|
||||
// 可选:如果需要预填充内容
|
||||
try {
|
||||
// 尝试从隐藏输入框读取初始内容
|
||||
const initialContent = hiddenContentInput.value;
|
||||
if (initialContent) {
|
||||
const parsedContent = JSON.parse(initialContent);
|
||||
editor.setContents(parsedContent);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('初始内容解析失败:', error);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 表单提交处理
|
||||
const addEntryForm = document.getElementById('addEntryForm');
|
||||
|
||||
if (!addEntryForm) {
|
||||
console.error('未找到表单元素 #addEntryForm');
|
||||
return;
|
||||
}
|
||||
|
||||
addEntryForm.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// 获取表单元素
|
||||
const titleInput = document.getElementById('title');
|
||||
const versionInput = document.getElementById('version');
|
||||
const contentInput = document.getElementById('content');
|
||||
const firstLevelInput = document.getElementById('first-level');
|
||||
const secondLevelInput = document.getElementById('second-level');
|
||||
const thirdLevelInput = document.getElementById('third-level');
|
||||
|
||||
// 验证表单数据
|
||||
if (!titleInput || !versionInput || !contentInput ||
|
||||
!firstLevelInput || !secondLevelInput || !thirdLevelInput) {
|
||||
console.error('表单元素缺失');
|
||||
showCustomModal({
|
||||
title: '错误',
|
||||
text: '表单元素未正确加载,请刷新页面',
|
||||
type: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
const formData = {
|
||||
title: titleInput.value.trim(),
|
||||
version: versionInput.value.trim(),
|
||||
content: contentInput.value,
|
||||
first_level: firstLevelInput.value,
|
||||
second_level: secondLevelInput.value,
|
||||
third_level: thirdLevelInput.value
|
||||
};
|
||||
|
||||
// 数据验证
|
||||
const validationErrors = [];
|
||||
if (!formData.title) validationErrors.push('标题不能为空');
|
||||
if (!formData.version) validationErrors.push('版本不能为空');
|
||||
if (!formData.content) validationErrors.push('内容不能为空');
|
||||
if (!formData.first_level || !formData.second_level || !formData.third_level) {
|
||||
validationErrors.push('请选择完整的分类');
|
||||
}
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
showCustomModal({
|
||||
title: '表单验证错误',
|
||||
text: validationErrors.join('<br>'),
|
||||
type: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/admin/wiki/add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showCustomModal({
|
||||
title: '成功',
|
||||
text: 'Wiki 条目添加成功',
|
||||
type: 'success',
|
||||
didClose: () => {
|
||||
// 可选:重置表单或跳转
|
||||
addEntryForm.reset();
|
||||
window.location.href = '/admin/wiki';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showCustomModal({
|
||||
title: '错误',
|
||||
text: result.error || '添加 Wiki 条目失败',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交表单时发生错误:', error);
|
||||
showCustomModal({
|
||||
title: '网络错误',
|
||||
text: '无法提交表单,请检查网络连接',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user