257 lines
8.7 KiB
JavaScript
257 lines
8.7 KiB
JavaScript
// 課程報表 - 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();
|
|
}
|
|
}
|
|
});
|
|
})();
|