| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 | <!DOCTYPE html><html lang="zh-CN"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Project管理系统</title>    <!-- 引入Tailwind CSS -->    <script src="https://cdn.tailwindcss.com"></script>    <!-- 引入Font Awesome -->    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">        <!-- 配置Tailwind自定义颜色 -->    <script>        tailwind.config = {            theme: {                extend: {                    colors: {                        primary: '#3B82F6',                        secondary: '#10B981',                        danger: '#EF4444',                        neutral: '#64748B',                    },                    fontFamily: {                        sans: ['Inter', 'system-ui', 'sans-serif'],                    },                }            }        }    </script>        <!-- 自定义工具类 -->    <style type="text/tailwindcss">        @layer utilities {            .content-auto {                content-visibility: auto;            }            .card-shadow {                box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);            }            .transition-custom {                transition: all 0.3s ease;            }        }    </style></head><body class="bg-gray-50 min-h-screen">    <div class="container mx-auto px-4 py-8 max-w-6xl">        <header class="mb-10 text-center">            <h1 class="text-[clamp(1.8rem,4vw,2.5rem)] font-bold text-gray-800 mb-2">Project管理系统</h1>            <p class="text-gray-600">通过网络请求实现Project对象的增删查改操作</p>        </header>                <!-- 主要内容区 -->        <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">            <!-- 左侧:添加/编辑项目表单 -->            <div class="lg:col-span-1">                <div class="bg-white rounded-xl p-6 card-shadow">                    <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">                        <i class="fa fa-plus-circle text-primary mr-2"></i>                        <span id="formTitle">添加新项目</span>                    </h2>                                        <form id="projectForm" class="space-y-4">                        <input type="hidden" id="projectId">                                                <div>                            <label for="title" class="block text-sm font-medium text-gray-700 mb-1">项目标题</label>                            <input type="text" id="title"                                    class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-custom"                                   placeholder="请输入项目标题" required>                        </div>                                                <div>                            <label for="duration" class="block text-sm font-medium text-gray-700 mb-1">项目时长(天)</label>                            <input type="number" id="duration" min="1"                                    class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-custom"                                   placeholder="请输入项目时长" required>                        </div>                                                <div class="flex gap-3 pt-2">                            <button type="submit" id="submitBtn"                                     class="flex-1 bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-custom flex items-center justify-center">                                <i class="fa fa-save mr-2"></i> 保存项目                            </button>                            <button type="button" id="cancelBtn"                                     class="hidden bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-lg transition-custom">                                取消                            </button>                        </div>                    </form>                </div>                                <!-- 查询区域 -->                <div class="bg-white rounded-xl p-6 card-shadow mt-6">                    <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">                        <i class="fa fa-search text-primary mr-2"></i>                        查询项目                    </h2>                                        <div class="space-y-4">                        <button onclick="queryAllProjects()"                                 class="w-full bg-gray-100 hover:bg-gray-200 text-gray-800 font-medium py-2 px-4 rounded-lg transition-custom flex items-center justify-center">                            <i class="fa fa-list mr-2"></i> 查询所有项目                        </button>                                                <div>                            <label for="searchTitle" class="block text-sm font-medium text-gray-700 mb-1">按标题查询</label>                            <div class="flex">                                <input type="text" id="searchTitle"                                        class="flex-1 px-4 py-2 border border-gray-300 rounded-l-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-custom"                                       placeholder="请输入项目标题">                                <button onclick="queryProjectByTitle()"                                         class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-r-lg transition-custom">                                    <i class="fa fa-search"></i>                                </button>                            </div>                        </div>                                                <div>                            <label for="searchRegex" class="block text-sm font-medium text-gray-700 mb-1">按标题前缀查询</label>                            <div class="flex">                                <input type="text" id="searchRegex"                                        class="flex-1 px-4 py-2 border border-gray-300 rounded-l-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-custom"                                       placeholder="请输入标题前缀">                                <button onclick="queryProjectByRegex()"                                         class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-r-lg transition-custom">                                    <i class="fa fa-search"></i>                                </button>                            </div>                        </div>                    </div>                </div>            </div>                        <!-- 右侧:项目列表 -->            <div class="lg:col-span-2">                <div class="bg-white rounded-xl p-6 card-shadow h-full">                    <h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">                        <i class="fa fa-table text-primary mr-2"></i>                        项目列表                    </h2>                                        <div id="loading" class="hidden text-center py-10">                        <i class="fa fa-spinner fa-spin text-2xl text-primary"></i>                        <p class="mt-2 text-gray-600">加载中...</p>                    </div>                                        <div id="emptyState" class="text-center py-16 hidden">                        <i class="fa fa-folder-open-o text-4xl text-gray-300 mb-4"></i>                        <p class="text-gray-500">暂无项目数据,请添加项目或查询数据</p>                    </div>                                        <div id="errorState" class="text-center py-16 hidden">                        <i class="fa fa-exclamation-triangle text-4xl text-yellow-500 mb-4"></i>                        <p class="text-gray-500" id="errorMessage">加载数据时发生错误</p>                    </div>                                        <div id="projectList" class="overflow-x-auto">                        <table class="min-w-full divide-y divide-gray-200">                            <thead>                                <tr>                                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>                                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">标题</th>                                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">时长(天)</th>                                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">创建时间</th>                                    <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>                                </tr>                            </thead>                            <tbody id="projectTableBody" class="divide-y divide-gray-200">                                <!-- 项目数据将通过JavaScript动态填充 -->                            </tbody>                        </table>                    </div>                </div>            </div>        </div>    </div>        <!-- 通知提示组件 -->    <div id="toast" class="fixed bottom-5 right-5 px-6 py-3 rounded-lg shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 flex items-center">        <i id="toastIcon" class="mr-2"></i>        <span id="toastMessage"></span>    </div>    <script>        // API基础URL        const API_BASE_URL = "http://dev.fmode.cn:1337/parse/classes/Project";        // 请求头配置        const headers = {            "accept": "*/*",            "content-type": "text/plain;charset=UTF-8",            "x-parse-application-id": "dev"        };                // DOM元素        const projectForm = document.getElementById('projectForm');        const projectIdInput = document.getElementById('projectId');        const titleInput = document.getElementById('title');        const durationInput = document.getElementById('duration');        const formTitle = document.getElementById('formTitle');        const submitBtn = document.getElementById('submitBtn');        const cancelBtn = document.getElementById('cancelBtn');        const projectTableBody = document.getElementById('projectTableBody');        const loadingIndicator = document.getElementById('loading');        const emptyState = document.getElementById('emptyState');        const errorState = document.getElementById('errorState');        const errorMessage = document.getElementById('errorMessage');        const toast = document.getElementById('toast');        const toastIcon = document.getElementById('toastIcon');        const toastMessage = document.getElementById('toastMessage');                // 初始化页面        document.addEventListener('DOMContentLoaded', () => {            // 加载所有项目            queryAllProjects();                        // 表单提交事件            projectForm.addEventListener('submit', handleFormSubmit);                        // 取消按钮事件            cancelBtn.addEventListener('click', resetForm);        });                // 显示加载状态        function showLoading() {            loadingIndicator.classList.remove('hidden');            emptyState.classList.add('hidden');            errorState.classList.add('hidden');            projectTableBody.innerHTML = '';        }                // 显示空状态        function showEmptyState() {            loadingIndicator.classList.add('hidden');            emptyState.classList.remove('hidden');            errorState.classList.add('hidden');        }                // 显示错误状态        function showError(message) {            loadingIndicator.classList.add('hidden');            emptyState.classList.add('hidden');            errorState.classList.remove('hidden');            errorMessage.textContent = message;        }                // 显示通知提示        function showToast(message, isSuccess = true) {            toastMessage.textContent = message;            toastIcon.className = isSuccess ? 'fa fa-check-circle text-green-500 mr-2' : 'fa fa-exclamation-circle text-red-500 mr-2';            toast.className = `fixed bottom-5 right-5 px-6 py-3 rounded-lg shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 flex items-center ${isSuccess ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'}`;                        // 3秒后隐藏            setTimeout(() => {                toast.className = 'fixed bottom-5 right-5 px-6 py-3 rounded-lg shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 flex items-center';            }, 3000);        }                // 重置表单        function resetForm() {            projectForm.reset();            projectIdInput.value = '';            formTitle.textContent = '添加新项目';            submitBtn.innerHTML = '<i class="fa fa-save mr-2"></i> 保存项目';            cancelBtn.classList.add('hidden');        }                // 处理表单提交        async function handleFormSubmit(e) {            e.preventDefault();                        const projectId = projectIdInput.value;            const projectData = {                title: titleInput.value.trim(),                duration: parseInt(durationInput.value)            };                        try {                if (projectId) {                    // 更新项目                    await updateProject(projectId, projectData);                    showToast('项目更新成功');                } else {                    // 创建新项目                    await createProject(projectData);                    showToast('项目创建成功');                }                                // 重置表单                resetForm();                                // 重新加载项目列表                queryAllProjects();            } catch (error) {                showToast(`操作失败: ${error.message}`, false);                console.error('操作失败:', error);            }        }                // 创建项目        async function createProject(projectData) {            const response = await fetch(API_BASE_URL, {                method: "POST",                headers: headers,                body: JSON.stringify(projectData),                mode: "cors",                credentials: "omit"            });                        if (!response.ok) {                throw new Error(`HTTP错误,状态码: ${response.status}`);            }                        return await response.json();        }                // 查询所有项目        async function queryAllProjects() {            showLoading();                        try {                const response = await fetch(API_BASE_URL, {                    method: "GET",                    headers: headers,                    mode: "cors",                    credentials: "omit"                });                                if (!response.ok) {                    throw new Error(`HTTP错误,状态码: ${response.status}`);                }                                const data = await response.json();                renderProjectList(data.results);            } catch (error) {                showError(`查询失败: ${error.message}`);                console.error('查询失败:', error);            }        }                // 按标题查询项目        async function queryProjectByTitle() {            const title = document.getElementById('searchTitle').value.trim();            if (!title) {                showToast('请输入项目标题', false);                return;            }                        showLoading();                        try {                // 构建查询参数,需要URL编码                const encodedTitle = encodeURIComponent(title);                const response = await fetch(`${API_BASE_URL}?where={"title":"${encodedTitle}"}`, {                    method: "GET",                    headers: headers,                    mode: "cors",                    credentials: "omit"                });                                if (!response.ok) {                    throw new Error(`HTTP错误,状态码: ${response.status}`);                }                                const data = await response.json();                renderProjectList(data.results);            } catch (error) {                showError(`查询失败: ${error.message}`);                console.error('查询失败:', error);            }        }                // 按标题前缀查询项目        async function queryProjectByRegex() {            const prefix = document.getElementById('searchRegex').value.trim();            if (!prefix) {                showToast('请输入标题前缀', false);                return;            }                        showLoading();                        try {                // 构建正则表达式查询参数                const encodedRegex = encodeURIComponent(`^${prefix}`);                const response = await fetch(`${API_BASE_URL}?where={"title":{"$regex":"${encodedRegex}"}}`, {                    method: "GET",                    headers: headers,                    mode: "cors",                    credentials: "omit"                });                                if (!response.ok) {                    throw new Error(`HTTP错误,状态码: ${response.status}`);                }                                const data = await response.json();                renderProjectList(data.results);            } catch (error) {                showError(`查询失败: ${error.message}`);                console.error('查询失败:', error);            }        }                // 更新项目        async function updateProject(projectId, projectData) {            const response = await fetch(`${API_BASE_URL}/${projectId}`, {                method: "PUT",                headers: headers,                body: JSON.stringify(projectData),                mode: "cors",                credentials: "omit"            });                        if (!response.ok) {                throw new Error(`HTTP错误,状态码: ${response.status}`);            }                        return await response.json();        }                // 删除项目        async function deleteProject(projectId) {            if (!confirm('确定要删除这个项目吗?')) {                return;            }                        try {                const response = await fetch(`${API_BASE_URL}/${projectId}`, {                    method: "DELETE",                    headers: headers,                    mode: "cors",                    credentials: "omit"                });                                if (!response.ok) {                    throw new Error(`HTTP错误,状态码: ${response.status}`);                }                                showToast('项目删除成功');                queryAllProjects();            } catch (error) {                showToast(`删除失败: ${error.message}`, false);                console.error('删除失败:', error);            }        }                // 编辑项目        function editProject(project) {            projectIdInput.value = project.objectId;            titleInput.value = project.title;            durationInput.value = project.duration;            formTitle.textContent = '编辑项目';            submitBtn.innerHTML = '<i class="fa fa-pencil mr-2"></i> 更新项目';            cancelBtn.classList.remove('hidden');                        // 滚动到表单            projectForm.scrollIntoView({ behavior: 'smooth' });        }                // 渲染项目列表        function renderProjectList(projects) {            loadingIndicator.classList.add('hidden');                        if (!projects || projects.length === 0) {                showEmptyState();                return;            }                        projectTableBody.innerHTML = '';                        // 按创建时间排序,最新的在前            projects.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));                        projects.forEach(project => {                const row = document.createElement('tr');                row.className = 'hover:bg-gray-50 transition-custom';                                // 格式化日期                const formattedDate = new Date(project.createdAt).toLocaleString();                                row.innerHTML = `                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 max-w-xs truncate">${project.objectId}</td>                    <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${project.title}</td>                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${project.duration}</td>                    <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${formattedDate}</td>                    <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">                        <button onclick="editProject(${JSON.stringify(project)})"                                 class="text-primary hover:text-primary/80 mr-4 transition-custom">                            <i class="fa fa-pencil"></i> 编辑                        </button>                        <button onclick="deleteProject('${project.objectId}')"                                 class="text-danger hover:text-danger/80 transition-custom">                            <i class="fa fa-trash"></i> 删除                        </button>                    </td>                `;                                projectTableBody.appendChild(row);            });        }                // 暴露函数到全局,以便在HTML中调用        window.createProject = createProject;        window.queryAllProjects = queryAllProjects;        window.queryProjectByTitle = queryProjectByTitle;        window.queryProjectByRegex = queryProjectByRegex;        window.editProject = editProject;        window.deleteProject = deleteProject;    </script></body></html>
 |