Files
sryang 577060bc78 chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore
- 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
2026-09-10 09:42:37 +08:00

651 lines
25 KiB
JavaScript

// ========================================
// 活動管理 - Vue.js 應用程式
// 檔案位置:Scripts/ClassesList.js
// ========================================
(() => {
'use strict';
new Vue({
el: '#classesApp',
data: {
// API
apiName: 'ClassesService',
// 搜尋條件
search: {
courseCode: '',
courseName: '',
courseDate1: '',
courseDate2: '',
courseLocation: '',
projectID: '',
projectName: '',
closed: ''
},
// 搜尋結果
classes: [],
loading: false,
// 分頁
currentPage: 1,
pageSize: 20,
totalCount: 0,
// 專案自動完成
projectSuggestions: [],
showProjectSuggestions: false,
projectSearchTimeout: null,
// 彈窗
showModal: false,
isNewMode: true,
editItem: {
ID: 0,
CourseCode: '',
CourseName: '',
CourseDate: '',
CourseLocation: '',
StartTime: '',
EndTime: '',
Teacher: '',
projectID: '',
projectName: '',
NotificationTitle: '',
NotificationTemplate: '',
AgreedTerms: '',
Closed: false,
DB_APPNO: 0
},
// 編輯模式專案自動完成
editProjectSuggestions: [],
showEditProjectSuggestions: false,
editProjectSearchTimeout: null,
// 驗證錯誤訊息
validationErrors: {
CourseName: '',
CourseDate: '',
StartTime: '',
EndTime: '',
Teacher: '',
CourseLocation: '',
NotificationTitle: '',
NotificationTemplate: ''
}
},
computed: {
totalPages() {
return Math.ceil(this.totalCount / this.pageSize);
},
generatePreview() {
if (!this.editItem.NotificationTemplate) {
return '';
}
let preview = this.editItem.NotificationTemplate;
// 替換模板變數
preview = preview.replace(/{課程日期}/g, this.editItem.CourseDate ? this.editItem.CourseDate : '(課程日期未設定)');
preview = preview.replace(/{課程名稱}/g, this.editItem.CourseName || '(課程名稱未設定)');
preview = preview.replace(/{課程地點}/g, this.editItem.CourseLocation || '(課程地點未設定)');
preview = preview.replace(/{開始時間}/g, this.editItem.StartTime || '(開始時間未設定)');
preview = preview.replace(/{結束時間}/g, this.editItem.EndTime || '(結束時間未設定)');
preview = preview.replace(/{講師}/g, this.editItem.Teacher || '(講師未設定)');
preview = preview.replace(/{學員姓名}/g, '(學員姓名)');
return preview;
}
},
mounted() {
console.log('[ClassesList] Vue app mounted');
// 初始載入資料
this.performSearch();
},
methods: {
/**
* 執行搜尋
*/
async performSearch() {
this.currentPage = 1;
await this.loadClasses();
},
/**
* 載入活動資料
*/
async loadClasses() {
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
});
if (response.Success) {
this.classes = (response.Data || []);
this.totalCount = response.TotalCount || 0;
console.log('[ClassesList] 載入成功,共 ' + this.totalCount + ' 筆');
} else {
this.$message.error(response.Message || '查詢失敗');
this.classes = [];
this.totalCount = 0;
}
} catch (error) {
console.error('[ClassesList] 載入錯誤:', error);
this.$message.error('載入資料發生錯誤');
this.classes = [];
this.totalCount = 0;
} finally {
this.loading = false;
}
},
/**
* 清除搜尋條件
*/
clearSearch() {
this.search = {
courseCode: '',
courseName: '',
courseDate1: '',
courseDate2: '',
courseLocation: '',
projectID: '',
projectName: '',
closed: ''
};
this.projectSuggestions = [];
this.showProjectSuggestions = false;
this.performSearch();
},
/**
* 換頁
*/
goToPage(page) {
if (page < 1 || page > this.totalPages) return;
this.currentPage = page;
this.loadClasses();
},
/**
* 格式化專案資訊 (編號 - 名稱)
*/
formatProjectInfo(item) {
if (!item.ProjectID) return '';
return item.ProjectName
? `${item.ProjectID} - ${item.ProjectName}`
: item.ProjectID;
},
/**
* 開啟新增彈窗
*/
openAddModal() {
this.isNewMode = true;
this.editItem = {
ID: 0,
CourseCode: '(自動產生)',
CourseName: '',
CourseDate: '',
CourseLocation: '',
StartTime: '',
EndTime: '',
Teacher: '',
projectID: '',
projectName: '',
NotificationTitle: '',
NotificationTemplate: '',
AgreedTerms: '',
Closed: false,
DB_APPNO: 0
};
this.editProjectSuggestions = [];
this.showEditProjectSuggestions = false;
this.clearValidationErrors();
this.showModal = true;
},
/**
* 開啟更正彈窗
*/
openEditModal(item) {
this.isNewMode = false;
const projectDisplay = item.ProjectID && item.ProjectName
? `${item.ProjectID} - ${item.ProjectName}`
: (item.ProjectID || '');
this.editItem = {
ID: item.ID,
CourseCode: item.CourseCode,
CourseName: item.CourseName,
CourseDate: this.$format.date(item.CourseDate),
CourseLocation: item.CourseLocation || '',
StartTime: item.StartTime || '',
EndTime: item.EndTime || '',
Teacher: item.Teacher || '',
projectID: item.ProjectID || '',
projectName: projectDisplay,
NotificationTitle: item.NotificationTitle || '',
NotificationTemplate: item.NotificationTemplate || '',
AgreedTerms: item.AgreedTerms || '',
Closed: item.Closed,
DB_APPNO: item.DB_APPNO
};
this.editProjectSuggestions = [];
this.showEditProjectSuggestions = false;
this.clearValidationErrors();
this.showModal = true;
},
/**
* 關閉彈窗
*/
closeModal() {
this.showModal = false;
},
/**
* 插入模板文字
*/
insertTemplate(text) {
const textarea = this.$refs.templateTextarea;
if (!textarea) return;
const startPos = textarea.selectionStart;
const endPos = textarea.selectionEnd;
const currentValue = this.editItem.NotificationTemplate || '';
// 在游標位置插入文字
this.editItem.NotificationTemplate =
currentValue.substring(0, startPos) +
text +
currentValue.substring(endPos);
// 設定游標位置
this.$nextTick(() => {
textarea.selectionStart = textarea.selectionEnd = startPos + text.length;
textarea.focus();
});
},
/**
* 清除驗證錯誤訊息
*/
clearValidationErrors() {
this.validationErrors = {
CourseName: '',
CourseDate: '',
StartTime: '',
EndTime: '',
Teacher: '',
CourseLocation: '',
NotificationTitle: '',
NotificationTemplate: ''
};
},
/**
* 搜尋專案 (自動完成)
*/
searchProjects() {
// 清除之前的超時
if (this.projectSearchTimeout) {
clearTimeout(this.projectSearchTimeout);
}
const keyword = this.search.projectName.trim();
// 如果輸入為空,清空建議和ProjectID
if (!keyword) {
this.projectSuggestions = [];
this.search.projectID = '';
return;
}
// 延遲搜尋以避免過多API呼叫
this.projectSearchTimeout = setTimeout(async () => {
try {
const response = await this.$api.call(this.apiName, 'SearchProjects', {
keyword: keyword
});
if (response.Success) {
this.projectSuggestions = response.Data || [];
this.showProjectSuggestions = this.projectSuggestions.length > 0;
} else {
this.projectSuggestions = [];
this.showProjectSuggestions = false;
}
} catch (error) {
console.error('[ClassesList] 搜尋專案錯誤:', error);
this.projectSuggestions = [];
this.showProjectSuggestions = false;
}
}, 300);
},
/**
* 選擇專案
*/
selectProject(suggestion) {
this.search.projectID = suggestion.Value;
this.search.projectName = `${suggestion.Value} - ${suggestion.Name}`;
this.projectSuggestions = [];
this.showProjectSuggestions = false;
},
/**
* 隱藏專案建議 (延遲隱藏以允許點擊)
*/
hideProjectSuggestions() {
setTimeout(() => {
this.showProjectSuggestions = false;
}, 200);
},
/**
* 搜尋編輯模式的專案 (自動完成)
*/
searchEditProjectSuggestions() {
// 清除之前的超時
if (this.editProjectSearchTimeout) {
clearTimeout(this.editProjectSearchTimeout);
}
const keyword = this.editItem.projectName.trim();
// 如果輸入為空,清空建議和ProjectID
if (!keyword) {
this.editProjectSuggestions = [];
this.editItem.projectID = '';
return;
}
// 延遲搜尋以避免過多API呼叫
this.editProjectSearchTimeout = setTimeout(async () => {
try {
const response = await this.$api.call(this.apiName, 'SearchProjects', {
keyword: keyword
});
if (response.Success) {
this.editProjectSuggestions = response.Data || [];
this.showEditProjectSuggestions = this.editProjectSuggestions.length > 0;
} else {
this.editProjectSuggestions = [];
this.showEditProjectSuggestions = false;
}
} catch (error) {
console.error('[ClassesList] 搜尋編輯模式專案錯誤:', error);
this.editProjectSuggestions = [];
this.showEditProjectSuggestions = false;
}
}, 300);
},
/**
* 選擇編輯模式的專案
*/
selectEditProject(suggestion) {
this.editItem.projectID = suggestion.Value;
this.editItem.projectName = `${suggestion.Value} - ${suggestion.Name}`;
this.editProjectSuggestions = [];
this.showEditProjectSuggestions = false;
},
/**
* 隱藏編輯模式的專案建議 (延遲隱藏以允許點擊)
*/
hideEditProjectSuggestions() {
setTimeout(() => {
this.showEditProjectSuggestions = false;
}, 200);
},
/**
* 驗證輸入
*/
validateInput() {
this.clearValidationErrors();
let isValid = true;
// 驗證課程名稱
if (!this.editItem.CourseName || this.editItem.CourseName.trim() === '') {
this.validationErrors.CourseName = '課程名稱為必填欄位';
isValid = false;
} else if (this.editItem.CourseName.length > 100) {
this.validationErrors.CourseName = '課程名稱最長 100 個字元';
isValid = false;
}
// 驗證課程日期
if (!this.editItem.CourseDate) {
this.validationErrors.CourseDate = '課程日期為必填欄位';
isValid = false;
}
// 驗證開始時間
if (!this.editItem.StartTime || this.editItem.StartTime.trim() === '') {
this.validationErrors.StartTime = '開始時間為必填欄位';
isValid = false;
}
// 驗證結束時間
if (!this.editItem.EndTime || this.editItem.EndTime.trim() === '') {
this.validationErrors.EndTime = '結束時間為必填欄位';
isValid = false;
}
// 驗證講師
if (!this.editItem.Teacher || this.editItem.Teacher.trim() === '') {
this.validationErrors.Teacher = '講師為必填欄位';
isValid = false;
}
// 驗證通知標題
if (this.editItem.NotificationTitle && this.editItem.NotificationTitle.length > 100) {
this.validationErrors.NotificationTitle = '通知標題最長 100 個字元';
isValid = false;
}
// 驗證通知模板
if (this.editItem.NotificationTemplate && this.editItem.NotificationTemplate.length > 500) {
this.validationErrors.NotificationTemplate = '通知模板最長 500 個字元';
isValid = false;
}
return isValid;
},
/**
* 儲存活動
*/
async saveClasses() {
if (!this.validateInput()) return;
try {
// 準備資料
const item = {
ID: this.editItem.ID,
CourseCode: this.editItem.CourseCode,
CourseName: this.editItem.CourseName.trim(),
CourseDate: this.editItem.CourseDate,
CourseLocation: this.editItem.CourseLocation,
StartTime: this.editItem.StartTime,
EndTime: this.editItem.EndTime,
Teacher: this.editItem.Teacher,
ProjectID: this.editItem.projectID,
NotificationTitle: this.editItem.NotificationTitle,
NotificationTemplate: this.editItem.NotificationTemplate,
AgreedTerms: this.editItem.AgreedTerms,
Closed: this.editItem.Closed,
DB_APPNO: this.editItem.DB_APPNO
};
const response = await this.$api.call(this.apiName, 'SaveClasses', {
isNew: this.isNewMode,
item: item
});
if (response.Success) {
this.$message.success(response.Message || '儲存成功');
this.closeModal();
this.loadClasses();
} else {
this.$message.error(response.Message || '儲存失敗');
}
} catch (error) {
console.error('[ClassesList] 儲存錯誤:', error);
this.$message.error('儲存發生錯誤');
}
},
/**
* 儲存後繼續新增
*/
async saveAndContinue() {
if (!this.validateInput()) return;
try {
// 準備資料
const item = {
ID: 0,
CourseCode: '',
CourseName: this.editItem.CourseName.trim(),
CourseDate: this.editItem.CourseDate,
CourseLocation: this.editItem.CourseLocation,
StartTime: this.editItem.StartTime,
EndTime: this.editItem.EndTime,
Teacher: this.editItem.Teacher,
ProjectID: this.editItem.projectID,
NotificationTitle: this.editItem.NotificationTitle,
NotificationTemplate: this.editItem.NotificationTemplate,
AgreedTerms: this.editItem.AgreedTerms,
Closed: this.editItem.Closed,
DB_APPNO: 0
};
const response = await this.$api.call(this.apiName, 'SaveClasses', {
isNew: true,
item: item
});
if (response.Success) {
this.$message.success(response.Message || '儲存成功');
// 清除輸入內容,重新進入新增模式
this.editItem = {
ID: 0,
CourseCode: '(自動產生)',
CourseName: '',
CourseDate: '',
CourseLocation: '',
StartTime: '',
EndTime: '',
Teacher: '',
projectID: '',
projectName: '',
NotificationTitle: '',
NotificationTemplate: '',
AgreedTerms: '',
Closed: false,
DB_APPNO: 0
};
this.loadClasses();
} else {
this.$message.error(response.Message || '儲存失敗');
}
} catch (error) {
console.error('[ClassesList] 儲存錯誤:', error);
this.$message.error('儲存發生錯誤');
}
},
/**
* 刪除活動
*/
async deleteClasses(item) {
if (!confirm(`確定要刪除活動「${item.CourseName}」嗎?`)) {
return;
}
try {
const response = await this.$api.call(this.apiName, 'DeleteClasses', {
id: item.ID,
dbAppNo: item.DB_APPNO
});
if (response.Success) {
this.$message.success(response.Message || '刪除成功');
this.loadClasses();
} else {
this.$message.error(response.Message || '刪除失敗');
}
} catch (error) {
console.error('[ClassesList] 刪除錯誤:', error);
this.$message.error('刪除發生錯誤');
}
},
/**
* 匯出活動
*/
async performExport() {
try {
// 驗證必要條件:課程日期(起)和課程日期(迄)為必填
if (!this.search.courseDate1 || !this.search.courseDate2) {
this.$message.warning('課程日期(起)和課程日期(迄)為必填欄位');
return;
}
const response = await this.$api.call(this.apiName, 'ExportClassesList', {
courseDate1: this.search.courseDate1 || null,
courseDate2: this.search.courseDate2 || null,
projectID: this.search.projectID || null
});
if (response.Success) {
// 取得檔案資訊
const fileData = response.Data;
const fileName = fileData.FileName;
const fileBase64 = fileData.FileBase64;
const fileSize = fileData.FileSize;
// 轉換 Base64 為 Blob
const binaryString = atob(fileBase64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
// 建立下載連結
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = fileName;
// 執行下載
document.body.appendChild(link);
link.click();
// 清理資源
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
this.$message.success(`匯出成功 (${(fileSize / 1024).toFixed(2)} KB)`);
console.log('[ClassesList] 匯出成功:', fileName);
} else {
this.$message.error(response.Message || '匯出失敗');
}
} catch (error) {
console.error('[ClassesList] 匯出錯誤:', error);
this.$message.error('匯出發生錯誤');
}
}
}
});
})();