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

1077 lines
44 KiB
JavaScript

function CreateReceiptEditApp() {
const loadMarker = document.getElementById('receiptEditApp');
if (loadMarker) {
DoCreateReceiptEditApp();
}
}
function DoCreateReceiptEditApp() {
window.__vms = window.__vms || {}
if (window.__vms.receiptEditApp)
return;
window.__vms.receiptEditApp = new Vue({
el: '#receiptEditApp',
mixins: [DateMixin, ToastMixin, ApiMixin],
data: {
mode: 'view', // view, add, edit
編號: 0,
originalMainData: null,
originalLaborData: null,
originalTravelData: null,
mainData: {
編號: 0,
表單編號: '',
活動日期: '',
身分別: '',
講師_非講師編號: '',
領款人姓名: '',
身分證字號: '',
憑證類別: '',
計畫代號: '',
計畫名稱: '',
活動地點: '',
活動類別: '',
活動名稱事由: '',
製單人員: '',
付款方式: '',
作廢: 0,
列印次數: 0,
已關帳: false,
DB_APPNO: 1,
DB_CRDAT: '',
DB_CRUSR: '',
DB_CRUSR_NAME: '',
DB_TRDAT: '',
DB_TRUSR: '',
DB_TRUSR_NAME: ''
},
laborData: {
編號: '',
領據編號: 0,
費用別: '',
單價: 0,
數量: 0,
單位: '',
扣繳類別: '',
合計金額: 0,
應扣繳稅額: 0,
服務費: 0,
作廢: 0,
DB_APPNO: 1
},
travelData: {
編號: '',
領據編號: 0,
票價資訊: '',
費用別: '',
起點: '',
訖點: '',
捷運公車: 0,
火車: 0,
計程車: 0,
高鐵飛機: 0,
自行開車: 0,
過路費停車費: 0,
住宿費: 0,
合計: 0,
作廢: 0,
DB_APPNO: 1
},
dropdown: {
身分別: [],
憑證類別: [],
付款方式: [],
勞務費_費用別: [],
差旅費_費用別: [],
扣繳類別: [],
單位別: []
},
recipientList: [],
showRecipientDropdown: false,
planList: [],
showPlanDropdown: false,
originStations: [],
showOriginDropdown: false,
destStations: [],
showDestDropdown: false,
stations: [],
showActivityLocationPhrase: false,
activityLocationPhrases: [],
showActivityCategoryPhrase: false,
activityCategoryPhrases: [],
showTicketPricePhrase: false,
ticketPricePhrases: [],
loading: false,
variables: {
領據執行業務所得課稅門檻: 0,
領據薪資課稅門檻: 0,
領據基本工資: 0,
領據執行業務所得稅率: 0,
領據薪資稅率: 0
},
// 花花: 上下筆導航用
navIdList: [],
navCurrentIndex: -1,
navCurrentPage: 1,
navPageSize: 20,
navTotalPages: 0,
navSearchParams: {}
},
created() {
// 從 AJAX 取得下拉選單資料
this.loading = true;
this.loadVariables();
this.loadDropdownLists();
this.loadPhraseLists();
this.loading = false;
this.mainData.製單人員 = V製單人員;
this.編號 = 0;
if (document.getElementById('ctl00_ContentPlaceHolder1_hid編號').value !== '') {
this.編號 = parseInt(document.getElementById('ctl00_ContentPlaceHolder1_hid編號').value) || 0;
}
// 花花: 初始化上下筆導航狀態(從查詢畫面傳來的 HiddenField 讀取)
this._initNavigation();
},
mounted() {
if (this.編號 !== 0) {
this.mode = 'view';
this.loadData(this.編號)
} else {
this.mode = 'add';
this.reset();
this.backupData();
this.setDefault();
}
},
watch: {
'laborData.單價'() {
this.calculateLaborTotal();
},
'laborData.數量'() {
this.calculateLaborTotal();
},
'laborData.扣繳類別'() {
this.calculateTax();
},
'mainData.身分別'() {
if (this.mode === 'add' || this.mode === 'edit') {
this.mainData.講師_非講師編號 = '';
this.mainData.領款人姓名 = '';
this.mainData.身分證字號 = '';
this.recipientList = [];
}
},
'travelData.捷運公車'() { this.calculateTravelTotal(); },
'travelData.火車'() { this.calculateTravelTotal(); },
'travelData.計程車'() { this.calculateTravelTotal(); },
'travelData.高鐵飛機'() { this.calculateTravelTotal(); },
'travelData.自行開車'() { this.calculateTravelTotal(); },
'travelData.過路費停車費'() { this.calculateTravelTotal(); },
'travelData.住宿費'() { this.calculateTravelTotal(); }
},
computed: {
isViewMode() {
return this.mode === 'view';
},
isEditMode() {
return this.mode === 'edit' || this.mode === 'add';
},
canAddNew() {
return this.mode === 'view';
},
canEdit() {
return this.mode === 'view' && this.編號 !== 0;
},
canCancel() {
return this.mode === 'add' || this.mode === 'edit';
},
canSave() {
return this.mode === 'add' || this.mode === 'edit';
},
canReturnToList() {
return this.mode === 'view';
},
closed() {
return this.mainData.已關帳;
},
// 花花: 上下筆導航可用性(僅 view 模式可用)
hasPrev() {
if (this.mode !== 'view') return false;
if (this.navIdList.length === 0 || this.navCurrentIndex < 0) return false;
return this.navCurrentIndex > 0 || this.navCurrentPage > 1;
},
hasNext() {
if (this.mode !== 'view') return false;
if (this.navIdList.length === 0 || this.navCurrentIndex < 0) return false;
return this.navCurrentIndex < this.navIdList.length - 1 || this.navCurrentPage < this.navTotalPages;
},
laborWarnings() {
const warnings = [];
const 扣繳類別 = this.laborData.扣繳類別 || '';
const 有金額 = (this.laborData.單價 || 0) > 0 || (this.laborData.數量 || 0) > 0 || (this.laborData.合計金額 || 0) > 0;
// 費用別警告
if (['演講費', '撰稿費'].indexOf(this.laborData.費用別) >= 0 && 扣繳類別 === '50') {
warnings.push('扣繳類別只能是執行業務所得');
}
// 有金額但費用別未填
if (有金額 && !this.laborData.費用別) {
warnings.push('勞務費已輸入金額,請選擇費用別');
}
// 有金額但單位未填
if (有金額 && !this.laborData.單位) {
warnings.push('勞務費已輸入金額,請選擇單位');
}
// 合計金額警告
if (扣繳類別 === '50' && this.laborData.合計金額 >= this.variables.領據基本工資) {
warnings.push(`薪資不得超過基本工資${this.variables.領據基本工資}(含),超過請拆成不同日期的領據`);
}
if ((扣繳類別.startsWith('9A') || 扣繳類別.startsWith('9B')) && this.laborData.合計金額 >= this.variables.領據執行業務所得課稅門檻) {
warnings.push(`執行業務所得不得超過${this.variables.領據執行業務所得課稅門檻}(含),超過請拆成不同日期的領據`);
}
return warnings;
}
},
methods: {
async loadVariables() {
try {
const result = await this.callApi('領據處理', 'GetVariables', {});
if (result.Data) {
this.variables = result.Data;
}
} catch (error) {
console.error('載入片語清單失敗:', error);
}
},
async loadDropdownLists() {
this.dropdown.身分別 = await this.loadDropdownList("身分別");
this.dropdown.憑證類別 = await this.loadDropdownList("憑證類別");
this.dropdown.付款方式 = await this.loadDropdownList("付款方式");
this.dropdown.勞務費_費用別 = await this.loadDropdownList("勞務費_費用別");
this.dropdown.差旅費_費用別 = await this.loadDropdownList("差旅費_費用別");
this.dropdown.扣繳類別 = await this.loadDropdownList("扣繳類別");
this.dropdown.單位別 = await this.loadDropdownList("單位別");
},
async loadDropdownList(key) {
try {
const result = await this.callApi('領據處理', 'GetDropdownLists', { key });
return result.Data || [];
} catch (error) {
console.error('載入下拉選單失敗:', error);
return [];
}
},
async loadPhraseLists() {
try {
const result = await this.callApi('領據處理', 'GetPhraseLists', {});
if (result.Data) {
this.activityLocationPhrases = result.Data.activityLocation || [];
this.activityCategoryPhrases = result.Data.activityCategory || [];
this.ticketPricePhrases = result.Data.ticketPrice || [];
}
} catch (error) {
console.error('載入公用變數失敗:', error);
}
},
toggleActivityLocationPhrase() {
if (this.isViewMode) return;
this.showActivityLocationPhrase = !this.showActivityLocationPhrase;
this.showActivityCategoryPhrase = false;
this.showTicketPricePhrase = false;
},
toggleActivityCategoryPhrase() {
if (this.isViewMode) return;
this.showActivityCategoryPhrase = !this.showActivityCategoryPhrase;
this.showActivityLocationPhrase = false;
this.showTicketPricePhrase = false;
},
toggleTicketPricePhrase() {
if (this.isViewMode) return;
this.showTicketPricePhrase = !this.showTicketPricePhrase;
this.showActivityLocationPhrase = false;
this.showActivityCategoryPhrase = false;
},
insertPhrase(fieldName, phrase) {
let input;
if (fieldName === '活動地點') {
input = this.$refs.活動地點Input;
this.showActivityLocationPhrase = false;
} else if (fieldName === '活動類別') {
input = this.$refs.活動類別Input;
this.showActivityCategoryPhrase = false;
} else if (fieldName === '票價資訊') {
input = this.$refs.票價資訊Input;
this.showTicketPricePhrase = false;
}
if (input) {
const startPos = input.selectionStart || input.value.length;
const endPos = input.selectionEnd || input.value.length;
const currentValue = input.value;
const newValue = currentValue.substring(0, startPos) + phrase + currentValue.substring(endPos);
if (fieldName === '活動地點') {
this.mainData.活動地點 = newValue;
} else if (fieldName === '活動類別') {
this.mainData.活動類別 = newValue;
} else if (fieldName === '票價資訊') {
this.travelData.票價資訊 = newValue;
}
// 更新游標位置
this.$nextTick(() => {
input.focus();
input.setSelectionRange(startPos + phrase.length, startPos + phrase.length);
});
}
},
calculateLaborTotal() {
const price = parseFloat(this.laborData.單價) || 0;
const qty = parseFloat(this.laborData.數量) || 0;
this.laborData.合計金額 = Math.round(price * qty);
this.calculateTax();
},
async calculateTax() {
const laborFee = parseInt(this.laborData.合計金額) || 0;
const category = this.laborData.扣繳類別 || '';
if (laborFee > 0 && category) {
this.loading = true;
try {
const result = await this.callApi('領據處理', 'CalcTax', {
laborFee,
category
});
this.laborData.應扣繳稅額 = result.Data;
} catch (error) {
console.error('計算稅額失敗:', error);
} finally {
this.loading = false;
}
} else {
this.laborData.應扣繳稅額 = 0;
}
},
calculateTravelTotal() {
this.travelData.合計 =
(parseInt(this.travelData.捷運公車) || 0) +
(parseInt(this.travelData.火車) || 0) +
(parseInt(this.travelData.計程車) || 0) +
(parseInt(this.travelData.高鐵飛機) || 0) +
(parseInt(this.travelData.自行開車) || 0) +
(parseInt(this.travelData.過路費停車費) || 0) +
(parseInt(this.travelData.住宿費) || 0);
},
searchStation(field) {
const key = this.travelData[field];
if (key && key.length > 0) {
axios({
method: 'post',
url: `${API_TRAIN_FARE}/SelectStation`,
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
data: JSON.stringify({ key })
})
.then(response => {
const result = response.data.d || response.data;
if (result.Success) {
this.stations = result.Data || [];
} else {
this.stations = [];
this.ShowWarning(result.Message);
}
})
.catch(error => {
console.error('查詢車站失敗:', error);
});
}
},
async searchRecipient() {
const key = this.mainData.領款人姓名;
const identity = this.mainData.身分別;
const activationDate = this.mainData.活動日期;
if (!key || key.length === 0) {
this.recipientList = [];
this.showRecipientDropdown = false;
return;
}
if (!identity) {
this.ShowWarning('請先選擇身分別');
this.recipientList = [];
this.showRecipientDropdown = false;
return;
}
if (!activationDate) {
this.ShowWarning('請輸入活動日期');
this.recipientList = [];
this.showRecipientDropdown = false;
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'SearchRecipient', { key, identity, activationDate });
this.recipientList = result.Data || [];
this.showRecipientDropdown = this.recipientList.length > 0;
} catch (error) {
console.error('查詢領款人失敗:', error);
this.recipientList = [];
this.showRecipientDropdown = false;
this.ShowWarning(error.message);
} finally {
this.loading = false;
}
},
hideRecipientDropdown() {
setTimeout(() => {
this.showRecipientDropdown = false;
this.recipientList = [];
}, 200);
},
selectRecipient(recipient) {
this.mainData.講師_非講師編號 = recipient.Value;
this.mainData.領款人姓名 = recipient.Name;
this.mainData.身分證字號 = recipient.IdNumber;
this.mainData.憑證類別 = recipient.VoucherType;
this.laborData.扣繳類別 = recipient.ConductType;
this.recipientList = [];
this.showRecipientDropdown = false;
},
async searchInstructorEvaluation() {
const date = this.mainData.活動日期;
const teacherNo = this.mainData.講師_非講師編號;
const name = this.mainData.領款人姓名;
if (!date) {
this.ShowWarning('請輸入活動日期');
return;
}
if (!teacherNo && !name) {
this.ShowWarning('請輸入講師編號或領款人姓名');
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'SearchInstructorEvaluation', {
日期: date,
講師編號: teacherNo || '',
姓名: name || ''
});
const data = result.Data || [];
if (data.length === 0) {
this.ShowWarning('無相符講師評鑑');
} else {
const lines = data.map(item => `日期:${this.FormatDate(item.日期)},課程名稱:${item.課程名稱}`);
this.ShowSuccess(lines.join('\n'));
}
} catch (error) {
console.error('查詢講師評鑑失敗:', error);
this.ShowError('查詢講師評鑑失敗: ' + (error.message || '請稍後重試'));
} finally {
this.loading = false;
}
},
async searchPlan() {
const key = this.mainData.計畫代號;
const year = this.mainData.活動日期 ? new Date(this.mainData.活動日期).getFullYear() - 1911 : null;
if (year === null) {
this.ShowWarning("請輸入活動日期");
return;
}
if (!key || key.length === 0) {
this.planList = [];
this.showPlanDropdown = false;
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'SearchPlan', { key, year });
this.planList = result.Data || [];
this.showPlanDropdown = this.planList.length > 0;
} catch (error) {
console.error('查詢計畫失敗:', error);
this.planList = [];
this.showPlanDropdown = false;
this.ShowWarning(error.message);
} finally {
this.loading = false;
}
},
selectPlan(plan) {
this.mainData.計畫代號 = plan.Code;
this.mainData.計畫名稱 = plan.Name;
this.planList = [];
this.showPlanDropdown = false;
},
hidePlanDropdown() {
setTimeout(() => {
this.showPlanDropdown = false;
this.planList = [];
}, 200);
},
async searchOriginStation() {
const key = this.travelData.起點;
if (!key || key.length === 0) {
this.originStations = [];
this.showOriginDropdown = false;
return;
}
this.loading = true;
try {
const result = await this.callApi('火車票價', 'SelectOriginStation', { key });
this.originStations = result.Data || [];
this.showOriginDropdown = this.originStations.length > 0;
} catch (error) {
console.error('查詢起點失敗:', error);
this.originStations = [];
this.showOriginDropdown = false;
this.ShowWarning(error.message);
} finally {
this.loading = false;
}
},
selectOriginStation(station) {
this.travelData.起點 = station.Name;
this.originStations = [];
this.showOriginDropdown = false;
},
hideOriginDropdown() {
setTimeout(() => {
this.showOriginDropdown = false;
this.originStations = [];
}, 200);
this.calculateFare();
},
async searchDestStation() {
const key = this.travelData.訖點;
if (!key || key.length === 0) {
this.destStations = [];
this.showDestDropdown = false;
return;
}
this.loading = true;
try {
const result = await this.callApi('火車票價', 'SelectDestStation', { key });
this.destStations = result.Data || [];
this.showDestDropdown = this.destStations.length > 0;
} catch (error) {
console.error('查詢訖點失敗:', error);
this.destStations = [];
this.showDestDropdown = false;
this.ShowWarning(error.message);
} finally {
this.loading = false;
}
},
selectDestStation(station) {
this.travelData.訖點 = station.Name;
this.destStations = [];
this.showDestDropdown = false;
},
hideDestDropdown() {
setTimeout(() => {
this.showDestDropdown = false;
this.destStations = [];
}, 200);
this.calculateFare();
},
async calculateFare() {
const 起站 = this.travelData.起點;
const 迄站 = this.travelData.訖點;
if (!起站 || !迄站) {
return;
}
this.loading = true;
try {
const result = await this.callApi('火車票價', 'SelectFare', { 起站, 迄站 });
this.travelData.火車 = result.Data;
this.calculateTravelTotal();
} catch (error) {
console.error('查詢票價失敗:', error);
this.ShowWarning(error.message);
} finally {
this.loading = false;
}
},
async save() {
if (!this.validate() || (this.laborWarnings || []).length > 0) {
return;
}
this.loading = true;
try {
const data = {
isNew: this.mode === 'add',
mainItem: this.mainData,
laborItem: this.laborData,
travelItem: this.travelData
};
const result = await this.callApiWithErrorMsg('領據處理', 'Save', data, '儲存');
this.ShowSuccess(result.Message);
// 新增存檔更新編號變數
if (this.mode === 'add') {
this.編號 = result.Data.編號;
}
// 返回查看模式
this.mode = 'view';
this.loadData(this.編號);
this.backupData();
} catch (error) {
console.error('Save error:', error);
} finally {
this.loading = false;
}
},
validate() {
if (!this.mainData.身分別) {
this.ShowWarning('請選擇身分別');
return false;
}
if (!this.mainData.領款人姓名) {
this.ShowWarning('請輸入領款人姓名');
return false;
}
if (!this.mainData.計畫代號) {
this.ShowWarning('請輸入計畫代號');
return false;
}
return true;
},
returnToList() {
if ((this.mode === 'add' || this.mode === 'edit') && !confirm("是否放棄" + (this.mode === 'add' ? '新增' : '修改')))
return;
window.__doPostBack('ctl00$ContentPlaceHolder1$btnTab1', '');
},
backupData() {
this.originalMainData = JSON.parse(JSON.stringify(this.mainData));
this.originalLaborData = JSON.parse(JSON.stringify(this.laborData));
this.originalTravelData = JSON.parse(JSON.stringify(this.travelData));
},
restoreData() {
if (this.originalMainData) {
this.mainData = JSON.parse(JSON.stringify(this.originalMainData));
}
if (this.originalLaborData) {
this.laborData = JSON.parse(JSON.stringify(this.originalLaborData));
}
if (this.originalTravelData) {
this.travelData = JSON.parse(JSON.stringify(this.originalTravelData));
}
},
addNew() {
if (this.mode !== 'view') {
return;
}
this.mode = 'add';
this.reset();
this.backupData();
this.setDefault();
},
edit() {
if (this.mode !== 'view') {
return;
}
this.mode = 'edit';
this.backupData();
},
cancel() {
if (this.mode === 'view') {
return;
}
if (!confirm("是否放棄" + (this.mode === 'add' ? '新增' : '修改') + ",資料將復原?")) {
return;
}
this.restoreData();
this.mode = 'view';
},
reset() {
this.mainData = {
編號: 0,
表單編號: '',
活動日期: '',
身分別: '',
講師_非講師編號: '',
領款人姓名: '',
身分證字號: '',
憑證類別: '',
計畫代號: '',
計畫名稱: '',
活動地點: '',
活動類別: '',
活動名稱事由: '',
付款方式: '',
作廢: 0,
列印次數: 0,
DB_APPNO: 1,
DB_CRDAT: '',
DB_CRUSR: '',
DB_CRUSR_NAME: '',
DB_TRDAT: '',
DB_TRUSR: '',
DB_TRUSR_NAME: '',
};
this.laborData = {
編號: '',
領據編號: 0,
費用別: '',
單價: 0,
數量: 0,
單位: '',
扣繳類別: '',
合計金額: 0,
應扣繳稅額: 0,
服務費: 0,
作廢: 0,
DB_APPNO: 1
};
this.travelData = {
編號: '',
領據編號: 0,
票價資訊: '',
費用別: '',
起點: '',
訖點: '',
捷運公車: 0,
火車: 0,
計程車: 0,
高鐵飛機: 0,
自行開車: 0,
過路費停車費: 0,
住宿費: 0,
合計: 0,
作廢: 0,
DB_APPNO: 1
};
},
setDefault()
{
this.mainData.DB_CRDAT = this.FormatDate(new Date());
this.mainData.DB_CRUSR = document.getElementById('ctl00_hidCurrentUser').value;
this.mainData.DB_CRUSR_NAME = document.getElementById('ctl00_hidCurrentUserName').value;
},
async loadData(no) {
this.loading = true;
try {
const result = await this.callApiWithErrorMsg('領據處理', 'GetOne', { no }, '載入');
const data = result.Data;
this.mainData = {
編號: data.編號,
表單編號: data.表單編號,
活動日期: this.FormatDate(data.活動日期),
身分別: data.身分別,
講師_非講師編號: data.講師_非講師編號,
領款人姓名: data.領款人姓名,
身分證字號: data.身分證字號,
憑證類別: data.憑證類別,
計畫代號: data.計畫代號,
計畫名稱: data.計畫名稱,
活動地點: data.活動地點,
活動類別: data.活動類別,
活動名稱事由: data.活動名稱事由,
付款方式: data.付款方式,
作廢: data.作廢,
列印次數: data.列印次數,
已關帳: data.已關帳,
DB_APPNO: data.DB_APPNO,
DB_CRDAT: this.FormatDate(data.DB_CRDAT),
DB_CRUSR: data.DB_CRUSR,
DB_CRUSR_NAME: data.DB_CRUSR_NAME,
DB_TRDAT: data.DB_TRUSR !== null ? this.FormatDate(data.DB_TRDAT) : '',
DB_TRUSR: data.DB_TRUSR !== null ? data.DB_TRUSR : '',
DB_TRUSR_NAME: data.DB_TRUSR != null ? data.DB_TRUSR_NAME: ''
};
this.laborData = {
編號: data.勞務費_編號,
領據編號: data.編號,
費用別: data.勞務費_費用別,
單價: data.勞務費_單價,
數量: data.勞務費_數量,
單位: data.勞務費_單位,
扣繳類別: data.勞務費_扣繳類別,
合計金額: data.勞務費_合計金額,
應扣繳稅額: data.勞務費_應扣繳稅額,
服務費: data.勞務費_服務費,
作廢: data.勞務費_作廢
};
this.travelData = {
編號: data.差旅費_編號,
領據編號: data.編號,
票價資訊: data.差旅費_票價資訊,
費用別: data.差旅費_費用別,
起點: data.差旅費_起點,
訖點: data.差旅費_訖點,
捷運公車: data.差旅費_捷運公車,
火車: data.差旅費_火車,
計程車: data.差旅費_計程車,
高鐵飛機: data.差旅費_高鐵飛機,
自行開車: data.差旅費_自行開車,
過路費停車費: data.差旅費_過路費停車費,
住宿費: data.差旅費_住宿費,
合計: data.差旅費_合計,
作廢: data.差旅費_作廢
};
if (data.main) {
this.mainData = data.main;
}
if (data.labor) {
this.laborData = data.labor;
}
if (data.travel) {
this.travelData = data.travel;
}
this.backupData();
} catch (error) {
console.error('LoadData error:', error);
} finally {
this.loading = false;
}
},
async print() {
if (this.mainData.作廢 !== 0) {
this.ShowError('已作廢不可列印');
}
this.loading = true;
try {
const result = await this.callApiWithErrorMsg(
'領據處理',
'Print',
{ idList: [this.mainData.編號 ] },
'列印領據'
);
if (result.Success) {
// 下載 Excel 檔案
if (result.Data && result.Data.fileName) {
const link = document.createElement('a');
link.href = `data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,${result.Data.excelData}`;
link.download = result.Data.fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.ShowSuccess(result.Message);
} else {
this.ShowWarning(result.Message);
}
} else {
this.ShowError('列印失敗: ' + (error.message || '請稍後重試'));
}
} catch (error) {
this.ShowError('列印失敗: ' + (error.message || '請檢查網路連線'));
} finally {
this.loadData(this.編號);
this.loading = false;
}
},
async voidVoucher() {
if (this.mainData.作廢 === 0 && !confirm("是否確定作廢?") || this.mainData.作廢 !== 0 && !confirm("是否確定取消作廢?")) {
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'Void', {
no: this.mainData.編號
});
this.loadData(this.mainData.編號);
this.ShowSuccess('作廢操作完成');
} catch (error) {
console.error('Void error:', error);
this.ShowError('作廢操作失敗: ' + (error.message || '請檢查網路連線'));
} finally {
this.loading = false;
}
},
async voidLaborFee() {
if (this.laborData.作廢 === 0 && !confirm("是否確定作廢勞務費?") || this.laborData.作廢 !== 0 && !confirm("是否確定取消作廢勞務費?")) {
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'VoidLaborFee', {
receiptNo: this.mainData.編號
});
this.loadData(this.mainData.編號);
this.ShowSuccess('勞務費作廢操作完成');
} catch (error) {
console.error('VoidLaborFee error:', error);
this.ShowError('勞務費作廢操作失敗: ' + (error.message || '請檢查網路連線'));
} finally {
this.loading = false;
}
},
async voidTravelFee() {
if (this.travelData.作廢 === 0 && !confirm("是否確定作廢差旅費?") || this.travelData.作廢 !== 0 && !confirm("是否確定取消作廢差旅費?")) {
return;
}
this.loading = true;
try {
const result = await this.callApi('領據處理', 'VoidTravelFee', {
receiptNo: this.mainData.編號
});
this.loadData(this.mainData.編號);
this.ShowSuccess('差旅費作廢操作完成');
} catch (error) {
console.error('VoidTravelFee error:', error);
this.ShowError('差旅費作廢操作失敗: ' + (error.message || '請檢查網路連線'));
} finally {
this.loading = false;
}
},
// 花花: 上下筆導航 — 初始化和執行
_initNavigation() {
const hidIdList = document.getElementById('ctl00_ContentPlaceHolder1_hidIdList');
if (hidIdList && hidIdList.value) {
try {
this.navIdList = JSON.parse(hidIdList.value);
} catch(e) {
this.navIdList = [];
}
}
// 在 idList 中找到目前編號的位置
this.navCurrentIndex = this.navIdList.indexOf(this.編號);
this.navCurrentPage = 1 * document.getElementById('ctl00_ContentPlaceHolder1_hidCurrentPage').value || 1;
this.navPageSize = 1 * document.getElementById('ctl00_ContentPlaceHolder1_hidPageSize').value || 20;
this.navTotalPages = 1 * document.getElementById('ctl00_ContentPlaceHolder1_hidNavTotalPages').value || 0;
// 從 HiddenField 讀取搜尋條件副本,供跨頁查詢使用
this.navSearchParams = {
活動日期_1: document.getElementById('ctl00_ContentPlaceHolder1_hid活動日期_1').value || null,
活動日期_2: document.getElementById('ctl00_ContentPlaceHolder1_hid活動日期_2').value || null,
身分別: document.getElementById('ctl00_ContentPlaceHolder1_hid身分別').value || null,
講師_非講師編號: null,
憑證類別: document.getElementById('ctl00_ContentPlaceHolder1_hid憑證類別').value || null,
計畫代號: document.getElementById('ctl00_ContentPlaceHolder1_hid計畫代號').value || null,
計畫名稱: document.getElementById('ctl00_ContentPlaceHolder1_hid計畫名稱').value || null,
活動類別: document.getElementById('ctl00_ContentPlaceHolder1_hid活動類別').value || null,
付款方式: document.getElementById('ctl00_ContentPlaceHolder1_hid付款方式').value || null,
領款人姓名: document.getElementById('ctl00_ContentPlaceHolder1_hid付款方式').value || null,
orderBy: ''
};
},
async goPrev() {
if (!this.hasPrev) return;
if (this.navCurrentIndex > 0) {
// 當頁內上一筆:直接從 navIdList 取
this.navCurrentIndex--;
this.編號 = this.navIdList[this.navCurrentIndex];
this.loadData(this.編號);
} else {
// 跨頁上一筆:取上一頁最後一筆
await this._fetchPageAndNavigate(this.navCurrentPage - 1, 'last');
}
},
async goNext() {
if (!this.hasNext) return;
if (this.navCurrentIndex < this.navIdList.length - 1) {
// 當頁內下一筆:直接從 navIdList 取
this.navCurrentIndex++;
this.編號 = this.navIdList[this.navCurrentIndex];
this.loadData(this.編號);
} else {
// 跨頁下一筆:取下一頁第一筆
await this._fetchPageAndNavigate(this.navCurrentPage + 1, 'first');
}
},
async _fetchPageAndNavigate(pageIndex, position) {
this.loading = true;
try {
const params = { ...this.navSearchParams, pageIndex, pageSize: this.navPageSize };
const result = await this.callApiWithErrorMsg('領據處理', 'SelectPage', params, '查詢');
const newList = this.ConvertDatesInObject(result.Data || [], '-');
if (newList.length === 0) return;
this.navIdList = newList.map(item => item.編號);
this.navCurrentPage = pageIndex;
this.navTotalPages = Math.ceil(result.TotalCount / this.navPageSize);
this.navCurrentIndex = position === 'first' ? 0 : this.navIdList.length - 1;
this.編號 = this.navIdList[this.navCurrentIndex];
// 同步更新 hidden fields,避免 postback 後狀態遺失
document.getElementById('ctl00_ContentPlaceHolder1_hidIdList').value = JSON.stringify(this.navIdList);
document.getElementById('ctl00_ContentPlaceHolder1_hidNavTotalPages').value = this.navTotalPages;
document.getElementById('ctl00_ContentPlaceHolder1_hidCurrentPage').value = this.navCurrentPage;
this.loadData(this.編號);
} catch (error) {
console.error('導航查詢失敗:', error);
this.ShowError('導航失敗: ' + (error.message || '請稍後重試'));
} finally {
this.loading = false;
}
},
}
});
}