merge limo to daylight
This commit is contained in:
@@ -0,0 +1,827 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="hz-page">
|
||||
<u-navbar
|
||||
@leftClick="back()"
|
||||
:safeAreaInsetTop="true"
|
||||
:placeholder="true"
|
||||
:title="title"
|
||||
:fixed="true"
|
||||
:autoBack="false"
|
||||
leftIconColor="#000000"
|
||||
titleStyle="font-weight:bold;"
|
||||
v-if="NotCapping"
|
||||
>
|
||||
<view
|
||||
style="margin-top:2px;margin-right:3px;"
|
||||
slot="right"
|
||||
>
|
||||
<view style="border:1rpx solid #ccc;border-radius: 14px;padding:4px 12px;" class="hz-flex-row hz-flex-vertical-mid">
|
||||
<image @click="navTo('/pages/findPlayer/findPlayer',1,false)" src="../../static/images/ico_find_player.png" class="hz-nav-btn"></image>
|
||||
<view style="height:20px;border-left:1px solid #ccc;margin-left:8px;margin-right:8px;"></view>
|
||||
<image @click="navTo('/booking/bookingRecord/bookingRecord?from=booking',2,false)" src="../../static/images/ico_list.png" class="hz-nav-btn"></image>
|
||||
</view>
|
||||
</view>
|
||||
</u-navbar>
|
||||
|
||||
<view v-if="limoData" class="hz-spacing hz-bg-white" style="margin-top:8px;">
|
||||
<view class="hz-flex-row" v-if="!NotCapping" style="margin-top:20rpx;justify-content: center;">
|
||||
<image src="../../static/images/mgm_logo_1.png" style="width:130px;height:40px;"></image>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-pd-30 hz-font-md hz-font-bolder hz-card-booking" style="margin-top:20rpx;align-items:center;">
|
||||
<view style="width:72%;">Conf # : {{ getConfirmationNo(limoData) }}</view>
|
||||
<view class="hz-btn-status hz-text-center hz-limo-status-tag" :style="getLimoStatusStyle(limoData.status)">{{ getStatusText(limoData) }}</view>
|
||||
</view>
|
||||
|
||||
<view class="hz-card-profile hz-mr-b-30 hz-mr-t-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" >{{ playerData.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" >{{ playerData.tierName }}</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" >{{playerData.salutation + " " + playerData.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="hz-pd-30 hz-font-bolder hz-font-md hz-card-extend limo-info-card" style="margin-top:10px;">
|
||||
<view class="limo-info-grid">
|
||||
<view class="limo-info-item">
|
||||
<image src="../../static/images/ico_calendar.png" class="limo-info-icon"></image>
|
||||
<view class="hz-font-bold hz-font-md">{{ getPickupDate(limoData.pickUpDate) }}</view>
|
||||
</view>
|
||||
<view class="limo-info-item">
|
||||
<image src="../../static/images/clock.png" class="limo-info-icon"></image>
|
||||
<view class="hz-font-bold hz-font-md">{{ getPickupTime(limoData.pickUpDate) }}</view>
|
||||
</view>
|
||||
<view class="limo-info-item">
|
||||
<u-icon name="account-fill" size="18" color="#C39A4B" class="limo-info-icon"></u-icon>
|
||||
<view>{{ limoData.noOfPax }} Pax</view>
|
||||
</view>
|
||||
<!-- <view class="limo-info-item">
|
||||
<image src="../../static/images/car_no.png" class="limo-info-icon"></image>
|
||||
<view class="hz-font-bold hz-font-md">{{ getCarNo(limoData.carNo) }}</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<view v-if="canEditLimo(limoData)" @click="editLimoBooking()" class="limo-edit-button">
|
||||
<image src="/static/images/edit.png" mode="aspectFit" class="limo-edit-icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="hz-spacing hz-mr-t-30" style="margin-bottom:30px;">
|
||||
<view class="hz-flex-row">
|
||||
<view style="width:100%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.pickupPoint")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{limoData.pickUpPoint}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-mr-t-30">
|
||||
<view v-if="limoData.flightDetail!=null && limoData.flightDetail != ''" style="width:55%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.flightNo")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">
|
||||
<view>
|
||||
{{ limoData.flightDetail }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="limoData.greetType!=null && limoData.greetType != ''" style="width:45%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.greetType")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">
|
||||
<view>
|
||||
{{ limoData.greetType }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="hasExtraDropOffPoint(limoData)" class="hz-flex-row hz-mr-t-30">
|
||||
<view style="width:100%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.extraDropoff")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">
|
||||
<view v-for="(extraDropOffPoint,index) in getExtraDropOffPointDisplayItems(limoData.extraDropOffPoint)" :key="'extra-dropoff-'+index">
|
||||
<view>#{{index + 1}} {{extraDropOffPoint.zh}}</view>
|
||||
<view v-if="extraDropOffPoint.en">{{extraDropOffPoint.en}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-mr-t-30">
|
||||
<view style="width:100%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.dropoffPoint")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">
|
||||
<view v-for="(dropOffPoint,index) in getDropOffPointLines(limoData.dropOffPoint)" :key="'dropoff-'+index">
|
||||
{{dropOffPoint}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-mr-t-30">
|
||||
<view style="width:55%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("bookingConfirm.createdOn")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{limoData.createdAt}}</view>
|
||||
</view>
|
||||
<view style="width:45%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("bookingConfirm.createdBy")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{limoData.createdBy ? limoData.createdBy : '-'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-mr-t-30">
|
||||
<view v-if="NotCapping" style="width:55%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.overrideBy")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{limoData.overrideBy ? limoData.overrideBy : '-'}}</view>
|
||||
</view>
|
||||
<view style="width:45%">
|
||||
<view class="hz-flex-row hz-mr-t-30" @click="copyDriverInfo(limoData)">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.carTypeAndPlate")}}</view>
|
||||
<image src="/static/images/copy.png" style="height: 20px;width: 20px"></image>
|
||||
</view>
|
||||
<view class="hz-font-bolder hz-font-lg" style="white-space: pre-wrap;">{{formatCarTypeAndCarNo(limoData)}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-mr-t-30">
|
||||
<view v-if="NotCapping" style="width:55%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.tripPrice")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{formatTripPrice(limoData.totalAmount)}}</view>
|
||||
</view>
|
||||
<view v-if="!NotCapping" style="width:55%">
|
||||
</view>
|
||||
<view style="width:45%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.driverContact")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" style="white-space: pre-wrap;">{{GetDriverContact(limoData)}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="NotCapping" class="hz-flex-row hz-mr-t-30">
|
||||
<view style="width:55%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.driverSource")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{limoData.driverSource != null && limoData.driverSource != '' ? limoData.driverSource : "N/A"}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="limoData.remarks != null && limoData.remarks != '' && NotCapping" class="hz-flex-row hz-mr-t-30">
|
||||
<view style="width:100%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{$t("limoBookingDetail.remark")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{ limoData.remarks }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="height:100rpx;"></view>
|
||||
</view>
|
||||
|
||||
<u-empty
|
||||
v-if="loadError"
|
||||
mode="search"
|
||||
:text="dataNotFoundStr"
|
||||
>
|
||||
</u-empty>
|
||||
|
||||
<u-tabbar
|
||||
:fixed="true"
|
||||
:placeholder="true"
|
||||
:safeAreaInsetBottom="true"
|
||||
customStyle="z-index:100;height:58px;"
|
||||
v-if="limoData && showTabbar"
|
||||
>
|
||||
<view class="book hz-flex-row hz-spacing" style="width: 45%;">
|
||||
<view class="hz-btn hz-font-color-white hz-font-sm hz-font-bold hz-text-center" @click="popupLang()">
|
||||
{{$t("bookingDetail.saveImage")}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="book hz-flex-row hz-spacing" style="width: 45%;" :class="limoData.status !=='PENDING' ? 'hz-disabled' :''">
|
||||
<view class="hz-btn hz-font-color-white hz-font-sm hz-font-bold hz-text-center" @click="cancelLimoBooking()">
|
||||
{{$t("bookingDetail.cancelBooking")}}
|
||||
</view>
|
||||
</view>
|
||||
</u-tabbar>
|
||||
<u-popup :show="showCancelBookingSuccessPopup" mode="center" round="16px" :closeable="false" @close="closeCancelBookingSuccessPopup">
|
||||
<view class="booking-popup-card booking-popup-card--success"
|
||||
:style="'width:' + windowWidth + 'px;'">
|
||||
<view class="booking-popup-icon-row">
|
||||
<image :src="iconPath" style="width:64px;height:64px;"></image>
|
||||
</view>
|
||||
<view class="booking-popup-title booking-popup-title--success hz-font-md hz-font-bold hz-text-center">
|
||||
Cancel Booking Successfully
|
||||
</view>
|
||||
<view
|
||||
@click="closeCancelBookingSuccessPopup"
|
||||
class="booking-popup-button booking-popup-button--primary booking-popup-button--success hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center"
|
||||
>
|
||||
OK
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<u-popup :show="showSaveImageSuccessPopup" mode="center" round="16px" :closeable="false" @close="closeSaveImageSuccessPopup">
|
||||
<view class="booking-popup-card booking-popup-card--success"
|
||||
:style="'width:' + windowWidth + 'px;'">
|
||||
<view class="booking-popup-icon-row">
|
||||
<image src="../../static/images/ico_suc.png" style="width:64px;height:64px;"></image>
|
||||
</view>
|
||||
<view class="booking-popup-title booking-popup-title--success hz-font-md hz-font-bold hz-text-center">
|
||||
Image Saved Successfully
|
||||
</view>
|
||||
<view
|
||||
@click="closeSaveImageSuccessPopup"
|
||||
class="booking-popup-button booking-popup-button--primary booking-popup-button--success hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center"
|
||||
>
|
||||
OK
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<u-picker closeOnClickOverlay :show="showPicker" :defaultIndex="currentLangIndex" :columns="langList" @close="showPicker=false" :cancelText="cancelText" :confirmText="okText" confirmColor="#C39A4B" @cancel="showPicker=false" @confirm="confirmLang" keyName="name"></u-picker>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getLimoBookingById, getLimoBookingByConf } from '../../api/limoApi.js';
|
||||
import { cancelLimoBooking } from '../../api/limoApi.js';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
playerData:null,
|
||||
userData:null,
|
||||
deviceData:null,
|
||||
limoData:null,
|
||||
loadError:false,
|
||||
dataNotFoundStr:this.$t("common.dataNotFound"),
|
||||
title:'',
|
||||
from:'',
|
||||
conf:'',
|
||||
windowWidth:0,
|
||||
showSaveImageSuccessPopup:false,
|
||||
showCancelBookingSuccessPopup:false,
|
||||
NotCapping:true,
|
||||
showTabbar:true,
|
||||
showWhenScreenshot:true,
|
||||
capture:'',
|
||||
showPicker:false,
|
||||
lang:'',
|
||||
langList:[
|
||||
[{
|
||||
name: 'English',
|
||||
code: 'en'
|
||||
}, {
|
||||
name: '繁體中文',
|
||||
code: 'zh-Hant'
|
||||
}]
|
||||
],
|
||||
currentLangIndex:[0],
|
||||
cancelText:this.$t("common.cancel"),
|
||||
okText:this.$t("common.ok"),
|
||||
iconPath: ''
|
||||
}
|
||||
},
|
||||
onLoad(opt) {
|
||||
this.initUI();
|
||||
this.playerData = uni.getStorageSync("playerData");
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
this.deviceData = uni.getStorageSync("deviceData");
|
||||
this.windowWidth = this.deviceData && this.deviceData.windowWidth ? this.deviceData.windowWidth - 70 : 290;
|
||||
if(opt.from!==undefined && opt.from!='') this.from = opt.from;
|
||||
if(opt.conf!==undefined && opt.conf!='') this.conf = opt.conf;
|
||||
// this.getLimoData();
|
||||
this.getBooking(opt);
|
||||
},
|
||||
onShow() {
|
||||
this.$i18n.locale = uni.getLocale();
|
||||
},
|
||||
methods: {
|
||||
initUI() {
|
||||
this.title = this.$t("bookingDetail.title");
|
||||
},
|
||||
restoreScreenshotView() {
|
||||
this.NotCapping = true;
|
||||
this.showTabbar = true;
|
||||
this.showWhenScreenshot = true;
|
||||
},
|
||||
// #ifdef APP-PLUS
|
||||
async captureWebview() {
|
||||
uni.pageScrollTo({
|
||||
scrollTop: 0
|
||||
});
|
||||
this.NotCapping = false;
|
||||
this.showTabbar = false;
|
||||
this.showWhenScreenshot = false;
|
||||
await uni.$u.sleep(1000);
|
||||
var _this = this;
|
||||
var ws = plus.webview.getTopWebview();
|
||||
var bitmap = new plus.nativeObj.Bitmap('capScreen');
|
||||
ws.draw(bitmap, function(){
|
||||
console.log('截屏绘制图片成功');
|
||||
bitmap.save('_doc/a.png', {},
|
||||
async function(e){
|
||||
console.log('保存图片成功:' + JSON.stringify(e));
|
||||
await uni.$u.sleep(1000);
|
||||
_this.restoreScreenshotView();
|
||||
plus.gallery.save(e.target, () => {
|
||||
plus.nativeUI.toast(_this.$t("common.picSaveSuccess"));
|
||||
}, (err) => {
|
||||
console.log('保存到相册失败:' + JSON.stringify(err));
|
||||
});
|
||||
},
|
||||
function(e){
|
||||
console.log('保存图片失败:' + JSON.stringify(e));
|
||||
_this.restoreScreenshotView();
|
||||
}
|
||||
);
|
||||
_this.capture = bitmap.toBase64Data();
|
||||
bitmap.recycle();
|
||||
}, function(e){
|
||||
console.log('截屏绘制图片失败:' + JSON.stringify(e));
|
||||
_this.restoreScreenshotView();
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
back(){
|
||||
if(this.from==='list'){
|
||||
this.navTo('/booking/bookingRecord/bookingRecord?from=booking',2,false);
|
||||
}else{
|
||||
this.navBack();
|
||||
}
|
||||
},
|
||||
getPickupDate(str){
|
||||
if(!str) return '';
|
||||
let datePart = str.split(' ')[0];
|
||||
// Assume DD/MM/YYYY
|
||||
let parts = datePart.split('/');
|
||||
if(parts.length===3){
|
||||
let dateObj = new Date(parts[2], parts[1]-1, parts[0]);
|
||||
let weeks = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
|
||||
let week = weeks[dateObj.getDay()];
|
||||
return `(${week}) ${parts[2]}-${parts[1]}-${parts[0]}`;
|
||||
}
|
||||
return datePart;
|
||||
},
|
||||
getPickupTime(str){
|
||||
if(!str) return '';
|
||||
return str.split(' ')[1] || '';
|
||||
},
|
||||
getCarNo(carNo){
|
||||
if(carNo!== undefined && carNo !== null && carNo !== ''){
|
||||
return carNo
|
||||
}else{
|
||||
return 'N/A';
|
||||
}
|
||||
},
|
||||
getDropOffPointLines(dropOffPoint){
|
||||
if(dropOffPoint === null || dropOffPoint === undefined || dropOffPoint === '') return [''];
|
||||
return String(dropOffPoint).split(/[;;]/).map(item => item.trim()).filter(item => item !== '');
|
||||
},
|
||||
getExtraDropOffPointDisplayItems(extraDropOffPoint) {
|
||||
return this.getDropOffPointLines(extraDropOffPoint).map((item) => {
|
||||
const parts = String(item).split('/');
|
||||
return {
|
||||
zh: String(parts[0] || '').trim(),
|
||||
en: String(parts.slice(1).join('/') || '').trim()
|
||||
};
|
||||
});
|
||||
},
|
||||
getExtraDropOffPointFromBooking(booking) {
|
||||
if (!booking) {
|
||||
return '';
|
||||
}
|
||||
const value =
|
||||
booking.extraDropOffPoint != null && String(booking.extraDropOffPoint).trim() !== ''
|
||||
? booking.extraDropOffPoint
|
||||
: '';
|
||||
return String(value || '').trim();
|
||||
},
|
||||
hasExtraDropOffPoint(limoData) {
|
||||
return (
|
||||
limoData &&
|
||||
limoData.extraDropOffPoint != null &&
|
||||
String(limoData.extraDropOffPoint).trim() !== ''
|
||||
);
|
||||
},
|
||||
formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||
if(date === null || date === undefined || date === '') return '';
|
||||
let normalizedDate = date;
|
||||
if(typeof normalizedDate === 'string' && /^\d+$/.test(normalizedDate)){
|
||||
normalizedDate = Number(normalizedDate);
|
||||
}
|
||||
if(typeof normalizedDate === 'number' && normalizedDate < 1000000000000){
|
||||
normalizedDate = normalizedDate * 1000;
|
||||
}
|
||||
const d = new Date(normalizedDate);
|
||||
if(Number.isNaN(d.getTime())) return '';
|
||||
|
||||
const map = {
|
||||
YYYY: d.getFullYear(),
|
||||
MM: String(d.getMonth() + 1).padStart(2, '0'),
|
||||
DD: String(d.getDate()).padStart(2, '0'),
|
||||
HH: String(d.getHours()).padStart(2, '0'),
|
||||
mm: String(d.getMinutes()).padStart(2, '0'),
|
||||
ss: String(d.getSeconds()).padStart(2, '0')
|
||||
};
|
||||
return format.replace(/YYYY|MM|DD|HH|mm|ss/g, matched => map[matched]);
|
||||
},
|
||||
normalizeStatus(status){
|
||||
if(status==null || status===undefined){
|
||||
return '';
|
||||
}
|
||||
return String(status).toUpperCase().replace(/\s+/g,' ').trim();
|
||||
},
|
||||
canEditLimo(limo){
|
||||
return this.normalizeStatus(limo && limo.status) === 'PENDING';
|
||||
},
|
||||
getLimoStatusStyle(status){
|
||||
const normalizedStatus = this.normalizeStatus(status);
|
||||
const style = {
|
||||
minWidth: 'auto',
|
||||
height: 'auto',
|
||||
lineHeight: '1.2',
|
||||
whiteSpace: 'nowrap',
|
||||
paddingTop: '6px',
|
||||
paddingBottom: '6px',
|
||||
paddingLeft: '12px',
|
||||
paddingRight: '12px',
|
||||
flex: 1,
|
||||
borderRadius: '6px',
|
||||
fontSize: '12px',
|
||||
fontWeight: '700',
|
||||
backgroundColor: 'rgb(148, 148, 148)',
|
||||
color: '#ffffff'
|
||||
};
|
||||
if(normalizedStatus === 'CONFIRMED'){
|
||||
style.backgroundColor = '#439048';
|
||||
}
|
||||
if(normalizedStatus === 'DRIVER_DEPARTED'){
|
||||
style.backgroundColor = '#439048';
|
||||
}
|
||||
if(normalizedStatus === 'DRIVER_ASSIGNED'){
|
||||
style.backgroundColor = '#439048';
|
||||
}
|
||||
if(normalizedStatus === 'DRIVER_ARRIVED'){
|
||||
style.backgroundColor = '#439048';
|
||||
}
|
||||
if(normalizedStatus === 'GUEST_PICKED'){
|
||||
style.backgroundColor = '#439048';
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
editLimoBooking(){
|
||||
if(!this.canEditLimo(this.limoData)){
|
||||
return;
|
||||
}
|
||||
uni.setStorageSync('limoEditData', this.limoData);
|
||||
this.navTo('/limo/newLimo/newLimo?mode=edit&from=limoDetail',0,false);
|
||||
},
|
||||
async cancelLimoBooking() {
|
||||
if(this.limoData.status !== 'PENDING') return null;
|
||||
|
||||
let updatedBy = this.limoData.updatedBy;
|
||||
let bookingId = this.limoData.id;
|
||||
|
||||
let params = {
|
||||
updatedBy: updatedBy,
|
||||
id: bookingId
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await cancelLimoBooking(params);
|
||||
if(res && res.success) {
|
||||
this.iconPath = '../../static/images/ico_suc.png';
|
||||
this.showCancelBookingSuccessPopup = true;
|
||||
} else {
|
||||
this.iconPath = '../../static/images/ico_err.png';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
showSaveImageSuccessDialog(){
|
||||
this.showSaveImageSuccessPopup = true;
|
||||
},
|
||||
popupLang(){
|
||||
this.currentLangIndex = [];
|
||||
for(let i=0;i<this.langList[0].length;i++){
|
||||
if(this.langList[0][i].code === this.$i18n.locale){
|
||||
this.currentLangIndex.push(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.showPicker = true;
|
||||
},
|
||||
async confirmLang(e){
|
||||
this.$i18n.locale = e.value[0].code;
|
||||
this.lang = e.value[0].name;
|
||||
this.title = this.$t("bookingDetail.title");
|
||||
this.cancelText = this.$t("common.cancel");
|
||||
this.okText = this.$t("common.ok");
|
||||
this.showPicker = false;
|
||||
this.captureWebview();
|
||||
},
|
||||
closeSaveImageSuccessPopup(){
|
||||
this.showSaveImageSuccessPopup = false;
|
||||
},
|
||||
closeCancelBookingSuccessPopup(){
|
||||
this.showCancelBookingSuccessPopup = false;
|
||||
this.navTo('/booking/bookingRecord/bookingRecord?from=booking',2,false);
|
||||
},
|
||||
getLimoData(){
|
||||
const limoBookingList = [];
|
||||
getBooking();
|
||||
|
||||
},
|
||||
async getDataByConfNo(confNo) {
|
||||
if (confNo == null || confNo === '' || confNo === 'null') {
|
||||
return;
|
||||
}
|
||||
await this.getLimoBookingByConf(confNo);
|
||||
},
|
||||
async getLimoBookingByConf(conf,id) {
|
||||
this.loadError = false;
|
||||
uni.showLoading({ title: this.$t("common.loading") });
|
||||
try{
|
||||
let params = {};
|
||||
params.conf = conf;
|
||||
const res = await getLimoBookingByConf(params);
|
||||
if(res!=null && res.success==true){
|
||||
|
||||
let tempBooking = res.data;
|
||||
|
||||
let temp = {
|
||||
id: tempBooking.id,
|
||||
confirmationNo: tempBooking.confirmationNo,
|
||||
status: tempBooking.bookingStatus,
|
||||
bookingType: tempBooking.bookingType,
|
||||
serviceType: tempBooking.serviceType,
|
||||
pickUpDate: this.formatDate(tempBooking.pickUpDatetime, 'DD/MM/YYYY HH:mm'),
|
||||
greetType: tempBooking.greetType,
|
||||
signage: tempBooking.signage,
|
||||
tripPrice: tempBooking.tripPrice,
|
||||
tripContact: tempBooking.tripContact,
|
||||
bookingContact: tempBooking.bookingContact,
|
||||
tenOutContact: tempBooking.tenOutContact,
|
||||
guestContact: tempBooking.guestContact,
|
||||
isHighImportance: tempBooking.isHighImportance,
|
||||
isTenOut: tempBooking.isTenOut,
|
||||
isConnectGuestDirectly: tempBooking.isConnectGuestDirectly,
|
||||
noOfPax: tempBooking.noOfPax,
|
||||
pickUpPoint: tempBooking.pickUpPoint,
|
||||
carType: tempBooking.carType,
|
||||
extraDropOffPoint: this.getExtraDropOffPointFromBooking(tempBooking),
|
||||
extraOffPoint: this.getExtraDropOffPointFromBooking(tempBooking),
|
||||
dropOffPoint: tempBooking.dropOffPoint,
|
||||
remarks: tempBooking.remarks,
|
||||
isHourlyRate: tempBooking.isHourlyRate,
|
||||
hourlyRate: tempBooking.hourlyRate,
|
||||
flightDetail: tempBooking.flightDetail,
|
||||
flightEta: tempBooking.flightEta,
|
||||
flightStatus: tempBooking.flightStatus,
|
||||
approver: tempBooking.approver,
|
||||
approverId: tempBooking.approverId,
|
||||
paymentMethod: tempBooking.paymentMethod,
|
||||
createdAt: this.formatDate(tempBooking.createdAt, "YYYY-MM-DD HH:mm:ss"),
|
||||
createdBy: tempBooking.createdBy,
|
||||
overrideBy: tempBooking.overrideBy,
|
||||
carNo:tempBooking.carNo,
|
||||
driverContact:tempBooking.driverContact,
|
||||
driverSource:tempBooking.driverSource,
|
||||
totalAmount:tempBooking.totalAmount
|
||||
}
|
||||
|
||||
this.limoData = temp;
|
||||
|
||||
|
||||
}else{
|
||||
this.loadError = true;
|
||||
uni.$u.toast(res.message,5000);
|
||||
}
|
||||
}catch(e){
|
||||
this.loadError = true;
|
||||
console.error(e);
|
||||
uni.$u.toast(e.errMsg,5000);
|
||||
}finally{
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
async getLimoBookingById(id) {
|
||||
this.loadError = false;
|
||||
uni.showLoading({ title: this.$t("common.loading") });
|
||||
try{
|
||||
let params = {};
|
||||
params.id = id;
|
||||
const res = await getLimoBookingById(params);
|
||||
if(res!=null && res.success==true){
|
||||
|
||||
let tempBooking = res.data;
|
||||
|
||||
let temp = {
|
||||
id: tempBooking.id,
|
||||
confirmationNo: tempBooking.confirmationNo,
|
||||
status: tempBooking.bookingStatus,
|
||||
bookingType: tempBooking.bookingType,
|
||||
serviceType: tempBooking.serviceType,
|
||||
pickUpDate: this.formatDate(tempBooking.pickUpDatetime, 'DD/MM/YYYY HH:mm'),
|
||||
greetType: tempBooking.greetType,
|
||||
signage: tempBooking.signage,
|
||||
tripPrice: tempBooking.tripPrice,
|
||||
tripContact: tempBooking.tripContact,
|
||||
bookingContact: tempBooking.bookingContact,
|
||||
tenOutContact: tempBooking.tenOutContact,
|
||||
guestContact: tempBooking.guestContact,
|
||||
isHighImportance: tempBooking.isHighImportance,
|
||||
isTenOut: tempBooking.isTenOut,
|
||||
isConnectGuestDirectly: tempBooking.isConnectGuestDirectly,
|
||||
noOfPax: tempBooking.noOfPax,
|
||||
pickUpPoint: tempBooking.pickUpPoint,
|
||||
carType: tempBooking.carType,
|
||||
extraDropOffPoint: this.getExtraDropOffPointFromBooking(tempBooking),
|
||||
extraOffPoint: this.getExtraDropOffPointFromBooking(tempBooking),
|
||||
dropOffPoint: tempBooking.dropOffPoint,
|
||||
remarks: tempBooking.remarks,
|
||||
isHourlyRate: tempBooking.isHourlyRate,
|
||||
hourlyRate: tempBooking.hourlyRate,
|
||||
flightDetail: tempBooking.flightDetail,
|
||||
flightEta: tempBooking.flightEta,
|
||||
flightStatus: tempBooking.flightStatus,
|
||||
approver: tempBooking.approver,
|
||||
approverId: tempBooking.approverId,
|
||||
paymentMethod: tempBooking.paymentMethod,
|
||||
createdAt: this.formatDate(tempBooking.createdAt, "YYYY-MM-DD HH-mm-ss"),
|
||||
createdBy: tempBooking.createdBy,
|
||||
overrideBy: tempBooking.overrideBy,
|
||||
totalAmount:tempBooking.totalAmount
|
||||
}
|
||||
|
||||
this.limoData = temp;
|
||||
}else{
|
||||
this.loadError = true;
|
||||
uni.$u.toast(res.message,5000);
|
||||
}
|
||||
}catch(e){
|
||||
this.loadError = true;
|
||||
console.error(e);
|
||||
uni.$u.toast(e.errMsg,5000);
|
||||
}finally{
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
getBooking(opt) {
|
||||
const confNo =
|
||||
opt.confNo != null && opt.confNo !== '' && opt.confNo !== 'null'
|
||||
? opt.confNo
|
||||
: opt.conf;
|
||||
if (
|
||||
confNo != null &&
|
||||
confNo !== undefined &&
|
||||
confNo !== '' &&
|
||||
confNo !== 'null'
|
||||
) {
|
||||
this.getDataByConfNo(confNo);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
opt.id != null &&
|
||||
opt.id !== undefined &&
|
||||
opt.id !== '' &&
|
||||
opt.id !== 'null'
|
||||
) {
|
||||
this.getLimoBookingById(opt.id);
|
||||
}
|
||||
},
|
||||
formatTripPrice(value) {
|
||||
if (value === null || value === undefined || value === '') return '-';
|
||||
const text = String(value).replace(/,/g, '');
|
||||
const parts = text.split('.');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return parts.join('.');
|
||||
},
|
||||
formatCarTypeAndCarNo(limoBooking) {
|
||||
const carType = limoBooking.carType !== null ? limoBooking.carType : 'N/A';
|
||||
const carNo = this.getCarNo(limoBooking.carNo);
|
||||
console.log(limoBooking);
|
||||
return ""+carType + "\n (" + carNo+")";
|
||||
},
|
||||
GetDriverContact(limoBooking) {
|
||||
const driverContact = limoBooking && limoBooking.driverContact != null
|
||||
? String(limoBooking.driverContact).trim()
|
||||
: '';
|
||||
if (!driverContact) {
|
||||
return 'N/A';
|
||||
}
|
||||
const phoneNumbers = driverContact
|
||||
.split(/[,,]/)
|
||||
.map((phoneNumber) => phoneNumber.trim())
|
||||
.filter(Boolean);
|
||||
if (phoneNumbers.length <= 1) {
|
||||
return phoneNumbers[0] || 'N/A';
|
||||
}
|
||||
return phoneNumbers
|
||||
.map((phoneNumber, index) => `Phone No${index + 1}:${phoneNumber}`)
|
||||
.join('\n');
|
||||
},
|
||||
copyDriverInfo(limoBooking){
|
||||
const carType = limoBooking.carType !== null ? limoBooking.carType : 'N/A';
|
||||
const carNo = this.getCarNo(limoBooking.carNo);
|
||||
const driverContact = limoBooking.driverContact != null && limoBooking.driverContact != undefined && limoBooking.driverContact != "" ? limoBooking.driverContact : 'N/A';
|
||||
const locale = this.$i18n && this.$i18n.locale ? this.$i18n.locale : uni.getLocale();
|
||||
const isEnglish = String(locale || '').toLowerCase().startsWith('en');
|
||||
const data = isEnglish
|
||||
? `The details of your reserved limousine service are as follows:\nVehicle Type: ${carType}\nLicense Plate: ${carNo}\nDriver Phone: ${driverContact}`
|
||||
: `阁下预订的贵宾车资料如下:\n車型:${carType}\n車牌號碼:${carNo}\n司機電話:${driverContact}`;
|
||||
uni.setClipboardData({
|
||||
data: data,
|
||||
success: function () {
|
||||
//调用方法成功
|
||||
console.log('success');
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
getConfirmationNo(){
|
||||
return function (booking) {
|
||||
if(booking!==undefined && booking!==null){
|
||||
if(booking.confirmationNo!==undefined && booking.confirmationNo!==null &&
|
||||
booking.confirmationNo!=='null' && booking.confirmationNo!=='' && booking.approveStatus!='W'){
|
||||
return booking.confirmationNo;
|
||||
}
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
},
|
||||
getStatusText(){
|
||||
return function (booking) {
|
||||
console.log(booking);
|
||||
if(booking!==undefined && booking!==null){
|
||||
if(booking.status !==undefined && booking.status!==null) return booking.status.replace("_"," ");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.limo-info-card {
|
||||
position: relative;
|
||||
padding-right: 54px;
|
||||
}
|
||||
.limo-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.45fr) minmax(0, 0.9fr);
|
||||
column-gap: 18px;
|
||||
row-gap: 12px;
|
||||
}
|
||||
.limo-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.limo-info-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-right: 8px;
|
||||
flex: 0 0 18px;
|
||||
}
|
||||
.limo-edit-button {
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
right: 24px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.limo-edit-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.booking-popup-card {
|
||||
padding: 20px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.booking-popup-icon-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.booking-popup-title {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.booking-popup-title--success {
|
||||
line-height: 1.4;
|
||||
}
|
||||
.booking-popup-button {
|
||||
margin-top: 40px;
|
||||
}
|
||||
.booking-popup-button--primary {
|
||||
background-color: #C39A4B;
|
||||
}
|
||||
.booking-popup-button--success {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,761 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar
|
||||
:safeAreaInsetTop="true"
|
||||
:placeholder="true"
|
||||
:title="title"
|
||||
:fixed="true"
|
||||
:autoBack="true"
|
||||
leftIconColor="#ffffff"
|
||||
bgColor="#C39A4B"
|
||||
titleStyle="font-weight:bold;color:#ffffff;"
|
||||
>
|
||||
<view
|
||||
v-if="activeTabKey === 'approval' && canViewApproval && hasSelectedDate"
|
||||
class="hz-nav-filter-clear"
|
||||
slot="right"
|
||||
@click="clearDateFilter"
|
||||
>
|
||||
<u-icon
|
||||
size="28px"
|
||||
name="../../static/images/filter-clear.svg"
|
||||
></u-icon>
|
||||
</view>
|
||||
<view
|
||||
v-if="activeTabKey === 'notification' && canViewNotification"
|
||||
class="hz-nav-read-all"
|
||||
slot="right"
|
||||
@click="onReadAllClick"
|
||||
>
|
||||
<image src="/static/images/read_all.png" class="hz-nav-read-all-img"></image>
|
||||
</view>
|
||||
</u-navbar>
|
||||
|
||||
<u-tabs
|
||||
v-if="shouldShowTabs"
|
||||
:list="visibleTabList"
|
||||
lineColor="#C39A4B"
|
||||
lineWidth="36"
|
||||
inactiveStyle="color: #c0c0c0; font-weight: bold;"
|
||||
activeStyle="color: #C39A4B; font-weight: bold;"
|
||||
:scrollable="false"
|
||||
:current="tabIndex"
|
||||
@change="tabChange"
|
||||
>
|
||||
</u-tabs>
|
||||
|
||||
<!-- Limo Notification -->
|
||||
<view v-show="activeTabKey === 'notification' && canViewNotification">
|
||||
<view v-if="!showNotification">
|
||||
<view class="hz-flex-row approval-empty-img-row">
|
||||
<image src="/static/images/datanull.png" class="approval-empty-img"></image>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-font-bolder hz-font-md approval-empty-text-row">
|
||||
{{ dataNull }}
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="notice-card"
|
||||
v-for="(notice, index) in limoNoticeList"
|
||||
:key="notice.id != null ? notice.id : index"
|
||||
@click="onNoticeCardClick(notice)"
|
||||
:style="getNoticeCardStyle(notice)"
|
||||
>
|
||||
<image class="icon" :src="notice.icon" mode="aspectFill"></image>
|
||||
<view class="info">
|
||||
<view class="notice-type">{{ notice.type }}</view>
|
||||
<view class="notice-title">{{ notice.title }}</view>
|
||||
<view class="notice-desc">{{ notice.desc }}</view>
|
||||
<view class="notice-time">{{ notice.time }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Approval Routing -->
|
||||
<view v-show="activeTabKey === 'approval' && canViewApproval">
|
||||
<view class="hz-spacing hz-mr-t-20 hz-flex-row approval-search-row">
|
||||
<u-search
|
||||
:placeholder="searchHolder"
|
||||
v-model="searchInputStr"
|
||||
:showAction="false"
|
||||
bgColor="#ffffff"
|
||||
:label="searchLabel"
|
||||
borderColor="gray"
|
||||
class="approval-search-input"
|
||||
@search="searchApprovalByPlayerId"
|
||||
></u-search>
|
||||
<u-icon
|
||||
name="calendar"
|
||||
:size="45"
|
||||
:color="calendarIconColor"
|
||||
@click="showCalendar = true"
|
||||
></u-icon>
|
||||
</view>
|
||||
|
||||
<view v-if="!showApprovalList">
|
||||
<view class="hz-flex-row approval-empty-img-row">
|
||||
<image src="/static/images/datanull.png" class="approval-empty-img"></image>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-font-bolder hz-font-md approval-empty-text-row">
|
||||
{{ dataNull }}
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
<uni-card
|
||||
v-for="(approvalRecord, index) in approvalList"
|
||||
:key="index"
|
||||
@click="toDetail(approvalRecord.playerId)"
|
||||
>
|
||||
<view class="notification-content">
|
||||
<view class="icon-container">
|
||||
<image src="/static/images/task.png" class="task-icon"></image>
|
||||
</view>
|
||||
<view class="notification-info">
|
||||
<view class="notification-title">
|
||||
{{ $t("notification.pendingApprovalRequest") }}
|
||||
</view>
|
||||
<view class="notification-date">
|
||||
{{ approvalRecord.createdAt }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="notification-time">
|
||||
{{ getTimeAgo(approvalRecord.createdAt) }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="notification-detail">
|
||||
{{ approvalRecord.memberLastName }}, {{ approvalRecord.playerId }} ({{ approvalRecord.tier }}), {{ approvalRecord.propertyName }}, {{ approvalRecord.roomTypeCode }}, {{ approvalRecord.checkinDate }} to {{ approvalRecord.checkoutDate }}, {{ approvalRecord.booker }}
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<u-empty
|
||||
v-if="!hasAnyViewPermission"
|
||||
mode="list"
|
||||
:text="$t('notification.noPermission')"
|
||||
></u-empty>
|
||||
|
||||
<u-calendar
|
||||
v-if="activeTabKey === 'approval' && canViewApproval"
|
||||
:show="showCalendar"
|
||||
@close="showCalendar = false"
|
||||
:confirmText="confirmText"
|
||||
:confirmDisabledText="confirmText"
|
||||
color="#C39A4B"
|
||||
:allowSameDay="true"
|
||||
:startText="startText"
|
||||
:endText="endText"
|
||||
mode="range"
|
||||
:showMark="false"
|
||||
title=""
|
||||
@confirm="handleFilterDate"
|
||||
:defaultDate="selectedDate"
|
||||
>
|
||||
</u-calendar>
|
||||
|
||||
<u-modal
|
||||
:content="msgStr"
|
||||
:show="showMsg"
|
||||
:confirmText="yesText"
|
||||
:showCancelButton="false"
|
||||
closeOnClickOverlay
|
||||
@confirm="showMsg = false"
|
||||
confirmColor="#C39A4B"
|
||||
@close="showMsg = false"
|
||||
></u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getNotificationByUserId, changeNotification, countNotification, readAllNotification } from '../../api/notificationApi.js'
|
||||
import { getApprovalList } from '../../api/approvalApi.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: this.$t('notification.title'),
|
||||
userData: null,
|
||||
tabList: [
|
||||
{ name: this.$t('notification.title'), key: 'notification' },
|
||||
{ name: this.$t('approvalRouting.title'), key: 'approval' }
|
||||
],
|
||||
tabIndex: 0,
|
||||
activeTabKey: 'notification',
|
||||
pendingTabKey: '',
|
||||
limoNoticeList: [],
|
||||
limoEmptyText: this.$t('notification.noData'),
|
||||
searchInputStr: '',
|
||||
approvalList: [],
|
||||
showApprovalList: true,
|
||||
dataNull: this.$t('notification.noData'),
|
||||
searchHolder: this.$t('approval.searchStr'),
|
||||
calendarIconColor: '#000000',
|
||||
showCalendar: false,
|
||||
confirmText: this.$t('common.confirm').toUpperCase(),
|
||||
startText: this.$t('common.start'),
|
||||
endText: this.$t('common.end'),
|
||||
selectedDate: [],
|
||||
searchLabel: this.$t('common.playerId'),
|
||||
msgStr: '',
|
||||
showMsg: false,
|
||||
yesText: this.$t('common.yes'),
|
||||
notificationCount: 0,
|
||||
approvalRoutingCount: 0,
|
||||
showNotification: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
effectiveUserData() {
|
||||
return this.getEffectiveUserData(this.userData);
|
||||
},
|
||||
canViewNotification() {
|
||||
return !!(this.effectiveUserData && this.effectiveUserData.canViewNotification === true);
|
||||
},
|
||||
canViewApproval() {
|
||||
return !!(this.effectiveUserData && this.effectiveUserData.canViewApproval === true);
|
||||
},
|
||||
visibleTabList() {
|
||||
return this.tabList.filter((tab) => {
|
||||
if (tab.key === 'notification') {
|
||||
return this.canViewNotification;
|
||||
}
|
||||
if (tab.key === 'approval') {
|
||||
return this.canViewApproval;
|
||||
}
|
||||
return false;
|
||||
}).map((tab) => ({
|
||||
...tab,
|
||||
badge: this.getTabBadge(tab.key)
|
||||
}));
|
||||
},
|
||||
shouldShowTabs() {
|
||||
return this.visibleTabList.length > 1;
|
||||
},
|
||||
pageTitle() {
|
||||
if (this.visibleTabList.length === 1) {
|
||||
return this.visibleTabList[0].name;
|
||||
}
|
||||
return this.$t('notification.title');
|
||||
},
|
||||
hasAnyViewPermission() {
|
||||
return this.visibleTabList.length > 0;
|
||||
},
|
||||
hasSelectedDate() {
|
||||
return Array.isArray(this.selectedDate) && this.selectedDate.length > 0;
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options && options.tab != null && options.tab !== '') {
|
||||
const tab = Number(options.tab);
|
||||
if (tab === 1) {
|
||||
this.pendingTabKey = 'approval';
|
||||
this.activeTabKey = 'approval';
|
||||
}
|
||||
}
|
||||
this.applyNotificationCountsFromOptions(options || {});
|
||||
},
|
||||
onShow() {
|
||||
this.userData = uni.getStorageSync('userData');
|
||||
this.syncVisibleTabState(this.pendingTabKey || this.activeTabKey);
|
||||
this.syncPageTitle();
|
||||
this.pendingTabKey = '';
|
||||
this.fetchNotificationCounts();
|
||||
this.fetchActiveTabData();
|
||||
},
|
||||
methods: {
|
||||
getEffectiveUserData(userData) {
|
||||
if (userData && userData.data && typeof userData.data === 'object') {
|
||||
return userData.data;
|
||||
}
|
||||
return userData || {};
|
||||
},
|
||||
applyNotificationCountsFromOptions(options) {
|
||||
this.notificationCount = this.parseCountValue(options.notificationCount);
|
||||
this.approvalRoutingCount = this.parseCountValue(options.approvalRoutingCount);
|
||||
},
|
||||
parseCountValue(value) {
|
||||
const count = Number(value);
|
||||
return Number.isFinite(count) && count > 0 ? count : 0;
|
||||
},
|
||||
getTabBadge(tabKey) {
|
||||
const count = tabKey === 'approval'
|
||||
? this.approvalRoutingCount
|
||||
: this.notificationCount;
|
||||
if (count <= 0) {
|
||||
return {
|
||||
show: false,
|
||||
value: 0
|
||||
};
|
||||
}
|
||||
return {
|
||||
show: true,
|
||||
value: count,
|
||||
max: 99,
|
||||
bgColor: '#fa3534',
|
||||
color: '#ffffff',
|
||||
customStyle: {
|
||||
transform: 'translateY(-2px)',
|
||||
fontSize: '10px',
|
||||
lineHeight: '10px',
|
||||
padding: '1px 4px'
|
||||
}
|
||||
};
|
||||
},
|
||||
parseNotificationCounts(res) {
|
||||
const data = res && res.data && typeof res.data === 'object' ? res.data : (res || {});
|
||||
return {
|
||||
notificationCount: this.parseCountValue(data.notificationCount ?? data.NotificationCount),
|
||||
approvalRoutingCount: this.parseCountValue(data.approvalRoutingCount ?? data.ApprovalRoutingCount)
|
||||
};
|
||||
},
|
||||
async fetchNotificationCounts() {
|
||||
const userId = this.getUserIdFromUserData(this.userData);
|
||||
if (!userId || !this.hasAnyViewPermission) {
|
||||
this.notificationCount = 0;
|
||||
this.approvalRoutingCount = 0;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await countNotification({ userId });
|
||||
const counts = this.parseNotificationCounts(res);
|
||||
if (this.canViewNotification) {
|
||||
this.notificationCount = counts.notificationCount;
|
||||
}
|
||||
if (this.canViewApproval) {
|
||||
this.approvalRoutingCount = counts.approvalRoutingCount;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Notification] countNotification failed', error);
|
||||
}
|
||||
},
|
||||
syncVisibleTabState(preferredKey) {
|
||||
const tabs = this.visibleTabList;
|
||||
if (!tabs.length) {
|
||||
this.tabIndex = 0;
|
||||
this.activeTabKey = '';
|
||||
this.showCalendar = false;
|
||||
this.syncPageTitle();
|
||||
return;
|
||||
}
|
||||
const nextIndex = tabs.findIndex((tab) => tab.key === preferredKey);
|
||||
this.tabIndex = nextIndex >= 0 ? nextIndex : 0;
|
||||
this.activeTabKey = tabs[this.tabIndex].key;
|
||||
if (this.activeTabKey !== 'approval') {
|
||||
this.showCalendar = false;
|
||||
}
|
||||
this.syncPageTitle();
|
||||
},
|
||||
syncPageTitle() {
|
||||
this.title = this.pageTitle;
|
||||
},
|
||||
fetchActiveTabData() {
|
||||
if (this.activeTabKey === 'notification' && this.canViewNotification) {
|
||||
this.fetchNotificationList();
|
||||
return;
|
||||
}
|
||||
if (this.activeTabKey === 'approval' && this.canViewApproval) {
|
||||
this.getApprovalList();
|
||||
}
|
||||
},
|
||||
getUserIdFromUserData(userData) {
|
||||
const realUserData = this.getEffectiveUserData(userData);
|
||||
if (userData == null || userData === '') {
|
||||
return '';
|
||||
}
|
||||
const userId = realUserData.userId != null && realUserData.userId !== ''
|
||||
? realUserData.userId
|
||||
: realUserData.UserId;
|
||||
return userId != null && userId !== '' ? userId : '';
|
||||
},
|
||||
unwrapNotificationList(response) {
|
||||
if (Array.isArray(response)) {
|
||||
return response;
|
||||
}
|
||||
if (response && Array.isArray(response.notifications)) {
|
||||
return response.notifications;
|
||||
}
|
||||
if (response && Array.isArray(response.data)) {
|
||||
return response.data;
|
||||
}
|
||||
if (response && Array.isArray(response.records)) {
|
||||
return response.records;
|
||||
}
|
||||
if (response && Array.isArray(response.Records)) {
|
||||
return response.Records;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
formatNotificationTime(value) {
|
||||
if (value == null || value === '') {
|
||||
return '';
|
||||
}
|
||||
const timestamp = Number(value);
|
||||
if (!Number.isFinite(timestamp)) {
|
||||
return String(value);
|
||||
}
|
||||
const date = new Date(timestamp);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return String(value);
|
||||
}
|
||||
const pad = (num) => String(num).padStart(2, '0');
|
||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
||||
},
|
||||
getNoticeCardStyle(notice) {
|
||||
if (notice && Number(notice.status) === 0) {
|
||||
return { backgroundColor: '#F7F2E8' };
|
||||
}
|
||||
return {};
|
||||
},
|
||||
async onReadAllClick() {
|
||||
try {
|
||||
const res = await readAllNotification({});
|
||||
if (res.success == true) {
|
||||
this.fetchNotificationCounts();
|
||||
this.fetchNotificationList();
|
||||
} else {
|
||||
this.msgStr = res.message;
|
||||
this.showMsg = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Notification] readAllNotification failed', error);
|
||||
}
|
||||
},
|
||||
mapNotificationItem(item, index) {
|
||||
const content = item.content || '';
|
||||
return {
|
||||
id: item.id != null ? item.id : index,
|
||||
type: 'Limo',
|
||||
title: item.title || '',
|
||||
desc: content,
|
||||
confNo: item.confirmationNo,
|
||||
time: this.formatNotificationTime(item.createdAt || item.updatedAt),
|
||||
status: item.status != null ? Number(item.status) : 1,
|
||||
icon: '/static/images/limo_notification.png'
|
||||
};
|
||||
},
|
||||
updateNotificationLists(list) {
|
||||
this.limoNoticeList = list
|
||||
.map((item, index) => this.mapNotificationItem(item, index))
|
||||
.sort((a, b) => {
|
||||
const statusA = a.status != null ? Number(a.status) : 1;
|
||||
const statusB = b.status != null ? Number(b.status) : 1;
|
||||
return statusA - statusB;
|
||||
});
|
||||
},
|
||||
async fetchNotificationList() {
|
||||
const userId = this.getUserIdFromUserData(this.userData);
|
||||
if (!userId) {
|
||||
console.warn('[Notification] userId not found in userData cache');
|
||||
return;
|
||||
}
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading')
|
||||
});
|
||||
try {
|
||||
const res = await getNotificationByUserId();
|
||||
if(res.success == true){
|
||||
this.showNotification = true;
|
||||
const list = this.unwrapNotificationList(res);
|
||||
this.updateNotificationLists(list);
|
||||
}else {
|
||||
this.msgStr = res.message;
|
||||
this.showNotification = false;
|
||||
if (res.code === 'NO_PERMISSION') {
|
||||
this.dataNull = this.$t('notification.noPermission');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Notification] getNotificationByUserId failed', error);
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
tabChange(e) {
|
||||
const index = e && e.index != null ? e.index : e;
|
||||
const selectedTab = this.visibleTabList[index];
|
||||
if (!selectedTab) {
|
||||
return;
|
||||
}
|
||||
this.tabIndex = index;
|
||||
this.activeTabKey = selectedTab.key;
|
||||
this.fetchActiveTabData();
|
||||
},
|
||||
extractConfNoFromContent(content) {
|
||||
if (content == null || content === '') {
|
||||
return '';
|
||||
}
|
||||
const match = String(content).match(/confNo#([A-Za-z0-9]+)/i);
|
||||
return match ? match[1] : '';
|
||||
},
|
||||
async onNoticeCardClick(notice) {
|
||||
if (!notice || notice.id == null || notice.id === '') {
|
||||
uni.showToast({
|
||||
title: 'Notification id not found',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!notice.confNo) {
|
||||
uni.showToast({
|
||||
title: 'ConfNo not found',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await changeNotification({ id: notice.id });
|
||||
this.fetchNotificationCounts();
|
||||
} catch (error) {
|
||||
console.error('[Notification] changeNotification failed', error);
|
||||
}
|
||||
if(notice.confNo!=null && notice.confNo!='' && notice.confNo!=undefined){
|
||||
this.navTo(
|
||||
'/limo/bookingDetail/bookingDetail?conf=' +
|
||||
notice.confNo +
|
||||
'&from=notification',
|
||||
0,
|
||||
false
|
||||
);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
handleFilterDate(e) {
|
||||
this.selectedDate = e;
|
||||
this.showCalendar = false;
|
||||
|
||||
if (Array.isArray(this.selectedDate) && this.selectedDate.length > 0) {
|
||||
this.calendarIconColor = '#C39A4B';
|
||||
} else {
|
||||
this.calendarIconColor = '#000000';
|
||||
}
|
||||
|
||||
if (this.canViewApproval) {
|
||||
this.getApprovalList();
|
||||
}
|
||||
},
|
||||
clearDateFilter() {
|
||||
this.selectedDate = [];
|
||||
this.calendarIconColor = '#000000';
|
||||
if (this.canViewApproval) {
|
||||
this.getApprovalList();
|
||||
}
|
||||
},
|
||||
toDetail(playerId) {
|
||||
this.navTo('/pages/playerDetail/playerDetail?playerId=' + playerId, 0, false);
|
||||
},
|
||||
getTimeAgo(createdAt) {
|
||||
if (!createdAt) return '';
|
||||
|
||||
const now = new Date();
|
||||
const created = new Date(createdAt);
|
||||
const diffMs = now - created;
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const diffHours = Math.floor(diffMins / 60);
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
|
||||
if (diffMins < 1) return 'just now';
|
||||
if (diffMins < 60) return diffMins + 'm';
|
||||
if (diffHours < 24) return diffHours + 'h';
|
||||
return diffDays + 'd';
|
||||
},
|
||||
async getApprovalList() {
|
||||
if (!this.getUserIdFromUserData(this.userData)) {
|
||||
this.userData = uni.getStorageSync('userData');
|
||||
}
|
||||
const userId = this.getUserIdFromUserData(this.userData);
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
uni.showLoading({
|
||||
title: this.$t('common.loading')
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
userId,
|
||||
playerId: this.searchInputStr,
|
||||
rangeDate: this.selectedDate
|
||||
};
|
||||
const res = await getApprovalList(params);
|
||||
if (res.success == true) {
|
||||
if (res.data !== null && res.data.length > 0) {
|
||||
this.approvalList = res.data;
|
||||
const playerIds = this.approvalList.map((item) => item.playerId);
|
||||
const uniquePlayerIds = [...new Set(playerIds)];
|
||||
const playerList = uniquePlayerIds.map((playerId) => ({ playerId }));
|
||||
uni.setStorageSync('approvalPlayerList', playerList);
|
||||
this.showApprovalList = true;
|
||||
} else {
|
||||
this.approvalList = [];
|
||||
this.showApprovalList = false;
|
||||
this.dataNull = this.$t('notification.noData');
|
||||
}
|
||||
} else {
|
||||
this.msgStr = res.message;
|
||||
this.showApprovalList = false;
|
||||
if (res.errorCode === 'NO_PERMISSION') {
|
||||
this.dataNull = this.$t('notification.noPermission');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
uni.$u.toast(e.errMsg, 5000);
|
||||
const request = e.config != undefined ? JSON.stringify(e.config) : '';
|
||||
const response = e.data != undefined ? JSON.stringify(e.data) : '';
|
||||
await this.writeLog(
|
||||
userId,
|
||||
'find_player',
|
||||
'',
|
||||
'[APP][notification.vue][getApprovalList][Catch Exception]' + e.errMsg,
|
||||
request,
|
||||
response,
|
||||
1,
|
||||
false
|
||||
);
|
||||
} finally {
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
searchApprovalByPlayerId() {
|
||||
if (this.canViewApproval) {
|
||||
this.getApprovalList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hz-nav-filter-clear {
|
||||
margin-top: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.hz-nav-read-all {
|
||||
margin-top: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.hz-nav-read-all-img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.approval-search-row {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.approval-search-input {
|
||||
flex: 1;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.approval-empty-img-row {
|
||||
justify-content: center;
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.approval-empty-img {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.approval-empty-text-row {
|
||||
justify-content: center;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
display: flex;
|
||||
padding: 24rpx;
|
||||
margin: 30rpx;
|
||||
border: 1rpx solid #EBEEF5;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: rgba(0, 0, 0, 0.08) 0rpx 0rpx 6rpx 2rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.notice-type {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.notice-title {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.notice-desc {
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.notice-time {
|
||||
font-size: 20rpx;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.notification-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.notification-date {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.notification-time {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #C39A4B;
|
||||
background-color: #FFF8E7;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.notification-detail {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #000000;
|
||||
margin-top: 6px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user