first commit

This commit is contained in:
Mauve
2026-09-08 17:20:27 +08:00
commit a7f2e0ca01
752 changed files with 111259 additions and 0 deletions
+986
View File
@@ -0,0 +1,986 @@
<template>
<view class="hz-page">
<!-- #ifdef APP-PLUS -->
<simple-watermark ref="watermark"></simple-watermark>
<!-- #endif -->
<u-navbar @leftClick="back()" :safeAreaInsetTop="true" :placeholder="true" :title="title" :fixed="true"
:autoBack="false" leftIconColor="#000000" bgColor="#fff" titleStyle="font-weight:bold;">
</u-navbar>
<view class="hz-spacing hz-bg-white" style="margin-top:8px;">
<!-- Player Info 卡片 -->
<view class="hz-card-profile hz-mr-b-30">
<view class="hz-flex-row">
<view style="width:60%">
<view class="hz-font-color-light hz-font-sm">{{$t("common.playerId")}}</view>
<view class="hz-font-bolder hz-font-lg">
{{bookingListData.length > 0 ? bookingListData[0].playerId : '-'}}</view>
</view>
<view style="width:40%">
<view class="hz-font-color-light hz-font-sm">{{$t("common.tier")}}</view>
<view class="hz-font-bolder hz-font-lg">
{{bookingListData.length > 0 ? bookingListData[0].tier : '-'}}</view>
</view>
</view>
<view class="hz-flex-row hz-mr-t-30">
<view style="width:100%">
<view class="hz-font-color-light hz-font-sm">{{$t("common.name")}}</view>
<view class="hz-font-bolder hz-font-lg">
{{bookingListData.length > 0 ? (bookingListData[0].memberTitle || '') + ' ' + (bookingListData[0].memberFirstName || '') + ' ' + (bookingListData[0].memberLastName || '') : '-'}}
</view>
</view>
</view>
</view>
<!-- Booking Info 卡片 -->
<view class="hz-pd-16 hz-font-bolder hz-font-md hz-card-extend"
style="margin-top:10px;align-items: center;">
<view class="hz-flex-row" style="align-items: center; width: 100%;">
<!-- 房间信息轮播 -->
<view style="flex: 1; margin-right: 10px; min-height: 80px;">
<!-- 房间信息轮播 -->
<view style="position: relative; height: 100px;" @touchstart="touchStart" @touchend="touchEnd">
<!-- 轮播内容 -->
<view v-for="(room, index) in roomList" :key="index"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; transition: opacity 0.5s;"
:style="{ opacity: currentRoomIndex === index ? 1 : 0, zIndex: currentRoomIndex === index ? 1 : 0 }">
<view class="hz-flex-row" style="align-items: center;">
<!-- 多选框 -->
<view
style="width: 17px; height: 17px; display: flex; align-items: center; justify-content: center;;"
@click="toggleSelection(index)">
<view
style="width: 15px; height: 15px; border: 0.5px solid #C39A4B; transition: all 0.3s; display: flex; align-items: center; justify-content: center;border-radius: 25px;"
:style="{ backgroundColor: room.selected ? '#C39A4B' : '#ffffff' }">
<view v-if="room.selected"
style="color: white; font-size: 10px; font-weight: bold;">✔</view>
</view>
</view>
<!-- 房间信息 -->
<view style="flex: 1;margin-left: 10px;">
<!-- Edit 按钮 -->
<view @click="toEdit()" style="display:flex;justify-content:flex-end;width:100%;">
<image src="/static/images/edit_active.png"
style="width: 17px; height: 17px;" />
</view>
<view class="hz-flex-row" style="align-items: center;">
<image src="/static/images/ico_calendar.png"
style="width:16px;height:16px;"></image>
<span class="hz-font-bolder"
style="margin-left:4px;font-size: 14px;">{{room.date}}&nbsp; {{$t("common.to")}}&nbsp;
{{room.endDate}}</span>
</view>
<view class="hz-flex-row" style="margin-top:8px;">
<view class="hz-flex-row" style="align-items: center;">
<image src="/static/images/ico_room.png"
style="width:16px;height:16px;"></image>
<span class="hz-font-bolder"
style="margin-left:4px;font-size: 14px;">{{room.roomInfo}}</span>
</view>
</view>
</view>
</view>
</view>
<!-- 轮播指示器 -->
<view
style="position: absolute; bottom: 0; left: 0; width: 100%; display: flex; justify-content: center; gap: 8px;">
<view v-for="(room, index) in roomList" :key="index"
style="width: 6px; height: 6px; border-radius: 50%; transition: background-color 0.3s;"
:style="{ backgroundColor: currentRoomIndex === index ? '#C39A4B' : '#CCCCCC' }"
@click="currentRoomIndex = index"></view>
</view>
</view>
</view>
</view>
</view>
<!-- 玩家信息 -->
<view style="padding-left: 8px;padding-right: 8px;">
<view class="infoButton">
<view class="hz-flex-row dataMargin">
<view class="" style="width: 50%;font-weight: bolder">
Current Trip Theo
</view>
<view class="">
{{formatWithThousands(currentApprovalData.currentTripTheoWinAmount)}}
</view>
</view>
<view class="hz-flex-row dataMargin">
<view class="" style="width: 50%;font-weight: bolder">
Last 2 Days Theo
</view>
<view class="">
{{formatWithThousands(currentApprovalData.last2DayTheoWinAmount)}}
</view>
</view>
<view class="dataMargin">
<view class="hz-flex-row">
<view class="" style="width: 50%;font-weight: bolder">
R3 Theo/TPD/Actual win
</view>
</view>
<view class="hz-flex-row">
<view>
{{formatWithThousands(currentApprovalData.r3TheoWin)}} / {{formatWithThousands(currentApprovalData.r3TPD)}} / {{formatWithThousands(currentApprovalData.r3ActualWin)}}
</view>
</view>
</view>
<view class="hz-flex-row">
<view class="" style="width: 50%;font-weight: bolder">
R6 Theo/TPD/Actual win
</view>
</view>
<view class="hz-flex-row">
<view>
{{formatWithThousands(currentApprovalData.r6TheoWin)}} / {{formatWithThousands(currentApprovalData.r6TPD)}} / {{formatWithThousands(currentApprovalData.r6ActualWin)}}
</view>
</view>
</view>
<view class="infoButton">
<view style="font-weight: bolder">
Continuous / Overlap Booking (C/I to C/O)
</view>
<view>
{{currentApprovalData.overlapBooking}}
</view>
</view>
<!-- RoomCount -->
<view class="infoButton">
<view style="font-weight: bolder">
Room Count
</view>
<view>
{{ sortRoomCountByDate(currentApprovalData.roomCount) }}
</view>
</view>
<!-- Remark -->
<view class="infoButton">
<view style="font-weight: bolder">
Remark
</view>
<view class="">
{{roomList[currentRoomIndex] && roomList[currentRoomIndex].remark ? roomList[currentRoomIndex].remark : '-'}}
</view>
</view>
<view class="infoButton">
<view style="font-weight: bolder">
Sharer
</view>
<view class="">
{{roomList[currentRoomIndex] ? roomList[currentRoomIndex].sharer : '-'}}
</view>
</view>
<view class="infoButton">
<view style="font-weight: bolder">
Request Reason
</view>
<view class="">
{{ currentApprovalRouting.approvalReason}}
</view>
</view>
<view class="infoButton">
<view style="font-weight: bolder">
Routing Reason
</view>
<view class="">
{{currentApprovalRouting.routingReason}}
</view>
</view>
<view class="hz-mr-t-30">
<view class="hz-flex-row">
<view class="" style="width: 50%;font-weight: bolder">
Requested on
</view>
<view class="" style="font-weight: bolder">
Requested by
</view>
</view>
<view class="hz-flex-row">
<view class="" style="width: 50%;">
{{currentApprovalRouting.createdAt ? formatDate(currentApprovalRouting.createdAt) : '-'}}
</view>
<view class="" style="width: 50%;">
{{currentApprovalRouting.createdBy}}
</view>
</view>
</view>
</view>
</view>
<u-tabbar :fixed="true" :placeholder="true" :safeAreaInsetBottom="true" customStyle="z-index:100;height:58px;">
<view @click="toPreviousRecord()" class="book hz-flex-row hz-spacing"
:class="canPrevious==false? 'hz-disabled':''" style="width: 60%;">
<view class="hz-btn hz-font-color-primary hz-font-lg hz-font-bold hz-text-center"
style="background-color: #fff;border: #C39A4B solid 2px;display: flex;justify-content: center;align-items: center;">
<image src="/static/images/arrow_previous_active.png"
style="width: 25px; height: 25px;" />
</view>
</view>
<view @click="onTabApproveTap" class="book hz-flex-row hz-spacing"
:class="approvalLoading==true || roomList.filter(r => r.selected).length > 0? 'hz-disabled':''">
<view class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center">
{{$t("approval.approve")}}
</view>
</view>
<view @click="onTabRejectTap" class="book hz-flex-row hz-spacing"
:class="approvalLoading==true || roomList.filter(r => r.selected).length > 0? 'hz-disabled':''">
<view class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center">
{{$t("bookingDetail.reject")}}
</view>
</view>
<view @click="toNextRecord()" class="book hz-flex-row hz-spacing" :class="canNext==false? 'hz-disabled':''"
style="width: 60%">
<view class="hz-btn hz-font-color-primary hz-font-lg hz-font-bold hz-text-center"
style="background-color: #fff;border: #C39A4B solid 2px;display: flex;justify-content: center;align-items: center;">
<image src="/static/images/arrow_next_active.png"
style="width: 25px; height: 25px;" />
</view>
</view>
</u-tabbar>
<u-popup :safeAreaInsetBottom="true" :closeOnClickOverlay="false" :safeAreaInsetTop="true" :mode="'center'" :round="12" :show="showMsgBox"
customStyle="width:94%; padding-top: 30px" @close="closePopup()">
<view>
<view class="hz-flex-row" style="justify-content:center;align-items:center;width:100%;">
<image :src="iconPath" style="width:64px;height:64px;"></image>
</view>
<view class="hz-font-xl hz-font-bold hz-text-center"
style="margin-top:20px;margin-bottom: 20px;margin-left: 15px;margin-right: 15px;white-space:pre-wrap;">
<rich-text v-html="popMsgStr" style="line-height:26px;"></rich-text>
</view>
<view v-if="showSubmit">
<view @click="currentAction === 'approve' ? confirmApproval() : confirmReject()"
class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center"
style="width: 90%;margin: 0 auto;margin-bottom: 15px;">
{{$t("common.confirm").toUpperCase()}}
</view>
<view @click="closePopup()"
class="hz-btn hz-font-color-primary hz-font-lg hz-font-bold hz-text-center"
style="width: 90%;margin: 0 auto;margin-bottom: 30px;background-color: white;border: 0.5px solid;">
{{$t("common.cancel").toUpperCase()}}
</view>
</view>
<view v-else>
<view @click="backToNotification()"
class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center"
style="width: 90%;margin: 0 auto;margin-bottom: 15px;">
{{$t("approval.backToRecord").toUpperCase()}}
</view>
</view>
</view>
</u-popup>
<u-popup :safeAreaInsetBottom="true" :safeAreaInsetTop="true" :mode="'center'" :round="12"
:show="showReturnMsgBox">
<view :style="'width:'+ windowWidth + 'px;'" style="padding:20px;">
<view class="hz-flex-row" style="justify-content: center;">
<image :src="iconPath" style="width:64px;height:64px;"></image>
</view>
<view class="hz-font-md hz-font-bold hz-text-center" style="margin-top:20px;">
<rich-text v-html="msgStr" style="line-height:26px;"></rich-text>
</view>
<view @click="showReturnMsgBox = false"
class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center" style="margin-top:20px;">
{{buttonStr}}
</view>
</view>
</u-popup>
<u-calendar closeOnClickOverlay :confirmText="confirmText" :confirmDisabledText="confirmText" color="#C39A4B"
title="" :startText="startText" :endText="endText" :show="showCalendar" :allowSameDay="true" mode="range"
:minDate="selectAbleStart" :maxDate="selectAbleEnd" :defaultDate="[calendarStartDate, calendarEndDate]"
@close="cancelDate" @confirm="confirmDate" :showMark="false">
</u-calendar>
<!-- 悬浮栏 - 显示选中的记录数量 -->
<view v-if="roomList.filter(r => r.selected).length > 0" class="floating-bar">
<view class="floating-content">
<text class="selected-count">{{ roomList.filter(r => r.selected).length }} {{ $t("common.selected") }}</text>
<view class="floating-actions">
<view @click="handleBatchApprove" class="action-btn approve-btn">{{ $t("approval.batchApprove") }}</view>
<view @click="handleBatchReject" class="action-btn reject-btn">{{ $t("approval.batchReject") }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
batchSubmitApproval,
batchSubmitReject,
getApprovalData,
rejectApproval,
submitApproval
} from '../../api/approvalApi';
import {
times
} from '../../uni_modules/uview-ui/libs/function/digit';
// #ifdef APP-PLUS
import SimpleWatermark from '@/components/simple-watermark/simple-watermark.vue'
// #endif
export default {
components: {
// #ifdef APP-PLUS
SimpleWatermark
// #endif
},
data() {
return {
title: "Detail",
approvalLoading: false,
iconPath: '',
popMsgStr: '',
showMsgBox: false,
confirmText: this.$t('playerDetail.confirm'),
startText: this.$t('common.in'),
endText: this.$t('common.out'),
// 日历日期范围
calendarStartDate: '',
calendarEndDate: '',
selectAbleStart: '',
selectAbleEnd: '',
searchPlayerId: '',
showCalendar: false,
showSubmit: true,
deviceData: '',
canNext: false,
canPrevious: true,
// 玩家导航
currentPlayerIndex: 0,
approvalPlayerList: [],
showReturnMsgBox: false,
// 触摸事件
touchStartX: 0,
touchEndX: 0,
buttonStr: '',
msgStr: '',
windowWidth: 0,
// 房间信息轮播
currentRoomIndex: 0,
// 当前操作类型:approve 或 reject
currentAction: '',
bookingListData: [],
approvalGamingDataList: [],
approvalRoutingList: [],
roomList: []
}
},
computed: {
// 获取当前房间对应的 approvalGamingData
currentApprovalData() {
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom && currentRoom.id) {
const approvalData = this.approvalGamingDataList.find(
item => item.bookingId == currentRoom.id
);
return approvalData || {};
}
return {};
},
// 当前轮播房间对应的 cfgApprovalRouting(按 bookingId 匹配)
currentApprovalRouting() {
const currentRoom = this.roomList[this.currentRoomIndex];
if (!currentRoom || currentRoom.id == null) return {};
const row = this.approvalRoutingList.find(
item => item.bookingId == currentRoom.id
);
return row || {};
}
},
methods: {
formatWithThousands(value) {
if (value === null || value === undefined || value === '') return '-';
const str = String(value).trim();
// 已经是合法千分位格式(支持负数和小数)时,直接返回
if (/^-?\d{1,3}(,\d{3})*(\.\d+)?$/.test(str)) return str;
// 未格式化数字(或带逗号但格式不标准)时,去逗号后重新格式化
const normalized = str.replace(/,/g, '');
if (/^-?\d+(\.\d+)?$/.test(normalized)) {
const n = Number(normalized);
return n.toLocaleString('en-US');
}
return value;
},
// 将形如:2025-03-18 +12 (W +2) | 2025-03-16 + 16 ... 按日期升序排序
sortRoomCountByDate(roomCountValue) {
if (roomCountValue === null || roomCountValue === undefined || roomCountValue === '') return '-';
const input = String(roomCountValue).trim();
if (!input) return '-';
const dateRegex = /^(\d{4}-\d{2}-\d{2})/;
// 新格式:类似 2026-04-01(100,W+0),2026-04-03(100,W+0),...(逗号分隔,括号内部也包含逗号)
// 不能简单 split(','),提取每个完整的 “YYYY-MM-DD(... )” 片段再排序
const parts = input.match(/\d{4}-\d{2}-\d{2}\s*[^)]*\([^)]*\)/g);
if (!parts || parts.length <= 1) return input;
const enriched = parts.map((part) => {
const m = part.match(dateRegex);
const dateStr = m ? m[1] : '';
const time = dateStr ? Date.parse(dateStr) : Number.POSITIVE_INFINITY;
return { part, time };
});
enriched.sort((a, b) => {
if (a.time === b.time) return a.part.localeCompare(b.part);
return a.time - b.time;
});
// 新格式分段之间通常是逗号
return enriched.map(x => x.part).join(',');
},
back() {
this.navBack();
},
toEdit() {
// 获取当前轮播图显示的房间信息
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom) {
// 从 bookingListData 中获取原始日期范围作为可选范围
// 因为 roomList 中的日期可能已经被修改过
const originalBooking = this.bookingListData.find(item => item.id === currentRoom.id);
if (originalBooking) {
// 可选日期范围保持为原始日期
// 注意:selectAbleStart 和 selectAbleEnd 只在数据加载时设置,这里不再修改
// 但默认显示的日期应该是当前房间的当前日期(可能已经被修改过的)
this.calendarStartDate = currentRoom.checkinDate;
this.calendarEndDate = currentRoom.checkoutDate;
}
}
this.showCalendar = true;
},
showApproval() {
// 设置当前操作类型为 approve
this.currentAction = 'approve';
this.iconPath = '../../static/images/warn.png';
this.popMsgStr = this.$t("approval.submitApproval");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = true;
},
// 底部 Approve:有选中记录或 loading 时不进入 confirmApproval(避免仅样式置灰仍触发)
onTabApproveTap() {
if (this.approvalLoading || this.roomList.some(r => r.selected)) return;
this.confirmApproval();
},
// 底部 Reject:同上
onTabRejectTap() {
if (this.approvalLoading || this.roomList.some(r => r.selected)) return;
this.confirmReject();
},
async confirmApproval() {
if (this.approvalLoading || this.roomList.some(r => r.selected)) return;
uni.showLoading({
title: this.$t("common.loading")
});
// 获取当前轮播图显示的房间信息
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom) {
}
try {
let params = {
bookingId: currentRoom.id,
checkinDate: currentRoom.checkinDate,
checkoutDate: currentRoom.checkoutDate
};
const res = await submitApproval(params);
this.showMsgBox = false;
if (res.success == true) {
this.iconPath = '../../static/images/ico_suc.png';
this.popMsgStr = this.$t("bookingConfirm.approvalSuccess");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = false;
} else {
this.buttonStr = this.$t("common.ok");
this.iconPath = '../../static/images/ico_err.png';
this.msgStr = res.message!=null?res.message:this.$t("common.approvalFail");
this.url = '';
this.showReturnMsgBox = true;
}
} catch (e) {
console.error(e);
uni.$u.toast(e.errMsg, 5000);
var request = e.config != undefined ? JSON.stringify(e.config) : "";
var response = e.data != undefined ? JSON.stringify(e.data) : "";
await this.writeLog(this.userData.userId, "find_player", "",
"[APP][findPlayer.vue][getProfileByPlayerId][Catch Exception]" + e.errMsg, request,
response, 1, false);
} finally {
uni.hideLoading();
}
},
async getApprovalDetailData(playerId) {
uni.showLoading({
title: this.$t("common.loading")
});
try {
// 如果传入了 playerId,则使用传入的,否则使用 searchPlayerId
const targetPlayerId = playerId || this.searchPlayerId;
let params = {
playerId: targetPlayerId
};
const res = await getApprovalData(params);
if (res.success == true) {
if (res.data !== null) {
this.bookingListData = res.data.bookingsViewList;
this.approvalGamingDataList = res.data.approvalGamingData || [];
const routingList = res.data.cfgApprovalRoutingList;
if (Array.isArray(routingList) && routingList.length > 0) {
this.approvalRoutingList = routingList;
} else if (res.data.cfgApprovalRouting) {
this.approvalRoutingList = [res.data.cfgApprovalRouting];
} else {
this.approvalRoutingList = [];
}
// 将 bookingListData 转换为 roomList 格式
if (this.bookingListData && this.bookingListData.length > 0) {
this.roomList = this.bookingListData.map(item => {
// 格式化日期,添加星期和月份
const formatDate = (dateStr) => {
if (!dateStr) return '';
const date = new Date(dateStr);
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const weekday = weekdays[date.getDay()];
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `(${weekday})${year}-${month}-${day}`;
};
return {
id: item.id,
bookingId: item.id, // 保存 bookingId 用于匹配 approvalGamingData
date: formatDate(item.checkinDate),
checkinDate: item.checkinDate, // 保存原始入住日期
endDate: formatDate(item.checkoutDate),
checkoutDate: item.checkoutDate, // 保存原始退房日期
roomInfo: `${item.propertyName || ''}, ${item.room || ''}`.trim(),
selected: false,
sharer: item.sharer || '-',
remark: item.remark
};
});
// 切换 player 后重置轮播索引,避免 new roomList 更短导致取不到数据
this.currentRoomIndex = 0;
// 数据加载完成后,获取当前房间的日期作为可选范围
if (this.roomList.length > 0) {
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom) {
this.selectAbleStart = currentRoom.checkinDate;
this.selectAbleEnd = currentRoom.checkoutDate;
}
}
}
// 更新当前玩家在列表中的位置
this.updateCurrentPlayerIndex(targetPlayerId);
uni.hideLoading();
}
} else {
this.msgStr = res.message;
this.showMsg = true;
}
} catch (e) {
console.error(e);
uni.$u.toast(e.errMsg, 5000);
var request = e.config != undefined ? JSON.stringify(e.config) : "";
var response = e.data != undefined ? JSON.stringify(e.data) : "";
await this.writeLog(this.userData.userId, "find_player", "",
"[APP][findPlayer.vue][getProfileByPlayerId][Catch Exception]" + e.errMsg, request,
response, 1, false);
} finally {
uni.hideLoading();
}
},
closePopup() {
this.showMsgBox = false;
},
cancelDate() {
this.showCalendar = false;
},
confirmDate(e) {
// e 是选择的日期数组,格式为 [开始日期, 结束日期]
if (e) {
const startDate = e[0];
const endDate = e[e.length - 1];
// 获取当前轮播图显示的房间信息
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom) {
// 更新原始日期字段
currentRoom.checkinDate = startDate;
currentRoom.checkoutDate = endDate;
// 更新显示用的格式化日期
// 这里需要重新格式化日期,保持与之前相同的格式
const formatDateForDisplay = (dateStr) => {
if (!dateStr) return '';
const date = new Date(dateStr);
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const weekday = weekdays[date.getDay()];
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `(${weekday})${year}-${month}-${day}`;
};
const formatEndDateForDisplay = (dateStr) => {
if (!dateStr) return '';
const date = new Date(dateStr);
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const weekday = weekdays[date.getDay()];
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `(${weekday})${year}-${month}-${day}`;
};
currentRoom.date = formatDateForDisplay(startDate);
currentRoom.endDate = formatEndDateForDisplay(endDate);
}
}
this.showCalendar = false;
},
// 日期格式化方法
formatDate(timestamp) {
if (!timestamp) return '-';
const date = new Date(timestamp);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
// 更新当前玩家在列表中的位置
updateCurrentPlayerIndex(playerId) {
if (this.approvalPlayerList && this.approvalPlayerList.length > 0) {
const currentIndex = this.approvalPlayerList.findIndex(item => item.playerId === playerId);
if (currentIndex !== -1) {
this.currentPlayerIndex = currentIndex;
// 更新 canPrevious 和 canNext
this.canPrevious = currentIndex > 0;
this.canNext = currentIndex < this.approvalPlayerList.length - 1;
}
}
},
backToNotification() {
this.navBack();
},
toPreviousRecord() {
if (this.canPrevious === true) {
// 导航到上一个玩家
const previousIndex = this.currentPlayerIndex - 1;
if (previousIndex >= 0 && this.approvalPlayerList[previousIndex]) {
const previousPlayerId = this.approvalPlayerList[previousIndex].playerId;
// 先重置轮播索引,避免切换过程中出现空白
this.currentRoomIndex = 0;
this.getApprovalDetailData(previousPlayerId);
}
} else {
}
},
toNextRecord() {
if (this.canNext === true) {
// 导航到下一个玩家
const nextIndex = this.currentPlayerIndex + 1;
if (nextIndex < this.approvalPlayerList.length && this.approvalPlayerList[nextIndex]) {
const nextPlayerId = this.approvalPlayerList[nextIndex].playerId;
// 先重置轮播索引,避免切换过程中出现空白
this.currentRoomIndex = 0;
this.getApprovalDetailData(nextPlayerId);
}
}
},
// 处理轮播图切换事件
handleSwiperChange(e) {
this.currentRoomIndex = e.detail.current;
this.updateSelectableDates();
},
// 触摸开始事件
touchStart(e) {
this.touchStartX = e.touches[0].clientX;
},
// 触摸结束事件
touchEnd(e) {
this.touchEndX = e.changedTouches[0].clientX;
this.handleSwipe();
},
// 处理滑动事件
handleSwipe() {
const swipeThreshold = 30; // 滑动阈值
// 向左滑动
if (this.touchStartX - this.touchEndX > swipeThreshold) {
this.currentRoomIndex = (this.currentRoomIndex + 1) % this.roomList.length;
this.updateSelectableDates();
}
// 向右滑动
else if (this.touchEndX - this.touchStartX > swipeThreshold) {
this.currentRoomIndex = (this.currentRoomIndex - 1 + this.roomList.length) % this.roomList.length;
this.updateSelectableDates();
}
},
// 更新可选日期范围
updateSelectableDates() {
const currentRoom = this.roomList[this.currentRoomIndex];
if (currentRoom) {
// 从 bookingListData 中获取原始日期范围作为可选范围
const originalBooking = this.bookingListData.find(item => item.id === currentRoom.id);
if (originalBooking) {
// 可选日期范围保持为原始日期
this.selectAbleStart = originalBooking.checkinDate;
this.selectAbleEnd = originalBooking.checkoutDate;
// 但默认显示的日期应该是当前房间的当前日期(可能已经被修改过的)
this.calendarStartDate = currentRoom.checkinDate;
this.calendarEndDate = currentRoom.checkoutDate;
}
}
},
// 切换房间选择状态
toggleSelection(index) {
this.roomList[index].selected = !this.roomList[index].selected;
},
showReject() {
// 设置当前操作类型为 reject
this.currentAction = 'reject';
this.iconPath = '../../static/images/ico_err.png';
this.popMsgStr = this.$t("approval.submitReject");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = true;
},
async confirmReject() {
if (this.approvalLoading || this.roomList.some(r => r.selected)) return;
uni.showLoading({
title: this.$t("common.loading")
});
// 获取当前轮播图显示的房间信息
const currentRoom = this.roomList[this.currentRoomIndex];
try {
let params = {
bookingId: currentRoom.id
};
const res = await rejectApproval(params);
if (res.success == true) {
if (res.data !== null) {
this.iconPath = '../../static/images/ico_suc.png';
this.popMsgStr = this.$t("bookingConfirm.rejectSuccess");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = false;
}
} else {
this.buttonStr = this.$t("common.ok");
this.iconPath = '../../static/images/ico_err.png';
this.msgStr = res.message!=null?res.message:this.$t("common.rejectFail");
this.url = '';
this.showReturnMsgBox = true;
}
} catch (e) {
console.error(e);
uni.$u.toast(e.errMsg, 5000);
var request = e.config != undefined ? JSON.stringify(e.config) : "";
var response = e.data != undefined ? JSON.stringify(e.data) : "";
await this.writeLog(this.userData.userId, "find_player", "",
"[APP][findPlayer.vue][getProfileByPlayerId][Catch Exception]" + e.errMsg, request,
response, 1, false);
} finally {
uni.hideLoading();
}
// 延时显示Success
setTimeout(() => {}, 1000);
},
// 批量批准
async handleBatchApprove() {
uni.showLoading({
title: this.$t("common.loading")
});
try {
const selectedRooms = this.roomList.filter(room => room.selected);
// 新建参数,包含每个房间的 RoomId、checkindate 和 checkoutdate
const roomInfoList = selectedRooms.map(room => ({
bookingId: room.id,
checkinDate: room.checkinDate,
checkoutDate: room.checkoutDate
}));
const params = {submitInfoList:roomInfoList};
const res = await batchSubmitApproval(params);
this.showMsgBox = false;
if (res.success == true) {
this.iconPath = '../../static/images/suc.png';
this.popMsgStr = this.$t("bookingConfirm.approvalSuccess");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = false;
} else {
this.buttonStr = this.$t("common.ok");
this.iconPath = '../../static/images/ico_err.png';
this.msgStr = res.message!=null?res.message:this.$t("common.appro")
this.url = '';
this.showReturnMsgBox = true;
}
} catch (e) {
console.error(e);
uni.$u.toast(e.errMsg, 5000);
var request = e.config != undefined ? JSON.stringify(e.config) : "";
var response = e.data != undefined ? JSON.stringify(e.data) : "";
await this.writeLog(this.userData.userId, "batch_approval", "",
"[APP][playerDetail.vue][handleBatchApprove][Catch Exception]" + e.errMsg, request,
response, 1, false);
} finally {
uni.hideLoading();
}
this.roomList.forEach(room => room.selected = false);
},
// 批量拒绝
async handleBatchReject() {
uni.showLoading({
title: this.$t("common.loading")
});
try {
const selectedRooms = this.roomList.filter(room => room.selected);
// 新建参数,包含每个房间的 RoomId、checkindate 和 checkoutdate
const roomInfoList = selectedRooms.map(room => ({
bookingId: room.id
}));
const params = {submitInfoList:roomInfoList};
const res = await batchSubmitReject(params);
this.showMsgBox = false;
if (res.success == true) {
this.iconPath = '../../static/images/suc.png';
this.popMsgStr = this.$t("bookingConfirm.rejectSuccess");
this.showMsgBox = true; // 显示整个弹窗
this.showSubmit = false;
} else {
this.buttonStr = this.$t("common.ok");
this.iconPath = '../../static/images/ico_err.png';
this.msgStr = this.$t("common.rejectFail") +":"+ res.message;
this.url = '';
this.showReturnMsgBox = true;
}
} catch (e) {
console.error(e);
uni.$u.toast(e.errMsg, 5000);
var request = e.config != undefined ? JSON.stringify(e.config) : "";
var response = e.data != undefined ? JSON.stringify(e.data) : "";
await this.writeLog(this.userData.userId, "batch_approval", "",
"[APP][playerDetail.vue][handleBatchApprove][Catch Exception]" + e.errMsg, request,
response, 1, false);
} finally {
uni.hideLoading();
}
this.roomList.forEach(room => room.selected = false);
}
},
onShow() {
// 手动触发水印更新,确保水印在页面显示时正确显示
this.$nextTick(() => {
setTimeout(() => {
console.log('[TodoList] Manually triggering watermark update on show');
const watermarkStore = require('@/store/watermark.js');
if (watermarkStore && watermarkStore.updateWatermark) {
watermarkStore.updateWatermark(true);
}
}, 500);
});
},
onLoad(opt) {
this.deviceData = uni.getStorageSync("deviceData");
this.windowWidth = this.deviceData.windowWidth - 70;
this.searchPlayerId = opt.playerId;
this.approvalPlayerList = uni.getStorageSync("approvalPlayerList");
if (this.searchPlayerId != null) this.getApprovalDetailData()
},
onReady() {
// 页面首次渲染完成后,延迟触发水印更新
setTimeout(() => {
console.log('[TodoList] Triggering watermark update on ready');
const watermarkStore = require('@/store/watermark.js');
if (watermarkStore && watermarkStore.updateWatermark) {
watermarkStore.updateWatermark(true);
}
}, 1200);
}
}
</script>
<style scoped>
/* 悬浮栏样式 - 显示在tabbar上方 */
.floating-bar {
position: fixed;
bottom: 65px;
/* tabbar高度 */
left: 0;
right: 0;
background-color: #ffffff;
border-top: 1px solid #e4e7ed;
border-radius: 25px;
padding: 10px 15px;
margin: 0px 10px;
z-index: 99;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
}
.floating-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.selected-count {
font-size: 14px;
color: #606266;
font-weight: 500;
}
.floating-actions {
display: flex;
gap: 10px;
}
.action-btn {
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
.approve-btn {
background-color: #C39A4B;
color: #ffffff;
}
.reject-btn {
background-color:#C39A4B;
color: #ffffff;
}
.infoButton {
border-bottom: 0.5px #999 solid;
padding-bottom: 6px;
margin-top: 6px;
}
.dataMargin {
margin-bottom: 3px;
}
</style>