// 課程報表 - Vue.js 應用程式 // 檔案位置:Scripts/ClassesReport.js // ======================================== (() => { 'use strict'; new Vue({ el: '#classesReportApp', data: { // API apiName: 'ClassesService', // 搜尋條件 search: { courseCode: '', courseName: '', courseDate1: '', courseDate2: '', courseLocation: '', projectID: '', projectName: '', closed: '', timeFormat: 'datetime' }, // 搜尋結果 classes: [], loading: false, // 分頁 currentPage: 1, pageSize: 20, totalCount: 0, // 專案自動完成 projectSuggestions: [], showProjectSuggestions: false, projectSearchTimeout: null, // 匯出 exporting: false, exportingId: 0 }, computed: { totalPages() { return Math.ceil(this.totalCount / this.pageSize); } }, mounted() { console.log('[ClassesReport] Vue app mounted'); // 初始載入資料 this.performSearch(); }, methods: { /** * 執行搜尋 */ async performSearch() { this.currentPage = 1; await this.fetchClasses(); }, /** * 查詢課程列表 */ async fetchClasses() { this.loading = true; try { const response = await this.$api.call(this.apiName, 'SearchClasses', { pageIndex: this.currentPage, pageSize: this.pageSize, courseCode: this.search.courseCode, courseName: this.search.courseName, courseDate1: this.search.courseDate1 || null, courseDate2: this.search.courseDate2 || null, courseLocation: this.search.courseLocation, projectID: this.search.projectID, closed: this.search.closed === '' ? null : this.search.closed === 'true' }); if (response.Success) { this.classes = response.Data || []; this.totalCount = response.TotalCount || 0; console.log('[ClassesReport] 載入成功,共 ' + this.totalCount + ' 筆'); } else { this.$message.error(response.Message || '查詢失敗'); this.classes = []; this.totalCount = 0; } } catch (error) { console.error('[ClassesReport] 載入錯誤:', error); this.$message.error('載入資料發生錯誤'); this.classes = []; this.totalCount = 0; } finally { this.loading = false; } }, /** * 清除搜尋條件 */ clearSearch() { this.search = { courseCode: '', courseName: '', courseDate1: '', courseDate2: '', courseLocation: '', projectID: '', projectName: '', closed: '', timeFormat: 'datetime' }; this.performSearch(); }, /** * 搜尋專案 */ searchProjects(event) { const query = this.search.projectName.trim(); if (query.length === 0) { this.projectSuggestions = []; return; } clearTimeout(this.projectSearchTimeout); this.projectSearchTimeout = setTimeout(async () => { try { const response = await this.$api.call(this.apiName, 'SearchProjects', { keyword: query }); if (response.Success) { this.projectSuggestions = response.Data || []; } else { this.projectSuggestions = []; } } catch (error) { console.error('[ClassesReport] 搜尋專案出錯:', error); this.projectSuggestions = []; } }, 300); }, /** * 選擇專案 */ selectProject(project) { this.search.projectID = project.Value; this.search.projectName = project.Value + ' ' + project.Name; this.projectSuggestions = []; this.showProjectSuggestions = false; }, /** * 隱藏專案建議 */ hideProjectSuggestions() { setTimeout(() => { this.showProjectSuggestions = false; }, 200); }, /** * 上一頁 */ previousPage() { if (this.currentPage > 1) { this.currentPage--; this.fetchClasses(); } }, /** * 下一頁 */ nextPage() { if (this.currentPage < this.totalPages) { this.currentPage++; this.fetchClasses(); } }, /** * 匯出報表 */ async exportReport(courseID) { if (this.exporting) { return; } this.exporting = true; this.exportingId = courseID; try { const response = await this.$api.call(this.apiName, 'ExportClassesReport', { classesID: courseID, timeFormat: this.search.timeFormat }); if (response.Success) { // 下載檔案 const fileBase64 = response.Data.FileBase64; const fileName = response.Data.FileName; const byteCharacters = atob(fileBase64); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); // 建立下載連結 const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); this.$message.success('匯出成功'); } else { this.$message.error('匯出失敗:' + response.Message); } } catch (error) { console.error('[ClassesReport] 匯出報表出錯:', error); this.$message.error('匯出報表出錯:' + error.message); } finally { this.exporting = false; this.exportingId = 0; } }, /** * 呼叫後端 WebService */ async callWebService(methodName, params) { const url = `${this.apiName}.asmx/${methodName}`; const options = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }; const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } } }); })();