chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore - 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
This commit is contained in:
@@ -0,0 +1,455 @@
|
||||
function CreateTrainFareApp() {
|
||||
const loadMarker = document.getElementById('TrainFareAPP');
|
||||
if (loadMarker) {
|
||||
DoCreateTrainFareApp();
|
||||
}
|
||||
}
|
||||
|
||||
function DoCreateTrainFareApp() {
|
||||
trainFareApp = new Vue({
|
||||
el: "#TrainFareAPP",
|
||||
mixins: [DateMixin, ToastMixin, ApiMixin],
|
||||
data: {
|
||||
versions: [],
|
||||
selectedVersionId: '',
|
||||
isEditMode: false,
|
||||
|
||||
originStations: [],
|
||||
destStations: [],
|
||||
fareData: {},
|
||||
editFareData: {},
|
||||
|
||||
loading: false
|
||||
},
|
||||
mounted() {
|
||||
this.LoadVersions();
|
||||
},
|
||||
methods: {
|
||||
async LoadVersions() {
|
||||
try {
|
||||
const result = await this.callApiWithErrorMsg('火車票價維護', 'GetVersions', {}, '載入版本清單');
|
||||
this.versions = result.Data || [];
|
||||
if (!this.selectedVersionId && this.versions.length > 0) {
|
||||
this.selectedVersionId = this.versions[0].Value;
|
||||
this.LoadFareTable();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('LoadVersions error:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async LoadFareTable() {
|
||||
if (!this.selectedVersionId) {
|
||||
this.originStations = [];
|
||||
this.destStations = [];
|
||||
this.fareData = {};
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const result = await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'GetFareTable',
|
||||
{ versionId: this.selectedVersionId },
|
||||
'載入票價表'
|
||||
);
|
||||
|
||||
const data = result.Data || {};
|
||||
this.originStations = data.originStations || [];
|
||||
this.destStations = data.destStations || [];
|
||||
this.fareData = data.fares || {};
|
||||
this.editFareData = JSON.parse(JSON.stringify(this.fareData));
|
||||
this.isEditMode = false;
|
||||
} catch (error) {
|
||||
console.error('LoadFareTable error:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
EnterEditMode() {
|
||||
this.editFareData = JSON.parse(JSON.stringify(this.fareData));
|
||||
this.isEditMode = true;
|
||||
},
|
||||
|
||||
CancelEdit() {
|
||||
this.editFareData = {};
|
||||
this.isEditMode = false;
|
||||
},
|
||||
|
||||
async SaveChanges() {
|
||||
if (!this.selectedVersionId) {
|
||||
this.ShowWarning('請先選擇版本');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'SaveFareTable',
|
||||
{
|
||||
versionId: this.selectedVersionId,
|
||||
fares: JSON.stringify(this.editFareData)
|
||||
},
|
||||
'儲存'
|
||||
);
|
||||
this.ShowSuccess('儲存成功');
|
||||
this.isEditMode = false;
|
||||
this.LoadVersions();
|
||||
this.LoadFareTable();
|
||||
} catch (error) {
|
||||
console.error('SaveChanges error:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async DeleteVersion() {
|
||||
if (!this.selectedVersionId) {
|
||||
this.ShowWarning('請先選擇版本');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`確定要刪除版本 ${this.selectedVersionId} 嗎?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'DeleteVersion',
|
||||
{ versionId: this.selectedVersionId },
|
||||
'刪除'
|
||||
);
|
||||
this.ShowSuccess('版本刪除成功');
|
||||
this.selectedVersionId = '';
|
||||
this.LoadVersions();
|
||||
this.LoadFareTable();
|
||||
} catch (error) {
|
||||
console.error('DeleteVersion error:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
GetFare(origin, destination) {
|
||||
const key = `${origin}_${destination}`;
|
||||
return this.fareData[key] || '';
|
||||
},
|
||||
|
||||
GetFareInput(origin, destination) {
|
||||
if (origin === destination) return null;
|
||||
const key = `${origin}_${destination}`;
|
||||
return this.editFareData[key] || null;
|
||||
},
|
||||
|
||||
SetFareInput(origin, destination, value) {
|
||||
if (origin === destination) return;
|
||||
const key = `${origin}_${destination}`;
|
||||
// 轉換為整數,空值或非數字時設為 0
|
||||
const numValue = parseInt(value) || 0;
|
||||
this.$set(this.editFareData, key, numValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function CreateTrainFareImportExportApp() {
|
||||
const loadMarker = document.getElementById('TrainFareImportExportAPP');
|
||||
if (loadMarker) {
|
||||
DoCreateTrainFareImportExportApp();
|
||||
}
|
||||
}
|
||||
|
||||
function DoCreateTrainFareImportExportApp() {
|
||||
const importExportApp = new Vue({
|
||||
el: "#TrainFareImportExportAPP",
|
||||
mixins: [DateMixin, ToastMixin, ApiMixin, Base64Mixin],
|
||||
data: {
|
||||
activeTab: 'export',
|
||||
versions: [],
|
||||
exportVersionId: '',
|
||||
exportResponse: null,
|
||||
|
||||
selectedFile: null,
|
||||
uploadedFilePath: null,
|
||||
importPreviewData: {},
|
||||
importOriginStations: [],
|
||||
importDestStations: [],
|
||||
checkResult: null,
|
||||
|
||||
loading: false
|
||||
},
|
||||
computed: {
|
||||
isImportButtonDisabled() {
|
||||
// 匯入按鈕禁用條件:
|
||||
// 1. 沒有上傳檔案
|
||||
// 2. 沒有驗證結果
|
||||
// 3. 驗證失敗
|
||||
// 4. 驗證未完成(success 不為 true)
|
||||
return !this.uploadedFilePath ||
|
||||
!this.checkResult ||
|
||||
!this.checkResult.success;
|
||||
},
|
||||
exportOriginStations() {
|
||||
return this.exportResponse?.Data?.originStations || [];
|
||||
},
|
||||
exportDestStations() {
|
||||
return this.exportResponse?.Data?.destStations || [];
|
||||
},
|
||||
exportData() {
|
||||
return this.exportResponse?.Data?.fares || {};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.LoadVersions();
|
||||
},
|
||||
watch: {
|
||||
exportVersionId() {
|
||||
// 版本選擇改變時,重置匯出數據
|
||||
this.exportResponse = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async LoadVersions() {
|
||||
try {
|
||||
const result = await this.callApiWithErrorMsg('火車票價維護', 'GetVersions', {}, '載入版本清單');
|
||||
this.versions = result.Data || [];
|
||||
} catch (error) {
|
||||
console.error('LoadVersions error:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async DownloadTemplate() {
|
||||
try {
|
||||
const result = await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'GetExcelTemplate',
|
||||
{},
|
||||
'下載範本'
|
||||
);
|
||||
|
||||
// 下載 Excel 檔案
|
||||
const excelData = result.Data;
|
||||
if (!excelData) {
|
||||
this.ShowError('下載失敗:未取得範本檔案資料');
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = this.Base64ToBlob(excelData);
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = '火車票價_匯入範本.xlsx';
|
||||
link.click();
|
||||
|
||||
this.ShowSuccess('範本下載成功');
|
||||
} catch (error) {
|
||||
console.error('DownloadTemplate error:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async ExportData() {
|
||||
if (!this.exportVersionId) {
|
||||
this.ShowWarning('請選擇版本');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const result = await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'ExportFareData',
|
||||
{ versionId: this.exportVersionId },
|
||||
'匯出'
|
||||
);
|
||||
|
||||
// 儲存完整響應以供計算屬性使用
|
||||
this.exportResponse = result;
|
||||
|
||||
// 下載 Excel 檔案
|
||||
const excelData = result.ExcelData;
|
||||
if (!excelData) {
|
||||
this.ShowError('匯出失敗:未取得 Excel 檔案資料');
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = this.Base64ToBlob(excelData);
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `火車票價_版本${this.exportVersionId}_${new Date().getTime()}.xlsx`;
|
||||
link.click();
|
||||
|
||||
this.ShowSuccess('匯出成功');
|
||||
} catch (error) {
|
||||
console.error('ExportData error:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
OnFileSelected(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
this.selectedFile = file;
|
||||
this.checkResult = null;
|
||||
this.importPreviewData = {};
|
||||
this.importOriginStations = [];
|
||||
this.importDestStations = [];
|
||||
|
||||
this.UploadFile(file);
|
||||
},
|
||||
|
||||
UploadFile(file) {
|
||||
if (!file) {
|
||||
this.ShowError('請選擇檔案');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
// 使用 .ashx Handler 上傳檔案
|
||||
const uploadUrl = `${API_BASE}/TrainFareUploadHandler.ashx`;
|
||||
|
||||
fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(text => {
|
||||
try {
|
||||
const result = JSON.parse(text);
|
||||
|
||||
if (result && result.Success) {
|
||||
const uploadedFilePath = result.Data;
|
||||
this.ShowSuccess('檔案上傳成功');
|
||||
// 立即驗證上傳的檔案
|
||||
this.ValidateUploadedFile(uploadedFilePath);
|
||||
} else {
|
||||
const errorMsg = result ? result.Message : '上傳失敗';
|
||||
this.ShowError('上傳失敗:' + errorMsg);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Parse response error:', e);
|
||||
console.error('Response text:', text);
|
||||
this.ShowError('檔案上傳失敗:回應格式錯誤');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Upload error:', error);
|
||||
this.ShowError('檔案上傳失敗:' + error.message);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('UploadFile error:', error);
|
||||
this.ShowError('檔案上傳出錯:' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
async ValidateUploadedFile(filePath) {
|
||||
try {
|
||||
const result = await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'ValidateImportFile',
|
||||
{ filePath: filePath },
|
||||
'驗證檔案'
|
||||
);
|
||||
|
||||
this.checkResult = {
|
||||
success: result.Success,
|
||||
errors: result.Data?.Errors || []
|
||||
};
|
||||
|
||||
if (this.checkResult.success) {
|
||||
// 解析預覽資料
|
||||
this.uploadedFilePath = filePath;
|
||||
this.importPreviewData = result.Data?.Fares || {};
|
||||
this.importOriginStations = result.Data?.OriginStations || [];
|
||||
this.importDestStations = result.Data?.DestStations || [];
|
||||
this.ShowSuccess('檔案驗證成功');
|
||||
} else {
|
||||
this.ShowError('檔案驗證失敗');
|
||||
this.uploadedFilePath = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('ValidateUploadedFile error:', error);
|
||||
this.uploadedFilePath = null;
|
||||
}
|
||||
},
|
||||
|
||||
CancelImport() {
|
||||
this.selectedFile = null;
|
||||
this.uploadedFilePath = null;
|
||||
this.checkResult = null;
|
||||
this.importPreviewData = {};
|
||||
this.importOriginStations = [];
|
||||
this.importDestStations = [];
|
||||
const fileInput = document.querySelector('input[type="file"]');
|
||||
if (fileInput) {
|
||||
fileInput.value = '';
|
||||
}
|
||||
},
|
||||
|
||||
async ImportData() {
|
||||
// 匯入按鈕已被禁用,不應該執行到這裡
|
||||
// 但仍保留安全檢查作為雙重保障
|
||||
if (!this.uploadedFilePath || !this.checkResult || !this.checkResult.success) {
|
||||
this.ShowWarning('請先上傳並驗證檔案');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
const result = await this.callApiWithErrorMsg(
|
||||
'火車票價維護',
|
||||
'ImportFareData',
|
||||
{
|
||||
mode: 'new',
|
||||
versionId: null,
|
||||
filePath: this.uploadedFilePath
|
||||
},
|
||||
'匯入'
|
||||
);
|
||||
|
||||
this.ShowSuccess('匯入成功');
|
||||
this.CancelImport();
|
||||
|
||||
// 更新版本清單
|
||||
if (trainFareApp) {
|
||||
trainFareApp.LoadVersions();
|
||||
}
|
||||
this.LoadVersions();
|
||||
} catch (error) {
|
||||
console.error('ImportData error:', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
GetExportFare(origin, destination) {
|
||||
const key = `${origin}_${destination}`;
|
||||
return this.exportData[key] || '';
|
||||
},
|
||||
|
||||
GetImportFare(origin, destination) {
|
||||
const key = `${origin}_${destination}`;
|
||||
return this.importPreviewData[key] || '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//// 頁面載入時建立 Vue 應用
|
||||
//document.addEventListener('DOMContentLoaded', function () {
|
||||
// CreateTrainFareApp();
|
||||
// CreateTrainFareImportExportApp();
|
||||
//});
|
||||
Reference in New Issue
Block a user