merge limo to daylight
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import config from './common/config.js'
|
||||
import {writeDebugLog,writePublicDebugLog,getSettingByKey,getSettings,verifyToken,logout} from './api/commonApi.js'
|
||||
import {writeDebugLog,getSettings,verifyToken,logout,writePublicDebugLog} from './api/commonApi.js'
|
||||
import { getCfgSettingByKey } from './api/configApi.js'
|
||||
import store from './store/index.js'
|
||||
import FixedCoordinateConverter from './common/fixedCoordinateConverter.js'
|
||||
@@ -9,7 +9,7 @@
|
||||
import {refreshToken} from './api/commonApi.js'
|
||||
import dayjs from './uni_modules/uview-ui/libs/util/dayjs.js';
|
||||
import { decryptCfgSettingValue } from './common/cfgSettingCrypto.js';
|
||||
import {saveDeviceToken} from './api/notification.js';
|
||||
import { saveDeviceToken, saveNotification } from './api/notificationApi.js';
|
||||
// #ifdef APP-PLUS
|
||||
var networkModule = uni.requireNativePlugin("NetworkUtils-NetworkUtilsModule")
|
||||
// #endif
|
||||
@@ -17,7 +17,9 @@
|
||||
data() {
|
||||
return {
|
||||
timer: null, // 定时器引用
|
||||
backgroundTaskId: 0 // iOS 后台任务ID
|
||||
backgroundTaskId: 0, // iOS 后台任务ID
|
||||
lastPushNotificationTitle: '',
|
||||
lastPushNotificationContent: ''
|
||||
}
|
||||
},
|
||||
onLaunch: function() {
|
||||
@@ -28,22 +30,18 @@
|
||||
type: 'wgs84',
|
||||
success: (res) => {}
|
||||
});
|
||||
/*plus.globalEvent.addEventListener('newintent', (e)=>{
|
||||
var args= plus.runtime.arguments;
|
||||
console.log(args)
|
||||
uni.showToast({
|
||||
title: 'APP LAUNCH-newintent'
|
||||
});
|
||||
if(args){
|
||||
var code = this.getSchemeParam('code',args)
|
||||
uni.showToast({
|
||||
title: code
|
||||
});
|
||||
uni.redirectTo({
|
||||
url:'/pages/login/login?code='+encodeURIComponent(code)
|
||||
})
|
||||
}
|
||||
});*/
|
||||
// 延迟触发推送注册:避免 plus/原生桥尚未就绪导致 refresh 未真正调到原生(Xcode 看不到 refreshDeviceTokenAsync ENTER)
|
||||
setTimeout(() => {
|
||||
this.refreshPushDeviceTokenAndSync({ requestAuthorization: true }).catch((err) => {
|
||||
console.warn('[APNs] refreshDeviceTokenAsync failed', err)
|
||||
})
|
||||
}, 1200)
|
||||
|
||||
this.setupPushNotificationListener();
|
||||
setTimeout(() => {
|
||||
this.syncPendingPushNotificationsFromNative();
|
||||
}, 2000);
|
||||
|
||||
// #endif
|
||||
},
|
||||
onShow: function() {
|
||||
@@ -80,12 +78,248 @@
|
||||
// #endif
|
||||
},
|
||||
beforeDestroy() {
|
||||
// 组件销毁时清理资源
|
||||
// #ifdef APP-PLUS
|
||||
this.stopTimer();
|
||||
this.stopTimer();
|
||||
// #endif
|
||||
},
|
||||
methods:{
|
||||
methods: {
|
||||
parsePushMessageReceivedPayload(rawPayload) {
|
||||
const root =
|
||||
rawPayload &&
|
||||
rawPayload.detail != null &&
|
||||
typeof rawPayload.detail === 'object'
|
||||
? rawPayload.detail
|
||||
: rawPayload;
|
||||
if (!root || typeof root !== 'object') {
|
||||
return { notificationTitle: '', notificationContent: '' };
|
||||
}
|
||||
let merged = Object.assign({}, root);
|
||||
let extra = merged.data ?? merged.payload ?? merged.message ?? merged.content;
|
||||
if (typeof extra === 'string') {
|
||||
const text = extra.trim();
|
||||
if (text.startsWith('{') || text.startsWith('[')) {
|
||||
try {
|
||||
extra = JSON.parse(text);
|
||||
} catch (parseError) {
|
||||
extra = null;
|
||||
}
|
||||
} else if (text) {
|
||||
merged._dataStringFallback = text;
|
||||
}
|
||||
}
|
||||
if (extra != null && typeof extra === 'object' && !Array.isArray(extra)) {
|
||||
merged = Object.assign({}, merged, extra);
|
||||
}
|
||||
const aps = merged.aps;
|
||||
let alertBody = '';
|
||||
let alertTitle = '';
|
||||
if (aps && typeof aps.alert === 'object' && aps.alert !== null) {
|
||||
alertTitle = String(aps.alert.title || '').trim();
|
||||
alertBody = String(
|
||||
aps.alert.body ?? aps.alert.subtitle ?? ''
|
||||
).trim();
|
||||
} else if (aps && typeof aps.alert === 'string') {
|
||||
alertBody = String(aps.alert).trim();
|
||||
}
|
||||
const notificationTitle =
|
||||
String(
|
||||
alertTitle ||
|
||||
merged.title ||
|
||||
merged.Title ||
|
||||
merged.notificationTitle ||
|
||||
merged.notification_title ||
|
||||
''
|
||||
).trim();
|
||||
const notificationContent = String(
|
||||
alertBody ||
|
||||
merged.body ||
|
||||
merged.content ||
|
||||
merged.Content ||
|
||||
merged.message ||
|
||||
merged.Message ||
|
||||
merged.text ||
|
||||
merged.description ||
|
||||
merged._dataStringFallback ||
|
||||
''
|
||||
).trim();
|
||||
return { notificationTitle, notificationContent };
|
||||
},
|
||||
getCachedUserId() {
|
||||
const userData = uni.getStorageSync('userData');
|
||||
if (
|
||||
userData != null &&
|
||||
userData !== '' &&
|
||||
userData != undefined &&
|
||||
userData.userId != null &&
|
||||
userData.userId !== ''
|
||||
) {
|
||||
return userData.userId;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
isUserLoggedIn() {
|
||||
const user = uni.getStorageSync('userData');
|
||||
const token = uni.getStorageSync('token');
|
||||
const clientId = uni.getStorageSync('clientId');
|
||||
const timeOut = uni.getStorageSync('timeOut');
|
||||
const now = Math.floor(new Date().getTime() / 1000);
|
||||
let loginTag = false;
|
||||
if (user) {
|
||||
loginTag = user.loginTag === true;
|
||||
}
|
||||
if (
|
||||
token == undefined ||
|
||||
token == null ||
|
||||
token === '' ||
|
||||
clientId == undefined ||
|
||||
clientId == null ||
|
||||
clientId === ''
|
||||
) {
|
||||
loginTag = false;
|
||||
}
|
||||
if (timeOut != null && timeOut !== '' && now >= timeOut) {
|
||||
loginTag = false;
|
||||
}
|
||||
return loginTag === true;
|
||||
},
|
||||
getPushNotificationPageUrl() {
|
||||
return '/limo/notification/notification';
|
||||
},
|
||||
getPushConfirmNo(payload = {}) {
|
||||
const confirmNo = payload.confirmNo || payload.raw?.ConfirmNo || payload.raw?.confirmNo || payload.raw?.confNo;
|
||||
return confirmNo ? String(confirmNo) : '';
|
||||
},
|
||||
getPushTargetUrl(payload = {}) {
|
||||
const confirmNo = this.getPushConfirmNo(payload);
|
||||
if (confirmNo) {
|
||||
return `/limo/bookingDetail/bookingDetail?confNo=${encodeURIComponent(confirmNo)}&from=push`;
|
||||
}
|
||||
return this.getPushNotificationPageUrl();
|
||||
},
|
||||
setPendingPushNavigation(url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
uni.setStorageSync('pendingPushNavigation', url);
|
||||
console.log('[Push] pending navigation saved:', url);
|
||||
},
|
||||
tryConsumePendingPushNavigation() {
|
||||
const pendingUrl = uni.getStorageSync('pendingPushNavigation');
|
||||
if (!pendingUrl) {
|
||||
return false;
|
||||
}
|
||||
if (!this.isUserLoggedIn()) {
|
||||
return false;
|
||||
}
|
||||
uni.removeStorageSync('pendingPushNavigation');
|
||||
console.log('[Push] consume pending navigation:', pendingUrl);
|
||||
this.navTo(pendingUrl, 0, false);
|
||||
return true;
|
||||
},
|
||||
shouldOpenNotificationPageFromPush(payload = {}, meta = {}) {
|
||||
return meta.userTapped === true || payload.userTapped === true;
|
||||
},
|
||||
navigateToNotificationPageFromPush(payload = {}) {
|
||||
const targetUrl = this.getPushTargetUrl(payload);
|
||||
console.log('[Push] navigateToNotificationPageFromPush targetUrl=', targetUrl, 'confirmNo=', this.getPushConfirmNo(payload));
|
||||
if (!this.isUserLoggedIn()) {
|
||||
this.setPendingPushNavigation(targetUrl);
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.navTo(targetUrl, 0, false);
|
||||
},
|
||||
queuePushForSaveLater(title, content) {
|
||||
const queue = uni.getStorageSync('pendingPushSaveQueue') || []
|
||||
queue.push({ title, content, at: Date.now() })
|
||||
uni.setStorageSync('pendingPushSaveQueue', queue)
|
||||
console.warn('[Push] userId 未就绪,已暂存待 saveNotification,条数=', queue.length)
|
||||
},
|
||||
async flushPendingPushSaveQueue() {
|
||||
const userId = this.getCachedUserId()
|
||||
if (!userId) {
|
||||
return
|
||||
}
|
||||
const queue = uni.getStorageSync('pendingPushSaveQueue') || []
|
||||
if (!queue.length) {
|
||||
return
|
||||
}
|
||||
uni.removeStorageSync('pendingPushSaveQueue')
|
||||
console.log('[Push] flushPendingPushSaveQueue count=', queue.length)
|
||||
for (const item of queue) {
|
||||
try {
|
||||
await saveNotification({
|
||||
title: item.title,
|
||||
content: item.content,
|
||||
userId
|
||||
})
|
||||
console.log('[Push] saveNotification success (flushed)', item.title)
|
||||
} catch (saveError) {
|
||||
console.error('[Push] saveNotification failed (flushed)', saveError)
|
||||
}
|
||||
}
|
||||
},
|
||||
async persistReceivedPushNotification(notificationTitle, notificationContent) {
|
||||
const userId = this.getCachedUserId();
|
||||
if (!userId) {
|
||||
this.queuePushForSaveLater(notificationTitle, notificationContent)
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await saveNotification({
|
||||
title: notificationTitle,
|
||||
content: notificationContent,
|
||||
userId
|
||||
});
|
||||
console.log('[Push] saveNotification success', {
|
||||
title: notificationTitle,
|
||||
content: notificationContent,
|
||||
userId
|
||||
});
|
||||
} catch (saveError) {
|
||||
console.error('[Push] saveNotification failed', saveError);
|
||||
}
|
||||
},
|
||||
setupGlobalEventListeners() {
|
||||
if (this._globalPushHookRegistered) {
|
||||
return;
|
||||
}
|
||||
this._globalPushHookRegistered = true;
|
||||
uni.$on('onPushMessageReceived', (rawPayload) => {
|
||||
try {
|
||||
const { notificationTitle, notificationContent } =
|
||||
this.parsePushMessageReceivedPayload(rawPayload);
|
||||
this.lastPushNotificationTitle = notificationTitle;
|
||||
this.lastPushNotificationContent = notificationContent;
|
||||
console.log(
|
||||
'[Push] onPushMessageReceived',
|
||||
notificationTitle || '(no title)',
|
||||
notificationContent || '(no content)',
|
||||
rawPayload
|
||||
);
|
||||
this.persistReceivedPushNotification(
|
||||
notificationTitle,
|
||||
notificationContent
|
||||
);
|
||||
const toastText =
|
||||
notificationTitle ||
|
||||
notificationContent ||
|
||||
'Received push message';
|
||||
uni.showToast({
|
||||
title:
|
||||
toastText.length > 36
|
||||
? `${toastText.slice(0, 33)}…`
|
||||
: toastText,
|
||||
icon: 'none',
|
||||
duration: 2800
|
||||
});
|
||||
} catch (handlerError) {
|
||||
console.error('[Push] handler error', handlerError, rawPayload);
|
||||
}
|
||||
});
|
||||
},
|
||||
startTimer() {
|
||||
// 先清除可能存在的旧定时器
|
||||
this.stopTimer();
|
||||
@@ -135,6 +369,10 @@
|
||||
}
|
||||
this.macauString = res.data;
|
||||
uni.setStorageSync("macauString",this.macauString.keyValues);
|
||||
// uni.showToast({
|
||||
// title:'Macau String = '+this.macauString.keyValues,
|
||||
// icon: "none"
|
||||
// })
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}finally{
|
||||
@@ -168,6 +406,7 @@
|
||||
plus.screen.lockOrientation("portrait");
|
||||
// #endif
|
||||
await this.initCfg(); // 获取配置参数
|
||||
this.setupGlobalEventListeners();
|
||||
},
|
||||
// 初始化方法
|
||||
async initCfg(){
|
||||
@@ -371,10 +610,6 @@
|
||||
},
|
||||
//根据Permission显示Tabbar
|
||||
showTabbarByPermission(userData){
|
||||
uni.setTabBarItem({
|
||||
index: 3,
|
||||
visible: !!userData && userData.canViewCalendar === true
|
||||
});
|
||||
if(userData!==null && userData!==undefined){
|
||||
console.log('Setting Tabbar');
|
||||
if(userData.canViewDashboard){
|
||||
@@ -395,6 +630,12 @@
|
||||
visible:true
|
||||
});
|
||||
}
|
||||
if(userData.canViewCalendar){
|
||||
uni.setTabBarItem({
|
||||
index:3,
|
||||
visible:true
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
// 返回
|
||||
@@ -421,6 +662,110 @@
|
||||
});
|
||||
|
||||
},
|
||||
/** 从原生读取当前缓存的 APNs DeviceToken,并写入本地 Storage(供业务上报) */
|
||||
syncPushDeviceTokenFromNative() {
|
||||
getDeviceToken({})
|
||||
.then(async (ret) => {
|
||||
console.log('[APNs] getDeviceToken', ret.status, ret.updatedAt);
|
||||
const deviceToken = ret.deviceToken ? String(ret.deviceToken).trim() : '';
|
||||
let useLanguage = 0;
|
||||
//获取AppSetting,后端可以判断发中文还是发英文 英文:0 中文:1 默认为0
|
||||
if(uni.getLocale()!==null && uni.getLocale()!==undefined){
|
||||
useLanguage = uni.getLocale()=='en'? 0 : 1;
|
||||
}
|
||||
if (deviceToken) {
|
||||
const userId = this.getCachedUserId();
|
||||
console.log('[APNs] saveDeviceToken params', {
|
||||
userId,
|
||||
deviceToken,
|
||||
rawUserData: uni.getStorageSync('userData'),
|
||||
rawRet: ret,
|
||||
useLanguage
|
||||
});
|
||||
this.writeLog(
|
||||
userId,
|
||||
'syncPushDeviceTokenFromNative',
|
||||
'',
|
||||
'[APP][App.vue][getDevice Token][Success]' + deviceToken,
|
||||
'',
|
||||
'',
|
||||
1,
|
||||
false
|
||||
);
|
||||
uni.setStorageSync('apnsDeviceToken', deviceToken);
|
||||
uni.setStorageSync('apnsDeviceTokenUpdatedAt', ret.updatedAt || 0);
|
||||
try {
|
||||
const res = await saveDeviceToken({ userId, deviceToken, useLanguage});
|
||||
console.log('[APNs] saveDeviceToken success', res);
|
||||
} catch (saveErr) {
|
||||
console.error('[APNs] saveDeviceToken failed', saveErr);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.warn('[APNs] getDeviceToken fail', e);
|
||||
uni.showToast({
|
||||
title: 'error = ' + e,
|
||||
icon: 'none'
|
||||
});
|
||||
const userId = this.getCachedUserId();
|
||||
this.writeLog(
|
||||
userId,
|
||||
'syncPushDeviceTokenFromNative',
|
||||
'',
|
||||
'[APP][App.vue][getDevice Token][Fail] Error Message :' + e,
|
||||
'',
|
||||
'',
|
||||
1,
|
||||
false
|
||||
);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 触发 refreshDeviceTokenAsync(重新向 APNs 注册),随后轮询 getDeviceToken。
|
||||
* @param {{ requestAuthorization?: boolean }} opts 默认可不传;已授权场景可传 { requestAuthorization: false }
|
||||
*/
|
||||
refreshPushDeviceTokenNative(opts) {
|
||||
return refreshDeviceTokenAsync(opts || { requestAuthorization: true })
|
||||
},
|
||||
/** 刷新并尽量拿到新 token(适合服务端返回推送失效时调用) */
|
||||
refreshPushDeviceTokenAndSync(opts) {
|
||||
return refreshDeviceTokenAndFetch(opts || { requestAuthorization: true }).then((ret) => {
|
||||
if (ret.deviceToken) {
|
||||
uni.setStorageSync('apnsDeviceToken', ret.deviceToken)
|
||||
uni.setStorageSync('apnsDeviceTokenUpdatedAt', ret.updatedAt || 0)
|
||||
}
|
||||
return ret
|
||||
})
|
||||
},
|
||||
setupPushNotificationListener() {
|
||||
listenPushNotification((payload, meta) => {
|
||||
this.handlePushNotificationMessage(payload, meta)
|
||||
})
|
||||
},
|
||||
async handlePushNotificationMessage(payload = {}, meta = {}) {
|
||||
const { title, content } = payload
|
||||
this.lastPushNotificationTitle = title
|
||||
this.lastPushNotificationContent = content
|
||||
|
||||
|
||||
await this.persistReceivedPushNotification(title, content)
|
||||
|
||||
console.log('[Push] handlePushNotificationMessage userTapped=', payload.userTapped, meta?.userTapped, 'confirmNo=', this.getPushConfirmNo(payload))
|
||||
if (this.shouldOpenNotificationPageFromPush(payload, meta)) {
|
||||
this.navigateToNotificationPageFromPush(payload)
|
||||
}
|
||||
},
|
||||
async syncPendingPushNotificationsFromNative() {
|
||||
console.log('[Push] syncPendingPushNotificationsFromNative')
|
||||
await syncPendingPushNotifications((payload, meta) => {
|
||||
this.handlePushNotificationMessage(payload, {
|
||||
...meta,
|
||||
showToast: meta?.fromPending ? false : meta?.showToast
|
||||
})
|
||||
}, { showToast: false })
|
||||
await this.flushPendingPushSaveQueue()
|
||||
},
|
||||
checkLocationAndVPN(type){
|
||||
let objVPNData = this.checkVPNOpen();
|
||||
let isOpenVPN = false;
|
||||
@@ -472,10 +817,9 @@
|
||||
icon: "none"
|
||||
})*/
|
||||
this.writeLog(userId,"getLocationVPN","","[APP][App.vue][checkLocationAndVPN][Success]"+result.isInMacau+ ", city:"+result.city+ ", address:"+result.fullAddress+ ", IP address:"+ipAddress,"","",1,false);
|
||||
/*uni.showToast({
|
||||
title:'是否在澳门:'+isInMacau+',是否使用VPN:'+isOpenVPN,
|
||||
icon: "none"
|
||||
})*/
|
||||
|
||||
|
||||
|
||||
if(!isInMacau){
|
||||
let macauStringList = uni.getStorageSync("macauString").split(";");
|
||||
for(let i=0;i<macauStringList.length;i++){
|
||||
@@ -488,8 +832,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
//isInMacau = true;
|
||||
|
||||
//模擬數據 模拟数据
|
||||
// isInMacau = true;
|
||||
// isOpenVPN = false;
|
||||
//模擬數據 模拟数据
|
||||
|
||||
if((isInMacau===null||isInMacau===undefined) && isOpenVPN!==null){ //调用地址出错
|
||||
msgType = "1";
|
||||
}
|
||||
@@ -573,6 +921,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
const token = uni.getStorageSync("token");
|
||||
|
||||
let obj = {};
|
||||
obj.loginId = userId;
|
||||
obj.eventCode = eventCode;
|
||||
@@ -585,8 +935,11 @@
|
||||
//console.log(obj);
|
||||
|
||||
try{
|
||||
const token = uni.getStorageSync('token');
|
||||
const response = token ? await writeDebugLog(obj) : await writePublicDebugLog(obj);
|
||||
if(token != undefined && token != null && token !=""){
|
||||
const response = await writeDebugLog(obj);
|
||||
}else{
|
||||
const response = await writePublicDebugLog(obj);
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
console.error(e.errMsg);
|
||||
@@ -616,7 +969,6 @@
|
||||
index:2,
|
||||
visible:false
|
||||
});
|
||||
uni.setTabBarItem({ index: 3, visible: false });
|
||||
if(siteData.mockSSO==false&&!siteData.internalTag){
|
||||
//this.logoutWithADFSApp()
|
||||
uni.redirectTo({
|
||||
@@ -737,6 +1089,8 @@
|
||||
}
|
||||
},
|
||||
kickout() {
|
||||
|
||||
this.logout();
|
||||
uni.removeStorageSync("userData");
|
||||
uni.removeStorageSync("token");
|
||||
uni.removeStorageSync("idToken");
|
||||
|
||||
@@ -2,6 +2,7 @@ export const getBookingsMock = (params, config = {}) => uni.$u.http.post('/app/b
|
||||
export const saveBooking = (params, config = {}) => uni.$u.http.post('/app/booking/create', params, config)
|
||||
export const getBookings = (params, config = {}) => uni.$u.http.post('/app/bookings/search_optimize', params, config)
|
||||
export const getBookingByConf = (params, config = {}) => uni.$u.http.post('/app/booking/get_booking_by_conf', params, config)
|
||||
export const getLimoBookings = (params, config = {}) => uni.$u.http.post('/limo/search_limo', params, config)
|
||||
export const getBookingById = (params, config = {}) => uni.$u.http.post('/app/booking/get_booking_by_id', params, config)
|
||||
export const editBooking = (params, config = {}) => uni.$u.http.post('/app/booking/edit', params, config)
|
||||
export const getBookingsByGroupId = (params, config = {}) => uni.$u.http.post('/app/booking/get_bookings_by_groupId', params, config)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export const writeDebugLog = (params, config = {}) => uni.$u.http.post('/system/write_log', params, config)
|
||||
export const writePublicDebugLog = (params, config = {}) => uni.$u.http.post('/system/write_public_log', params, config)
|
||||
export const getSettingByKey = (params, config = {}) => uni.$u.http.post('/system/sys_setting/get', params, config)
|
||||
export const getSettings = (params, config = {}) => uni.$u.http.post('/system/sys_setting/get_public_login_settings', params, config)
|
||||
export const verifyToken = (params, config = {}) => uni.$u.http.post('/app/me', params, config)
|
||||
export const refreshToken = (params, config = {}) => uni.$u.http.post('/app/refresh_token?isRenewRefreshToken=false', params, config)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
export const getLimoTripPriceList = (params, config = {}) => uni.$u.http.post('/limo/getTripPriceList', params, config)
|
||||
export const getLimoLocation = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/getLocation', { params, ...config })
|
||||
export const getLimoCarType= (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/getCarType', { params, ...config })
|
||||
export const getLimoGreetType = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/getGreetType', { params, ...config })
|
||||
export const getQualification = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/checkQualification', { params, ...config })
|
||||
export const getLimoOverrider = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/getOverrider', { params, ...config })
|
||||
export const getLimoApprover = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/playerLimoBooker', { params, ...config })
|
||||
export const getLimoFlightDetails = (params, config = {}) =>
|
||||
uni.$u.http.get('/limo/getFlightDetails', { params, ...config })
|
||||
export const getLimoTodayBooking = (params, config = {}) => uni.$u.http.post('/limo/getTodayBooking', params, config)
|
||||
export const createLimoBooking = (params, config = {}) => uni.$u.http.post('/limo/createBooking', params, config)
|
||||
export const prepareBooking = (params, config = {}) => uni.$u.http.post('/limo/prepareBooking', params, config)
|
||||
export const editLimoBooking = (params, config = {}) => uni.$u.http.post('/limo/updateBooking', params, config)
|
||||
export const cancelLimoBooking = (params, config = {}) => uni.$u.http.post('/limo/cancelBooking', params, config)
|
||||
export const getLimoBookingById = (params, config = {}) => uni.$u.http.post('/limo/get_limo_booking_by_id', params, config)
|
||||
export const getLimoBookingByConf = (params, config = {}) => uni.$u.http.post('/limo/get_limo_booking_by_conf', params, config)
|
||||
@@ -0,0 +1,9 @@
|
||||
export const saveNotification = (params, config = {}) => uni.$u.http.post('/notification/saveNotification', params, config)
|
||||
export const getNotificationByUserId = (params, config = {}) =>
|
||||
uni.$u.http.get('/notification/get_notification_by_user_id', { params, ...config })
|
||||
export const changeNotification = (params, config = {}) => uni.$u.http.post('/notification/change_status', params, config)
|
||||
export const readAllNotification = (params, config = {}) => uni.$u.http.post('/notification/read_all', params, config)
|
||||
export const countNotification = (params, config = {}) =>
|
||||
uni.$u.http.get('/notification/count_notification_by_user_id', { params, ...config })
|
||||
export const saveDeviceToken = (params, config = {}) => uni.$u.http.post('/deviceToken/save_device_token', params, config)
|
||||
export const updateDeviceToken = (params, config = {}) => uni.$u.http.post('/deviceToken/update_device_token', params, config)
|
||||
@@ -1883,3 +1883,4 @@
|
||||
border-radius: 22px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -502,7 +502,7 @@
|
||||
this.getBooking(this.opt);
|
||||
}else{
|
||||
this.iconPath = '../../static/images/ico_err.png';
|
||||
this.popMsgStr = this.$t("bookingDetail.changeMiscChargeFail");
|
||||
this.popMsgStr = this.$t("bookingDetail.changeMisChargeFail");
|
||||
this.showMsgBox = true;
|
||||
this.showETAMsg = false;
|
||||
|
||||
|
||||
@@ -18,88 +18,138 @@
|
||||
<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 v-if="userData && userData.canViewCalendar === true" @click="navToPlayerRoomCalendar" src="../../static/images/calendar-line.png" class="hz-nav-btn"></image>
|
||||
<image v-else @click="getDataByPage" src="../../static/images/ico_list.png" class="hz-nav-btn"></image>
|
||||
<image @click="navToPlayerRoomCalendar" src="../../static/images/calendar-line.png" class="hz-nav-btn"></image>
|
||||
</view>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="hz-spacing hz-bg-white" style="margin-top:8px;">
|
||||
<view class="hz-card-profile hz-mr-b-30">
|
||||
|
||||
<!-- booking record page -->
|
||||
<view class="hz-spacing hz-bg-white mt-[20]">
|
||||
<view class="hz-card-profile mb-[40]">
|
||||
<view class="hz-flex-row">
|
||||
<view style="width:60%">
|
||||
<view class="hz-w-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-w-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-w-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 v-if="!showEmpty">
|
||||
<!-- 'hz-card-extend' disable extend -->
|
||||
<view @click="navToDetail(booking)" v-for="(booking,index) in bookingList" :key="index"
|
||||
:class="getRecordColor(booking)" class="hz-pd-30 hz-font-bold hz-font-sm" style="margin-top:20rpx;align-items: center;">
|
||||
<view class="hz-flex-row">
|
||||
<view>
|
||||
<view class="hz-font-md">{{$t("common.confirmationNo")}}: {{ getConfirmationNo(booking)}}</view>
|
||||
|
||||
<view>
|
||||
<view v-for="(record,index) in displayRecordList" :key="`${record.recordType}-${record.id || record.confirmationNo || index}`">
|
||||
<view @click="openRecordDetail(record)" :class="getRecordCardClass(record)" class="hz-card-booking hz-record-card hz-pd-30 hz-font-bold hz-font-sm">
|
||||
<view class="hz-flex-row hz-booking-type-row">
|
||||
<view class="hz-booking-type-wrap">
|
||||
<image :src="getBookingTypeIcon(record)" class="hz-booking-type-icon"></image>
|
||||
<view class="hz-font-md">{{ getBookingTypeLabel(record) }}</view>
|
||||
</view>
|
||||
<view class="hz-font-md hz-text-right" :class="getRecordStatusClass(record)">{{getRecordStatusText(record)}}</view>
|
||||
</view>
|
||||
<view style="margin-left:auto">
|
||||
<view class="hz-font-md" :class="getStatusTextColor(booking)">{{getStatusText(booking)}}</view>
|
||||
<view v-if="isHotelRecord(record)">
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-50">
|
||||
<view class="hz-font-md">{{$t("common.confirmationNo")}}: {{ getConfirmationNo(record)}}</view>
|
||||
</view>
|
||||
<view class="hz-w-50">
|
||||
<view class="hz-font-md hz-text-right">{{ record.propertyName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-55">
|
||||
<view class="hz-font-md">{{$t("common.checkInDate")}}: {{ record.checkinDate }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-55">
|
||||
<view class="hz-font-md">{{$t("common.checkOutDate")}}: {{ record.checkoutDate }}</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-sharer-wrap" v-if="canShowSharer(record)">
|
||||
<view v-if="hasSharer(record)" class="hz-btn-sharer hz-font-min hz-sharer-tag">{{$t("bookingRecord.sharer").toUpperCase()}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-55 hz-font-md" v-show="record.eta!==null && record.eta!=='00:00:00'">{{$t("common.etaTime")}}: {{formatEtaToHHmm(record.eta)}}</view>
|
||||
<view v-if="record.miscCharge != null" class="hz-flex-row hz-sharer-wrap">
|
||||
<view>
|
||||
<view class="hz-font-md">{{$t("common.misCharge")}}: {{ formatWithThousands(record.miscCharge) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="hz-flex-row" style="margin-top:6px;">
|
||||
<view v-show="record.eta!==null && record.eta!=='00:00:00'" class="hz-font-md">{{$t("common.etaTime")}}: {{formatEtaToHHmm(record.eta)}}</view>
|
||||
<span v-show="record.eta!==null && record.eta!=='00:00:00' && record.miscCharge!==null" class="hz-font-md" style="padding:0 6px;">|</span>
|
||||
<view v-show="record.miscCharge!==null" class="hz-font-md">{{$t("common.misCharge")}}: {{formatWithThousands(record.miscCharge)}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row" style="margin-top:6px;">
|
||||
<view style="width:55%;">
|
||||
<view class="hz-font-md">{{$t("common.checkInDate")}}: {{ booking.checkinDate }}</view>
|
||||
<!-- 不然就是 limo 的 booking -->
|
||||
<view v-else>
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-100">
|
||||
<view class="hz-font-md">Conf # : {{ getConfirmationNo(record) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-100">
|
||||
<view class="hz-font-md">{{$t("limoBookingRecord.pickupDatetime")}}: {{ record.pickupDatetime }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-100">
|
||||
<view class="hz-font-md">{{$t("limoBookingRecord.pickup")}}: {{ record.pickup }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="record.extraDropoff && record.extraDropoff.length" class="hz-flex-row hz-row-gap">
|
||||
<view class="hz-w-100">
|
||||
<view class="hz-font-md">{{$t("limoBookingRecord.extraDropoff")}}:</view>
|
||||
<view class="hz-font-md" v-for="(dropoffPoint,index) in record.extraDropoff" :key="index">
|
||||
#{{index + 1}}:{{dropoffPoint}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-row-gap hz-flex-vertical-mid">
|
||||
<view class="hz-w-100 hz-limo-dropoff-wrap">
|
||||
<view class="hz-font-md">
|
||||
{{$t("limoBookingRecord.dropoff")}}: {{record.dropoff}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="width:50%;">
|
||||
<view style="text-align: right;" class="hz-font-md">{{ booking.propertyName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row" style="margin-top:6px;">
|
||||
<view style="width:55%;">
|
||||
<view class="hz-font-md">{{$t("common.checkOutDate")}}: {{ booking.checkoutDate }}</view>
|
||||
</view>
|
||||
<!-- enable sharer and extend 2024-09-27 -->
|
||||
<view class="hz-flex-row" style="width:50%;text-align: right;justify-content: flex-end;" v-if="userData.canNewBooking&&booking.propertyCategory!='OTHER'">
|
||||
<view v-if="(booking.sharer!==null && booking.sharer!=='[]')||booking.isShare" class="hz-btn-sharer hz-font-min" style="width:40%;height:14px;line-height:14px;margin-right: 3px;">{{$t("bookingRecord.sharer").toUpperCase()}}</view>
|
||||
<!-- <view @click="navToDetail(booking)" v-if="((booking.lastOperaStatus==='DUE_OUT' || booking.lastOperaStatus==='CHECKED_IN') && booking.confirmationNo!=null && (booking.approveStatus!='W'&&booking.approveStatus!='PN'))" class="hz-btn-extend hz-font-min" style="width:40%;height:14px;line-height:14px;">{{$t("bookingRecord.extend").toUpperCase()}}</view> -->
|
||||
<!-- <view @click="navTo('/booking/bookingGroup/bookingGroup?groupId='+booking.groupId,0,false)" v-if="booking.groupId!==undefined && booking.groupId!==null && booking.groupId!==''" class="hz-btn-group" style="margin-left:8px;">{{$t("bookingRecord.group")}}</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="hz-flex-row" style="margin-top:6px;">
|
||||
<view v-show="booking.eta!==null && booking.eta!=='00:00:00'" class="hz-font-md">{{$t("common.etaTime")}}: {{formatEtaToHHmm(booking.eta)}}</view>
|
||||
<span v-show="booking.eta!==null && booking.eta!=='00:00:00' && booking.miscCharge!==null" class="hz-font-md" style="padding:0 6px;">|</span>
|
||||
<view v-show="booking.miscCharge!==null" class="hz-font-md">{{$t("common.misCharge")}}: {{formatWithThousands(booking.miscCharge)}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <u-loadmore :status="showLoadMore" :loadmoreText="loadMoreStr" :nomoreText="nomoreStr" :fontSize="14" color="#ccc" :line="true" /> -->
|
||||
</view>
|
||||
<u-empty
|
||||
v-if="showEmpty"
|
||||
|
||||
<!-- <u-empty
|
||||
v-if="isDisplayEmpty"
|
||||
mode="search"
|
||||
:text="dataNotFoundStr"
|
||||
>
|
||||
</u-empty>
|
||||
</u-empty> -->
|
||||
</view>
|
||||
<u-tabbar
|
||||
:fixed="true"
|
||||
:placeholder="true"
|
||||
:safeAreaInsetBottom="true"
|
||||
customStyle="z-index:100;height:58px;"
|
||||
v-if="userData.canNewBooking"
|
||||
>
|
||||
<view class="book hz-flex-row hz-spacing">
|
||||
<view class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center" @click="navToNewBooking()">
|
||||
<view v-if="userData.canNewBooking" class="book hz-flex-row hz-spacing hz-book-btn-wrap" :class="{'hz-book-btn-wrap--single': hasSingleBookingPermission}">
|
||||
<view class="hz-btn hz-font-color-white hz-font-sm hz-font-bold hz-text-center" @click="navToNewBooking()">
|
||||
{{$t("bookingRecord.newsBooking")}}
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="userData.canViewLimo" class="book hz-flex-row hz-spacing hz-book-btn-wrap" :class="{'hz-book-btn-wrap--single': hasSingleBookingPermission}">
|
||||
<view class="hz-btn hz-font-color-white hz-font-sm hz-font-bold hz-text-center" @click="navToNewLimo()">
|
||||
{{$t("bookingRecord.newLimo")}}
|
||||
</view>
|
||||
</view>
|
||||
</u-tabbar>
|
||||
<u-modal :content="msgStr" :show="showMsg" :confirmText="yesText" :showCancelButton="false" closeOnClickOverlay @confirm="showMsg=false" confirmColor="#C39A4B" @close="showMsg=false"></u-modal>
|
||||
</view>
|
||||
@@ -109,7 +159,7 @@
|
||||
<script>
|
||||
import {playerLookup} from '../../api/mgmApi.js'
|
||||
import {mapOperaStatus,mapApproveStatus} from '../../common/mapping.js'
|
||||
import {getBookingsMock,getBookings} from '../../api/bookingApi.js';
|
||||
import {getBookings, getLimoBookings} from '../../api/bookingApi.js';
|
||||
import dayjs from '../../uni_modules/uview-ui/libs/util/dayjs.js';
|
||||
export default {
|
||||
data() {
|
||||
@@ -121,15 +171,14 @@
|
||||
dataNotFoundStr:this.$t("common.dataNotFound"),
|
||||
// 界面变量
|
||||
from:'',
|
||||
showEmpty:false,
|
||||
title:'',
|
||||
footFuncHei:100,
|
||||
currentIndex:0,
|
||||
showMsg:false,
|
||||
msgStr:this.$t("bookingRecord.operaProfile"),
|
||||
yesText:this.$t("common.ok"),
|
||||
currentTask:null,
|
||||
getDataByPageRequestId:0,
|
||||
limoBookingList:[
|
||||
]
|
||||
}
|
||||
},
|
||||
onLoad(opt) {
|
||||
@@ -145,6 +194,8 @@
|
||||
// 检查是否登录
|
||||
this.isLogin();
|
||||
// 拿localstorage中的playerData
|
||||
//修改MiscCharge后 返回页面自动刷新
|
||||
// this.refreshHotelBooking();
|
||||
|
||||
this.getDataByPage();
|
||||
},
|
||||
@@ -153,49 +204,109 @@
|
||||
this.pullDownRefresh();
|
||||
},
|
||||
methods: {
|
||||
navToPlayerRoomCalendar(){
|
||||
const userData = uni.getStorageSync("userData");
|
||||
if (!userData || userData.canViewCalendar !== true) return;
|
||||
this.navTo('/booking/playerRoomCalendar/playerRoomCalendar',0,false);
|
||||
updateHotelBookingList(res){
|
||||
if(Array.isArray(res) && res.length > 0){
|
||||
this.bookingList = res;
|
||||
}else{
|
||||
this.bookingList = [];
|
||||
}
|
||||
},
|
||||
updateLimoBookingList(res) {
|
||||
if(this.userData.canViewLimo==false) return;
|
||||
if (Array.isArray(res) && res.length > 0) {
|
||||
let temp = res.map(item => {
|
||||
const pickUpDatetime = item.pickUpDatetime || item.pickUpDateTime || item.pickupDatetime || '';
|
||||
return {
|
||||
id: item.id,
|
||||
recordType: 'limo',
|
||||
confirmationNo: item.confirmationNo,
|
||||
status: item.bookingStatus,
|
||||
pickUpDatetime,
|
||||
pickupDatetime: this.formatDate(pickUpDatetime, 'YYYY-MM-DD HH:mm'),
|
||||
pickup: item.pickUpPoint,
|
||||
dropoff: item.dropOffPoint,
|
||||
extraDropoff:this.getExtraDropOff(item.extraDropOffPoint)
|
||||
// extraDropoff:item.extraDropOffPoint.split(";")
|
||||
}
|
||||
});
|
||||
|
||||
this.limoBookingList = temp;
|
||||
} else {
|
||||
this.limoBookingList = [];
|
||||
}
|
||||
},
|
||||
openBookingPage(path){
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
this.navTo(path,0,false);
|
||||
uni.hideLoading();
|
||||
},
|
||||
|
||||
// 數據方法
|
||||
async getDataByPage(){
|
||||
if(this.userData.canViewBooking==false) return;
|
||||
if(this.currentTask){
|
||||
const previousTask = this.currentTask;
|
||||
const requestId = ++this.getDataByPageRequestId;
|
||||
if(previousTask){
|
||||
try{
|
||||
this.currentTask.abort();
|
||||
previousTask.abort();
|
||||
}catch(err){
|
||||
}
|
||||
}
|
||||
const requestId = ++this.getDataByPageRequestId;
|
||||
|
||||
// 一次页面加载会同时发起 Hotel 和 Limo 请求,统一保存并取消它们。
|
||||
const requestTasks = [];
|
||||
const requestController = {
|
||||
abort: () => {
|
||||
requestTasks.forEach(task => {
|
||||
if(task && typeof task.abort === 'function'){
|
||||
try{
|
||||
task.abort();
|
||||
}catch(err){
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
const requestConfig = {
|
||||
getTask: task => {
|
||||
if(requestId === this.getDataByPageRequestId){
|
||||
requestTasks.push(task);
|
||||
}else if(task && typeof task.abort === 'function'){
|
||||
task.abort();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.currentTask = requestController;
|
||||
let params = {};
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
try{
|
||||
if(this.playerData.nameIds.length==0){
|
||||
await this.getProfileByPlayerId(requestId)
|
||||
await this.getProfileByPlayerId(requestId, requestConfig)
|
||||
}else{
|
||||
params.member = this.playerData
|
||||
params.member = this.playerData;
|
||||
params.userId = this.userData.userId;
|
||||
const res = await getBookings(params, {
|
||||
getTask: (task, options) => {
|
||||
this.currentTask = task;
|
||||
}
|
||||
params.profileId = this.playerData.profileId;
|
||||
const limoPromise = getLimoBookings(params, requestConfig).catch((e) => {
|
||||
return null;
|
||||
});
|
||||
const hotelPromise = getBookings(params, requestConfig).catch((e) => {
|
||||
return null;
|
||||
});
|
||||
const [resLimo, resHotel] = await Promise.all([limoPromise, hotelPromise]);
|
||||
if(requestId !== this.getDataByPageRequestId) return;
|
||||
this.currentTask = null;
|
||||
this.bookingList = [];
|
||||
if(res.length>0){
|
||||
if(res!==undefined && res!==null){
|
||||
this.bookingList = res;
|
||||
}
|
||||
}else{
|
||||
|
||||
if (resLimo) {
|
||||
this.updateLimoBookingList(resLimo);
|
||||
}
|
||||
if (resHotel) {
|
||||
this.updateHotelBookingList(resHotel);
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
if(e.errMsg!==undefined && e.errMsg.includes("abort")){
|
||||
if(requestId !== this.getDataByPageRequestId || (e && e.errMsg!==undefined && e.errMsg.includes("abort"))){
|
||||
return;
|
||||
}
|
||||
// console.log(e);
|
||||
@@ -204,11 +315,38 @@
|
||||
await this.writeLog(this.userData.userId,"save_booking","","[APP][bookingDetail.vue][getDataByPage][Catch Exception]"+e.errMsg,"[RequestData]" +JSON.stringify(params),"",1,false);
|
||||
}finally{
|
||||
if(requestId === this.getDataByPageRequestId){
|
||||
this.currentTask = null;
|
||||
if(this.currentTask === requestController){
|
||||
this.currentTask = null;
|
||||
}
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
},
|
||||
async refreshHotelBooking(){
|
||||
if(this.userData.canViewBooking==false) return;
|
||||
let params = {};
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
try{
|
||||
if(this.playerData.nameIds.length==0){
|
||||
await this.getProfileByPlayerId()
|
||||
}else{
|
||||
params.member = this.playerData;
|
||||
params.userId = this.userData.userId;
|
||||
params.profileId = this.playerData.profileId;
|
||||
const resHotel = await getBookings(params);
|
||||
this.updateHotelBookingList(resHotel);
|
||||
}
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
// write log
|
||||
uni.$u.toast(e.errMsg,5000);
|
||||
await this.writeLog(this.userData.userId,"save_booking","","[APP][bookingDetail.vue][getDataByPage][Catch Exception]"+e.errMsg,"[RequestData]" +JSON.stringify(params),"",1,false);
|
||||
}finally{
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
pullDownRefresh(){
|
||||
try{
|
||||
this.getDataByPage('refresh');
|
||||
@@ -217,6 +355,60 @@
|
||||
}
|
||||
},
|
||||
// 界面方法
|
||||
isHotelRecord(record){
|
||||
return record.recordType === 'hotel';
|
||||
},
|
||||
getRecordCardClass(record){
|
||||
return this.getRecordColor(record);
|
||||
},
|
||||
openRecordDetail(record){
|
||||
if(this.isHotelRecord(record)){
|
||||
this.navToDetail(record);
|
||||
}else{
|
||||
this.navToLimoDetail(record);
|
||||
}
|
||||
},
|
||||
getBookingTypeIcon(record){
|
||||
if(this.isHotelRecord(record)){
|
||||
return '../../static/images/ico_hotel_active.png';
|
||||
}
|
||||
return '../../static/icon/tabbar/taxi-fill.png';
|
||||
},
|
||||
getBookingTypeLabel(record){
|
||||
let bookingType = this.$t("limoBookingRecord.bookingType");
|
||||
if(this.isHotelRecord(record)){
|
||||
return bookingType+': Hotel';
|
||||
}
|
||||
return bookingType+': Limo';
|
||||
},
|
||||
getRecordStatusText(record){
|
||||
if(this.isHotelRecord(record)){
|
||||
return this.getStatusText(record);
|
||||
}else{
|
||||
return record.status.replace("_"," ");
|
||||
}
|
||||
},
|
||||
getRecordStatusClass(record){
|
||||
return this.getStatusTextColor(record);
|
||||
},
|
||||
canShowSharer(record){
|
||||
return this.userData && this.userData.canNewBooking && record.propertyCategory!='OTHER';
|
||||
},
|
||||
hasSharer(record){
|
||||
return (record.sharer!==null && record.sharer!=='[]')||record.isShare;
|
||||
},
|
||||
hasEta(record){
|
||||
return record.eta!==undefined && record.eta!==null && record.eta!=='';
|
||||
},
|
||||
getDropOffPointLines(dropOffPoint){
|
||||
if(dropOffPoint === null || dropOffPoint === undefined || dropOffPoint === '') return [''];
|
||||
return String(dropOffPoint).split(/[;;]/).map(item => item.trim()).filter(item => item !== '');
|
||||
},
|
||||
getExtraDropOffPoint(dropOffPoint){
|
||||
if(dropOffPoint === null || dropOffPoint === undefined || dropOffPoint === '') return [''];
|
||||
|
||||
return String(dropOffPoint).split(/[;;]/).map(item => item.trim()).filter(item => item !== '');
|
||||
},
|
||||
back(){
|
||||
if(this.from==='booking'){
|
||||
this.navTo("/pages/findPlayer/findPlayer",1,false);
|
||||
@@ -227,6 +419,12 @@
|
||||
navToDetail(booking){
|
||||
this.navTo('/booking/bookingDetail/bookingDetail?id='+booking.id+"&conf="+booking.confirmationNo+"&from=list",0,false)
|
||||
},
|
||||
navToLimoDetail(limoBooking){
|
||||
this.navTo('/limo/bookingDetail/bookingDetail?id=' + limoBooking.id +'&conf='+limoBooking.confirmationNo+"&from=list",0,false)
|
||||
},
|
||||
navToPlayerRoomCalendar(){
|
||||
this.navTo('/booking/playerRoomCalendar/playerRoomCalendar',0,false)
|
||||
},
|
||||
// ETA 统一显示 HH:mm(兼容 HH:mm:ss / HH:mm)
|
||||
formatEtaToHHmm(eta) {
|
||||
if (eta === null || eta === undefined || eta === '') return '';
|
||||
@@ -259,81 +457,170 @@
|
||||
this.title = this.$t("bookingRecord.title");
|
||||
},
|
||||
navToNewBooking(){
|
||||
this.getDataByPage();
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
// remove no opera restrict
|
||||
// if(this.playerData.nameIds.length==0){
|
||||
// this.showMsg = true;
|
||||
// }else{
|
||||
// this.navTo('/booking/newBooking/newBooking',0,false)
|
||||
// }
|
||||
this.navTo('/booking/newBooking/newBooking',0,false)
|
||||
uni.hideLoading();
|
||||
this.openBookingPage('/booking/newBooking/newBooking');
|
||||
},
|
||||
async getProfileByPlayerId(requestId){
|
||||
navToNewLimo(){
|
||||
this.openBookingPage('/limo/newLimo/newLimo?from=bookingRecord');
|
||||
},
|
||||
async getProfileByPlayerId(requestId = this.getDataByPageRequestId, requestConfig = {}){
|
||||
try{
|
||||
let params = {playerId:this.playerData.playerId,userId:this.userData.userId};
|
||||
const res = await playerLookup(params, {
|
||||
getTask: (task, options) => {
|
||||
this.currentTask = task;
|
||||
}
|
||||
});
|
||||
const params = {playerId:this.playerData.playerId,userId:this.userData.userId};
|
||||
const res = await playerLookup(params, requestConfig);
|
||||
if(requestId !== this.getDataByPageRequestId) return;
|
||||
if(res.success == true){
|
||||
var player = res.data;
|
||||
const player = res.data;
|
||||
if(player !== null){
|
||||
if(player.codedFlag==1){
|
||||
uni.setStorageSync("playerData",player);
|
||||
this.playerData = uni.getStorageSync("playerData");
|
||||
let params = {};
|
||||
params.member = player
|
||||
params.userId = this.userData.userId;
|
||||
const res = await getBookings(params, {
|
||||
getTask: (task, options) => {
|
||||
this.currentTask = task;
|
||||
}
|
||||
});
|
||||
const bookingParams = {
|
||||
member: player,
|
||||
userId: this.userData.userId
|
||||
};
|
||||
const [resHotel, resLimo] = await Promise.all([
|
||||
getBookings(bookingParams, requestConfig),
|
||||
getLimoBookings(bookingParams, requestConfig)
|
||||
]);
|
||||
if(requestId !== this.getDataByPageRequestId) return;
|
||||
this.currentTask = null;
|
||||
this.bookingList = [];
|
||||
if(res.length>0){
|
||||
if(res!==undefined && res!==null){
|
||||
this.bookingList = res;
|
||||
}
|
||||
}else{
|
||||
}
|
||||
this.updateHotelBookingList(resHotel);
|
||||
this.updateLimoBookingList(resLimo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
if(e.errMsg!==undefined && e.errMsg.includes("abort")){
|
||||
if(requestId !== this.getDataByPageRequestId || (e && e.errMsg!==undefined && e.errMsg.includes("abort"))){
|
||||
return;
|
||||
}
|
||||
console.error(e);
|
||||
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{
|
||||
}
|
||||
},
|
||||
formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||
const d = new Date(date);
|
||||
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]);
|
||||
},
|
||||
getExtraDropOff(extraDropOffPoint) {
|
||||
let returnExtraDropOffPoint = null;
|
||||
if(extraDropOffPoint!=undefined && extraDropOffPoint!=null && extraDropOffPoint!=''){
|
||||
returnExtraDropOffPoint = extraDropOffPoint.split(";");
|
||||
}
|
||||
console.log(returnExtraDropOffPoint);
|
||||
return returnExtraDropOffPoint;
|
||||
},
|
||||
/** 用于酒店 / limo 混合列表排序:越大表示时间越晚 */
|
||||
getRecordSortTimeMs(record) {
|
||||
if (!record) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
if (record.recordType === 'limo') {
|
||||
const raw = record.pickUpDatetime || record.pickUpDateTime || record.pickupDatetime;
|
||||
if (raw != null && raw !== '') {
|
||||
const n = Number(raw);
|
||||
if (!Number.isNaN(n)) {
|
||||
return n;
|
||||
}
|
||||
const parsedRaw = dayjs(String(raw).trim());
|
||||
if (parsedRaw.isValid()) {
|
||||
return parsedRaw.valueOf();
|
||||
}
|
||||
}
|
||||
if (record.pickupDatetime) {
|
||||
const s = String(record.pickupDatetime).trim();
|
||||
const m = s.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})\s+(\d{1,2}):(\d{2})$/);
|
||||
if (m) {
|
||||
const year = m[3].length === 2 ? 2000 + parseInt(m[3], 10) : parseInt(m[3], 10);
|
||||
const d = new Date(
|
||||
year,
|
||||
parseInt(m[2], 10) - 1,
|
||||
parseInt(m[1], 10),
|
||||
parseInt(m[4], 10),
|
||||
parseInt(m[5], 10)
|
||||
);
|
||||
if (!Number.isNaN(d.getTime())) {
|
||||
return d.getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
const checkInDate = record.checkinDate || record.checkInDate || record.CheckInDate;
|
||||
if (checkInDate != null && String(checkInDate).trim() !== '') {
|
||||
const parsed = dayjs(String(checkInDate).trim());
|
||||
if (parsed.isValid()) {
|
||||
return parsed.valueOf();
|
||||
}
|
||||
}
|
||||
return Number.POSITIVE_INFINITY;
|
||||
},
|
||||
getRecordSortDateMs(record) {
|
||||
const timeMs = this.getRecordSortTimeMs(record);
|
||||
if (!Number.isFinite(timeMs) || Number.isNaN(timeMs)) {
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
const d = new Date(timeMs);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.getTime();
|
||||
},
|
||||
getRecordTypeSortIndex(record) {
|
||||
return record && record.recordType === 'limo' ? 1 : 0;
|
||||
},
|
||||
compareRecordForDisplay(a, b) {
|
||||
const dateA = this.getRecordSortDateMs(a);
|
||||
const dateB = this.getRecordSortDateMs(b);
|
||||
if (dateA !== dateB) {
|
||||
return dateA - dateB;
|
||||
}
|
||||
const typeDiff = this.getRecordTypeSortIndex(a) - this.getRecordTypeSortIndex(b);
|
||||
if (typeDiff !== 0) {
|
||||
return typeDiff;
|
||||
}
|
||||
if (a && b && a.recordType === 'limo' && b.recordType === 'limo') {
|
||||
const timeA = this.getRecordSortTimeMs(a);
|
||||
const timeB = this.getRecordSortTimeMs(b);
|
||||
if (timeA !== timeB) {
|
||||
return timeA - timeB;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
hasSingleBookingPermission(){
|
||||
if (!this.userData) return false;
|
||||
return Boolean(this.userData.canNewBooking) !== Boolean(this.userData.canViewLimo);
|
||||
},
|
||||
displayRecordList(){
|
||||
const hotelRecords = this.bookingList.map(item => ({...item, recordType: 'hotel'}));
|
||||
const limoRecords = this.limoBookingList.map(item => ({...item, recordType: 'limo'}));
|
||||
console.log(limoRecords);
|
||||
return hotelRecords.concat(limoRecords).sort((a, b) => this.compareRecordForDisplay(a, b));
|
||||
},
|
||||
isDisplayEmpty(){
|
||||
return this.displayRecordList.length === 0;
|
||||
},
|
||||
getConfirmationNo(){
|
||||
return function (booking) {
|
||||
if(booking!==undefined && booking!==null){
|
||||
if(booking.confirmationNo!==undefined && booking.confirmationNo!==null &&
|
||||
booking.confirmationNo!=='null' && booking.confirmationNo!=='' && booking.approveStatus!='W'){
|
||||
booking.confirmationNo!=='null' && booking.confirmationNo!=='' && booking.approveStatus!='W' && booking.approveStatus!='AP'){
|
||||
return booking.confirmationNo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'N/A';
|
||||
}
|
||||
}else{
|
||||
return 'N/A';
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
},
|
||||
dateFormat() {
|
||||
@@ -439,7 +726,41 @@
|
||||
if(booking.approveStatus!=null){
|
||||
approveStatus = booking.approveStatus;
|
||||
}
|
||||
// Opera和Approve Status都不为空的情况
|
||||
if(booking.recordType === 'limo'){
|
||||
const noOpera = operaStatus==null || operaStatus==undefined || operaStatus==='' || operaStatus==='null';
|
||||
const noApprove = approveStatus==null || approveStatus==undefined || approveStatus==='' || approveStatus==='null';
|
||||
if(noOpera && noApprove && booking.status!=null && booking.status!==undefined && String(booking.status).trim()!==''){
|
||||
const s = String(booking.status).toUpperCase().replace(/\s+/g,' ');
|
||||
if(s.includes('CANCEL')){
|
||||
return 'hz-status-font-cancel';
|
||||
}
|
||||
if(s.includes('WAITLIST') || s.includes('WAIT LIST')){
|
||||
return 'hz-status-font-waitlist';
|
||||
}
|
||||
if(s.includes('NOT YET')){
|
||||
return 'hz-status-font-waitlist';
|
||||
}
|
||||
if(s.includes('PENDING')){
|
||||
return 'hz-status-font-pending';
|
||||
}
|
||||
if(s.includes('CONFIRM')){
|
||||
return 'hz-status-font-duein';
|
||||
}
|
||||
if(s.includes('DRIVER_DEPARTED')){
|
||||
return 'hz-status-font-duein';
|
||||
}
|
||||
if(s.includes('DRIVER_ASSIGNED')){
|
||||
return 'hz-status-font-duein';
|
||||
}
|
||||
if(s.includes('DRIVER_ARRIVED')){
|
||||
return 'hz-status-font-duein';
|
||||
}
|
||||
if(s.includes('GUEST_PICKED')){
|
||||
return 'hz-status-font-duein';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
if((operaStatus!=null && operaStatus!=undefined) || (approveStatus!=null && approveStatus!=undefined))
|
||||
{
|
||||
if(approveStatus.toUpperCase()==='PN'||approveStatus.toUpperCase()==='F'){
|
||||
@@ -553,12 +874,31 @@
|
||||
},
|
||||
getRecordColor(){
|
||||
return function (booking) {
|
||||
if(booking==null){
|
||||
return 'hz-card-booking';
|
||||
}
|
||||
if(booking.recordType === 'limo'){
|
||||
const noApprove = booking.approveStatus==null || booking.approveStatus===undefined || booking.approveStatus==='' || booking.approveStatus==='null';
|
||||
const noOpera = booking.lastOperaStatus==null || booking.lastOperaStatus===undefined || booking.lastOperaStatus==='' || booking.lastOperaStatus==='null';
|
||||
if(noApprove && noOpera && booking.status!=null && booking.status!==undefined && String(booking.status).trim()!==''){
|
||||
const s = String(booking.status).toUpperCase().replace(/\s+/g,' ');
|
||||
if(s.includes('NOT YET') || s.includes('CONFIRM')){
|
||||
return 'hz-card-booking';
|
||||
}
|
||||
if(s.includes('WAITLIST') || s.includes('WAIT LIST') || s.includes('PENDING')){
|
||||
return 'hz-card-waitlist';
|
||||
}
|
||||
return 'hz-card-booking';
|
||||
}
|
||||
}
|
||||
if(booking.approveStatus==='W'|| booking.approveStatus==='WA'){
|
||||
return 'hz-card-waitlist'
|
||||
}else if(booking.approveStatus==='AP'){
|
||||
return 'hz-card-approval'
|
||||
}else if((booking.lastOperaStatus==='DUE_OUT' || booking.lastOperaStatus==='CHECKED_IN') && booking.confirmationNo!=null && (booking.sharer==null || booking.sharer==='[]' || booking.sharer==='')){
|
||||
return 'hz-card-booking'
|
||||
}else if(booking.approveStatus==='AP'){
|
||||
return 'hz-card-approval'
|
||||
}else{
|
||||
return 'hz-card-booking'
|
||||
}
|
||||
@@ -581,5 +921,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.hz-book-btn-wrap--single {
|
||||
width: 95%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -460,7 +460,6 @@
|
||||
this.modelBooking.propertyId = this.userData.propertyId;
|
||||
|
||||
this.modelBooking.teamId = this.userData.teamStructureId;
|
||||
this.modelBooking.sectionName = this.userData.section;
|
||||
this.modelBooking.sectionId = this.userData.sectionId;
|
||||
this.modelBooking.createdBy = this.userData.userId;
|
||||
this.modelBooking.createdByName = this.userData.userName;
|
||||
@@ -779,6 +778,7 @@
|
||||
|
||||
this.currentTask = null;
|
||||
|
||||
|
||||
if (res.success) {
|
||||
item.name = res.data.englishName;
|
||||
item.tierName = res.data.tierName || "";
|
||||
@@ -807,10 +807,10 @@
|
||||
let item = this.modelBooking.sharerList[index];
|
||||
let book = uni.getStorageSync("bookingData")
|
||||
let oldItem = book.sharerList[index];
|
||||
// 姓名被手动修改后,清除不再匹配的玩家 ID。
|
||||
if (item.name != oldItem.name && item.playerId.length > 4) {
|
||||
item.playerId = "";
|
||||
}
|
||||
//清空plaerId
|
||||
// if (item.name != oldItem.name && item.playerId.length == 8) {
|
||||
// item.playerId = "";
|
||||
// }
|
||||
},
|
||||
async buildCalendar() {
|
||||
uni.showLoading({
|
||||
|
||||
@@ -18,19 +18,19 @@
|
||||
<!-- <view class="player-summary"> -->
|
||||
<view class="hz-card-profile mb-[40]" style="margin:9px 9px 6px;">
|
||||
<view class="hz-flex-row">
|
||||
<view style="width:60%">
|
||||
<view class="hz-w-60">
|
||||
<view class="hz-font-color-light hz-font-sm">{{$t("common.playerId")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" >{{ safePlayerData.playerId }}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" >{{ playerData.playerId }}</view>
|
||||
</view>
|
||||
<view style="width:40%">
|
||||
<view class="hz-w-40">
|
||||
<view class="hz-font-color-light hz-font-sm">{{$t("common.tier")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" >{{ safePlayerData.tierName }}</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-w-100">
|
||||
<view class="hz-font-color-light hz-font-sm">{{$t("common.name")}}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" >{{ playerName }}</view>
|
||||
<view class="hz-font-bolder hz-font-lg" >{{playerData.salutation + " " + playerData.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -197,13 +197,11 @@
|
||||
propertyTabItemStyle() {
|
||||
return {
|
||||
height: '70rpx',
|
||||
padding: '0 24rpx',
|
||||
flexShrink: 0,
|
||||
padding: '0',
|
||||
};
|
||||
},
|
||||
propertyTabActiveStyle() {
|
||||
return {
|
||||
whiteSpace: 'nowrap',
|
||||
color: '#C39A4B',
|
||||
fontFamily: 'Inter-Bold',
|
||||
fontSize: '30rpx',
|
||||
@@ -212,7 +210,6 @@
|
||||
},
|
||||
propertyTabInactiveStyle() {
|
||||
return {
|
||||
whiteSpace: 'nowrap',
|
||||
color: '#111111',
|
||||
fontFamily: 'Inter-Bold',
|
||||
fontSize: '30rpx',
|
||||
@@ -241,7 +238,6 @@
|
||||
this.navBack();
|
||||
},
|
||||
async loadPropertiesRoomTypes() {
|
||||
if (!this.canLoadPlayerCalendar()) return;
|
||||
try {
|
||||
this.calendarReady = false;
|
||||
uni.showLoading({
|
||||
@@ -249,19 +245,14 @@
|
||||
});
|
||||
await this.loadCalendarSetting();
|
||||
const res = await getPropertiesRoomTypes({});
|
||||
if (this.isNoPermissionResponse(res)) {
|
||||
this.showCalendarNoPermission();
|
||||
return;
|
||||
}
|
||||
this.propertyList = Array.isArray(res && res.propertyList) ? res.propertyList : [];
|
||||
if (!this.propertyList.length) throw new Error('No calendar properties configured');
|
||||
this.propertyList = res.propertyList;
|
||||
this.selectedPropertyCode = this.getDefaultPropertyCode();
|
||||
this.selectDefaultOptions();
|
||||
this.buildCalendar();
|
||||
await this.loadQualificationData();
|
||||
this.calendarRenderKey += 1;
|
||||
this.$nextTick(() => {
|
||||
this.calendarReady = !this.calendarNoPermission;
|
||||
this.calendarReady = true;
|
||||
});
|
||||
} catch (e) {
|
||||
uni.$u.toast(e.message || e.errMsg || 'Load property room types failed');
|
||||
@@ -464,12 +455,10 @@
|
||||
}));
|
||||
},
|
||||
refreshCalendar() {
|
||||
if (!this.canLoadPlayerCalendar()) return;
|
||||
this.ensureSelectedOptionsForRefresh(true);
|
||||
this.loadQualificationData();
|
||||
},
|
||||
async loadQualificationData() {
|
||||
if (!this.canLoadPlayerCalendar()) return;
|
||||
const records = [];
|
||||
const dateRange = this.getCalendarDateRange();
|
||||
const requestId = this.startCalendarRequest();
|
||||
@@ -523,20 +512,7 @@
|
||||
});
|
||||
},
|
||||
isNoPermissionResponse(res) {
|
||||
return res && res.success === false && (res.errorCode || res.code) === 'NO_PERMISSION';
|
||||
},
|
||||
canLoadPlayerCalendar() {
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
if (!this.userData || this.userData.canViewCalendar !== true) {
|
||||
this.showCalendarNoPermission();
|
||||
return false;
|
||||
}
|
||||
if (!this.safePlayerData.playerId) {
|
||||
this.calendarReady = false;
|
||||
uni.$u.toast(this.$t("common.dataNotFound"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return res && res.success === false && res.errorCode === 'NO_PERMISSION';
|
||||
},
|
||||
showCalendarNoPermission() {
|
||||
this.qualificationMap = {};
|
||||
|
||||
@@ -139,10 +139,10 @@
|
||||
<!-- <view class="hz-font-bolder hz-font-lg" >{{ handleShowWhenScreenshot(bookingData.eta) }}</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="bookingData.miscCharge!=null" class="hz-flex-row">
|
||||
<view v-if="bookingData.mischarge!=null" class="hz-flex-row">
|
||||
<view style="width:100%">
|
||||
<view class="hz-font-color-black hz-font-sm">{{ $t("common.misCharge") }}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{ bookingData.miscCharge || "-" }}</view>
|
||||
<view class="hz-font-bolder hz-font-lg">{{ bookingData.mischarge || "-" }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -254,18 +254,19 @@
|
||||
<!-- Remark -->
|
||||
<view style="margin-bottom: 16px;margin-top: 16px;">
|
||||
<view style="text-align: left;">{{$t("bookingConfirm.approvalRemark")}}</view>
|
||||
<u-checkbox-group placement="row"
|
||||
:value="unqualifiedDateCheckboxStates[currentUnqualifiedIndex] || []"
|
||||
@change="changeOtherRemark"
|
||||
<u-checkbox-group placement="row" @change="changeOtherRemark"
|
||||
v-model="unqualifiedDateCheckboxStates[currentUnqualifiedIndex]"
|
||||
style="flex-direction: unset;display: block;">
|
||||
<view style="width:50%;display: inline-flex;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="Extend" name="Extend"></u-checkbox>
|
||||
customStyle="height:30px;width:100%;" label="Extend" name="Extend"
|
||||
:value="unqualifiedDateCheckboxStates[currentUnqualifiedIndex] && unqualifiedDateCheckboxStates[currentUnqualifiedIndex].includes('Extend')"></u-checkbox>
|
||||
|
||||
</view>
|
||||
<view style="width:50%;display: inline-flex;position: relative;left:10%;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="Remark" name="Remark"></u-checkbox>
|
||||
customStyle="height:30px;width:100%;" label="Remark" name="Remark"
|
||||
:value="unqualifiedDateCheckboxStates[currentUnqualifiedIndex] && unqualifiedDateCheckboxStates[currentUnqualifiedIndex].includes('Remark')"></u-checkbox>
|
||||
</view>
|
||||
</u-checkbox-group>
|
||||
<view style="width:100%;margin-top:16px;" v-show="showRemark">
|
||||
@@ -328,32 +329,41 @@
|
||||
<rich-text v-html="msgStr" style="line-height:26px;"></rich-text>
|
||||
</view>
|
||||
<view style="margin-bottom: 10px;text-align: left;"> {{$t("bookingConfirm.approvalRemark")}}</view>
|
||||
<!-- uView:u-checkbox 必须在 u-checkbox-group 内;房型互斥用 group + 受控 :value -->
|
||||
<u-checkbox-group placement="row"
|
||||
:value="waitlistRoomGroupValue"
|
||||
@change="onWaitlistRoomRemarkGroupChange"
|
||||
<u-radio-group placement="row" @change="changeRoomRemark" v-if="showRadio"
|
||||
style="flex-direction: unset;display: block;">
|
||||
<view style="width:50%;display: inline-flex;">
|
||||
<u-radio activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="2nd Room" name="2nd Room"></u-radio>
|
||||
|
||||
</view>
|
||||
<view style="width:50%;display: inline-flex;position: relative;left:10%;">
|
||||
<u-radio activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="3rd Room" name="3rd Room"></u-radio>
|
||||
</view>
|
||||
</u-radio-group>
|
||||
<u-checkbox-group placement="row" v-else style="flex-direction: unset;display: block;">
|
||||
<view style="width:50%;display: inline-flex;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="2nd Room" name="2nd Room"></u-checkbox>
|
||||
|
||||
</view>
|
||||
<view style="width:50%;display: inline-flex;position: relative;left:10%;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="3rd Room" name="3rd Room"></u-checkbox>
|
||||
</view>
|
||||
</u-checkbox-group>
|
||||
<u-checkbox-group placement="row"
|
||||
:value="waitlistOtherRemarkCheckList"
|
||||
@change="changeWaitlistOtherRemark"
|
||||
<u-checkbox-group placement="row" @change="changeOtherRemark"
|
||||
style="flex-direction: unset;display: block;">
|
||||
<view style="width:50%;display: inline-flex;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="Extend" name="Extend"></u-checkbox>
|
||||
customStyle="height:30px;width:100%;" label="Extend" name="Extend"
|
||||
:value="unqualifiedDateCheckboxStates[currentUnqualifiedIndex] && unqualifiedDateCheckboxStates[currentUnqualifiedIndex].includes('Extend')"></u-checkbox>
|
||||
|
||||
</view>
|
||||
<view style="width:50%;display: inline-flex;position: relative;left:10%;">
|
||||
<u-checkbox activeColor="#C39A4B" labelColor="#333333" shape="circle"
|
||||
customStyle="height:30px;width:100%;" label="Remark" name="Remark"></u-checkbox>
|
||||
customStyle="height:30px;width:100%;" label="Remark" name="Remark"
|
||||
:value="unqualifiedDateCheckboxStates[currentUnqualifiedIndex] && unqualifiedDateCheckboxStates[currentUnqualifiedIndex].includes('Remark')"></u-checkbox>
|
||||
</view>
|
||||
</u-checkbox-group>
|
||||
<view style="width:100%;margin-top:16px;" v-show="showRemark">
|
||||
@@ -427,8 +437,7 @@
|
||||
selectedApprover:'',
|
||||
showRemark: false,
|
||||
showWaitlistModal:false,
|
||||
// Waitlist 弹窗 Extend/Remark(必须与 u-checkbox-group 的 :value 绑定,勿用子项 :value)
|
||||
waitlistOtherRemarkCheckList: [],
|
||||
showRadio:false,
|
||||
unqualifiedDateList: [],
|
||||
currentUnqualifiedIndex: 0,
|
||||
unqualifiedDateRemarks: [],
|
||||
@@ -454,17 +463,6 @@
|
||||
// 數據方法
|
||||
getBooking(){
|
||||
this.bookingData = uni.getStorageSync("bookingData");
|
||||
// 确保 roomRemark 是响应式字段,否则 iOS 上可能出现 u-checkbox 状态未被正确回刷导致“可多选”
|
||||
if (this.bookingData !== null && this.bookingData !== undefined && typeof this.bookingData === 'object') {
|
||||
const hasRoomRemark = Object.prototype.hasOwnProperty.call(this.bookingData, 'roomRemark');
|
||||
if (!hasRoomRemark || this.bookingData.roomRemark === null || this.bookingData.roomRemark === undefined || this.bookingData.roomRemark === 'null') {
|
||||
(this.$set ? this.$set(this.bookingData, 'roomRemark', '') : this.bookingData.roomRemark = '');
|
||||
}
|
||||
const hasOtherRemark = Object.prototype.hasOwnProperty.call(this.bookingData, 'otherRemark');
|
||||
if (!hasOtherRemark || this.bookingData.otherRemark === null || this.bookingData.otherRemark === undefined || this.bookingData.otherRemark === 'null') {
|
||||
(this.$set ? this.$set(this.bookingData, 'otherRemark', '') : this.bookingData.otherRemark = '');
|
||||
}
|
||||
}
|
||||
if(this.bookingData!==null && this.bookingData!==undefined && this.bookingData!==''){
|
||||
this.oldDateList = this.bookingData.dateList;
|
||||
this.checkList = [];
|
||||
@@ -500,7 +498,11 @@
|
||||
this.submitBooking();
|
||||
}
|
||||
},
|
||||
buildUnqualifiedDateLists() {
|
||||
submitApproval() {
|
||||
// 显示审批模态框
|
||||
this.getApprovalReason();
|
||||
this.showApprovalModal = true;
|
||||
this.showModalBtn = true;
|
||||
this.currentUnqualifiedIndex = 0;
|
||||
this.unqualifiedDateList = [];
|
||||
this.unqualifiedDateRemarks = [];
|
||||
@@ -508,27 +510,33 @@
|
||||
this.unqualifiedDateApprovers = [];
|
||||
this.unqualifiedDateOtherRemarks = [];
|
||||
this.unqualifiedDateCheckboxStates = [];
|
||||
if (this.checkList != null && this.checkList.length > 0) {
|
||||
if (this.bookingData.bookType == 1) {
|
||||
for (let i = 0; i < this.bookingData.extendDate.length; i++) {
|
||||
for (let j = 0; j < this.checkList.length; j++) {
|
||||
if (i == this.checkList[j] && this.bookingData.extendDate[i].status == 1) {
|
||||
if(this.checkList!=null && this.checkList.length>0){
|
||||
if(this.bookingData.bookType==1){
|
||||
// 把extendDate中的状态都设置成不够分
|
||||
for(let i=0;i<this.bookingData.extendDate.length;i++){
|
||||
for(let j=0;j<this.checkList.length;j++){
|
||||
if(i == this.checkList[j] && this.bookingData.extendDate[i].status==1){
|
||||
console.log(this.bookingData.extendDate[i]);
|
||||
this.unqualifiedDateList.push(this.bookingData.extendDate[i]);
|
||||
this.unqualifiedDateRemarks.push(this.bookingData.extendDate[i].remark || null);
|
||||
this.unqualifiedDateReasons.push('');
|
||||
// 多选 Approver:为每个 index 初始化为数组
|
||||
this.unqualifiedDateApprovers.push([]);
|
||||
this.unqualifiedDateOtherRemarks.push('');
|
||||
this.unqualifiedDateCheckboxStates.push([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < this.bookingData.dateList.length; i++) {
|
||||
for (let j = 0; j < this.checkList.length; j++) {
|
||||
if (i == this.checkList[j] && this.bookingData.dateList[i].status == 1) {
|
||||
}else{
|
||||
// 把dateList中的状态都设置成不够分
|
||||
for(let i=0;i<this.bookingData.dateList.length;i++){
|
||||
for(let j=0;j<this.checkList.length;j++){
|
||||
if(i == this.checkList[j] && this.bookingData.dateList[i].status==1){
|
||||
// console.log(this.bookingData.dateList[i]);
|
||||
this.unqualifiedDateList.push(this.bookingData.dateList[i]);
|
||||
this.unqualifiedDateRemarks.push(this.bookingData.dateList[i].remark || '');
|
||||
this.unqualifiedDateReasons.push('');
|
||||
// 多选 Approver:为每个 index 初始化为数组
|
||||
this.unqualifiedDateApprovers.push([]);
|
||||
this.unqualifiedDateOtherRemarks.push('');
|
||||
this.unqualifiedDateCheckboxStates.push([]);
|
||||
@@ -536,16 +544,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
},
|
||||
submitApproval() {
|
||||
// 与 Waitlist 共用:必须先填充 unqualifiedDateList,否则 getWaitlistRemark 无法匹配 Extend
|
||||
this.buildUnqualifiedDateLists();
|
||||
// 显示审批模态框
|
||||
this.getApprovalReason();
|
||||
this.showApprovalModal = true;
|
||||
this.showModalBtn = true;
|
||||
},
|
||||
onApprovalChange(value){
|
||||
this.selectedApprover = value;
|
||||
// 多选:value 为数组,需要拼接 approverName
|
||||
@@ -1101,7 +1103,7 @@
|
||||
if (this.bookingData.extendDate[i].status == 1) {
|
||||
|
||||
// remarkText只保存remark输入的内容,不加Extend前缀
|
||||
this.bookingData.extendDate[i].remarkText = this.unqualifiedDateRemarks[unqualifiedIndex] || '';
|
||||
this.bookingData.extendData[i].remarkText = this.unqualifiedDateRemarks[unqualifiedIndex] || '';
|
||||
|
||||
// 添加approvalReason字段
|
||||
this.bookingData.extendDate[i].approvalReason = this.unqualifiedDateReasons[unqualifiedIndex] || null;
|
||||
@@ -1432,64 +1434,40 @@
|
||||
},
|
||||
getWaitlistRemark(type,index){
|
||||
let item = (type==2?this.bookingData.extendDate[index]:this.bookingData.dateList[index]);
|
||||
let unqualifiedIndex = this.unqualifiedDateList.findIndex(uItem => uItem === item);
|
||||
if (unqualifiedIndex === -1 && item.date && item.date.length) {
|
||||
unqualifiedIndex = this.unqualifiedDateList.findIndex((uItem) => {
|
||||
const ud = uItem.date;
|
||||
const id = item.date;
|
||||
return ud && id && ud.length && id.length &&
|
||||
ud[0] === id[0] && ud[ud.length - 1] === id[id.length - 1];
|
||||
});
|
||||
}
|
||||
// 仅一条 Waitlist/Unqualified 时,引用不一致也会导致 findIndex 失败,直接对齐下标 0
|
||||
if (unqualifiedIndex === -1 && this.unqualifiedDateList.length === 1) {
|
||||
unqualifiedIndex = 0;
|
||||
}
|
||||
const checkboxState = unqualifiedIndex !== -1
|
||||
? (this.unqualifiedDateCheckboxStates[unqualifiedIndex] || [])
|
||||
: [];
|
||||
const otherSlot = unqualifiedIndex !== -1
|
||||
? (this.unqualifiedDateOtherRemarks[unqualifiedIndex] || '')
|
||||
: '';
|
||||
const wlTags = this.waitlistOtherRemarkCheckList || [];
|
||||
const globalOther = (this.bookingData && this.bookingData.otherRemark) ? String(this.bookingData.otherRemark) : '';
|
||||
const parseTags = (s) => String(s).split(';').map((x) => x.trim()).filter(Boolean);
|
||||
const hasExtend = checkboxState.includes('Extend') ||
|
||||
parseTags(otherSlot).includes('Extend') ||
|
||||
wlTags.includes('Extend') ||
|
||||
parseTags(globalOther).includes('Extend');
|
||||
let remarkArr = [];
|
||||
let roomRemark = this.bookingData.roomRemark;
|
||||
let otherRemark = this.bookingData.otherRemark;
|
||||
if(roomRemark!=''&&roomRemark!=undefined) remarkArr.push(roomRemark);
|
||||
if(otherRemark!=''&&otherRemark!=undefined) remarkArr.push(otherRemark);
|
||||
|
||||
const roomRemark = this.bookingData.roomRemark;
|
||||
const idxRemark = unqualifiedIndex !== -1 ? this.unqualifiedDateRemarks[unqualifiedIndex] : '';
|
||||
const manualRemark = (idxRemark != null && idxRemark !== '') ? idxRemark : this.freeRemark;
|
||||
const remarkChecked = unqualifiedIndex !== -1 &&
|
||||
(this.unqualifiedDateCheckboxStates[unqualifiedIndex] || []).includes('Remark');
|
||||
|
||||
if (unqualifiedIndex !== -1 && this.unqualifiedDateOtherRemarks[unqualifiedIndex] != null) {
|
||||
this.bookingData.otherRemark = this.unqualifiedDateOtherRemarks[unqualifiedIndex];
|
||||
// 找到对应的unqualifiedDate索引
|
||||
const unqualifiedIndex = this.unqualifiedDateList.findIndex(uItem => uItem === item);
|
||||
let extendStr = '';
|
||||
if (unqualifiedIndex !== -1) {
|
||||
const checkboxState = this.unqualifiedDateCheckboxStates[unqualifiedIndex] || [];
|
||||
if (checkboxState.includes('Extend')) {
|
||||
extendStr = 'Extend';
|
||||
}
|
||||
}
|
||||
|
||||
// 对应 BookingDate 的 remark:勾选 Extend 时放在字符串首位
|
||||
const dateParts = [];
|
||||
if (hasExtend) {
|
||||
dateParts.push('Extend');
|
||||
}
|
||||
if (roomRemark != null && roomRemark !== '' && roomRemark !== undefined) {
|
||||
dateParts.push(roomRemark);
|
||||
}
|
||||
if (item.status == 1 &&
|
||||
item.remarkText != null && item.remarkText !== '' && item.remarkText !== undefined) {
|
||||
dateParts.push(item.remarkText);
|
||||
}
|
||||
if ((remarkChecked || this.showRemark) && manualRemark !== '' && manualRemark != null && item.status == 1) {
|
||||
if (manualRemark !== item.remarkText) dateParts.push(manualRemark);
|
||||
item.remarkText != '' &&
|
||||
item.remarkText != undefined) {
|
||||
if (extendStr) {
|
||||
remarkArr.push(extendStr + '; ' + item.remarkText);
|
||||
} else {
|
||||
remarkArr.push(item.remarkText);
|
||||
}
|
||||
} else if (item.status == 1 && extendStr) {
|
||||
remarkArr.push(extendStr);
|
||||
}
|
||||
|
||||
const dateRemarkJoin = dateParts.join('; ');
|
||||
if (dateRemarkJoin) {
|
||||
this.bookingData.remark = dateRemarkJoin;
|
||||
item.remark = dateRemarkJoin;
|
||||
} else {
|
||||
if(this.showRemark&&this.freeRemark!=''&&item.status==1) remarkArr.push(this.freeRemark);
|
||||
|
||||
if(remarkArr.length>0) {
|
||||
this.bookingData.remark = remarkArr.join('; ');
|
||||
item.remark = remarkArr.join('; ');
|
||||
}else{
|
||||
this.bookingData.remark = "";
|
||||
item.remark = "";
|
||||
}
|
||||
@@ -1585,10 +1563,6 @@
|
||||
},
|
||||
|
||||
showWaitlistPop() {
|
||||
// 关键:直接点「放入 Waitlist」不会经过 submitApproval,必须在此处填充 unqualifiedDateList,
|
||||
// 否则 getWaitlistRemark 里 findIndex 恒为 -1,Extend 永远不会写入 remark
|
||||
this.buildUnqualifiedDateLists();
|
||||
this.waitlistOtherRemarkCheckList = (this.unqualifiedDateCheckboxStates[0] || []).slice();
|
||||
this.showWaitlistModal = true;
|
||||
this.showMsgBox = false;
|
||||
},
|
||||
@@ -1632,27 +1606,17 @@
|
||||
}
|
||||
});
|
||||
},
|
||||
onWaitlistRoomRemarkGroupChange(e) {
|
||||
const raw = Array.isArray(e) ? e : (e && Array.isArray(e.detail) ? e.detail : []);
|
||||
const names = raw.map((x) => (x != null ? String(x) : '')).filter(Boolean);
|
||||
if (!this.bookingData) {
|
||||
return;
|
||||
changeRoomRemark(e,item) {
|
||||
if (e) {
|
||||
if(e==item.roomRemark){
|
||||
item.roomRemark=""
|
||||
item.showRadio = true;
|
||||
setTimeout(()=>{item.showRadio = false;this.$forceUpdate()},1)
|
||||
}else{
|
||||
item.roomRemark=e
|
||||
}
|
||||
}
|
||||
if (!Object.prototype.hasOwnProperty.call(this.bookingData, 'roomRemark')) {
|
||||
this.$set(this.bookingData, 'roomRemark', '');
|
||||
}
|
||||
if (names.length === 0) {
|
||||
this.bookingData.roomRemark = '';
|
||||
return;
|
||||
}
|
||||
if (names.length === 1) {
|
||||
this.bookingData.roomRemark = names[0];
|
||||
return;
|
||||
}
|
||||
// 双选时视为互斥:保留本次切换目标(与原先不同的那一项)
|
||||
const prev = this.bookingData.roomRemark;
|
||||
const next = names.find((n) => n !== prev) || names[names.length - 1];
|
||||
this.bookingData.roomRemark = next;
|
||||
this.$forceUpdate()
|
||||
},
|
||||
// changeOtherRemark(e,item) {
|
||||
// if (e) {
|
||||
@@ -1671,41 +1635,27 @@
|
||||
// this.$forceUpdate()
|
||||
// }
|
||||
// },
|
||||
changeWaitlistOtherRemark(e) {
|
||||
const raw = Array.isArray(e) ? e : (e && Array.isArray(e.detail) ? e.detail : []);
|
||||
const names = raw.map((x) => (x != null ? String(x) : '')).filter(Boolean);
|
||||
this.waitlistOtherRemarkCheckList = names.slice();
|
||||
const extras = names.filter((n) => n !== 'Remark');
|
||||
const str = extras.join('; ');
|
||||
this.showRemark = names.includes('Remark');
|
||||
const n = this.unqualifiedDateCheckboxStates.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
this.$set(this.unqualifiedDateCheckboxStates, i, names.slice());
|
||||
this.$set(this.unqualifiedDateOtherRemarks, i, str);
|
||||
}
|
||||
if (this.bookingData) {
|
||||
this.bookingData.otherRemark = str;
|
||||
}
|
||||
},
|
||||
changeOtherRemark(e) {
|
||||
const raw = Array.isArray(e) ? e : (e && Array.isArray(e.detail) ? e.detail : []);
|
||||
const idx = this.currentUnqualifiedIndex;
|
||||
if (!raw || raw.length === 0) {
|
||||
this.showRemark = false;
|
||||
this.$set(this.unqualifiedDateOtherRemarks, idx, '');
|
||||
this.$set(this.unqualifiedDateCheckboxStates, idx, []);
|
||||
if (this.bookingData) {
|
||||
this.bookingData.otherRemark = '';
|
||||
if (e) {
|
||||
let str = '';
|
||||
let show = false;
|
||||
for (let i = 0; i < e.length; i++) {
|
||||
|
||||
if (e[i] == 'Remark') {
|
||||
show = true;
|
||||
} else {
|
||||
str = e[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
const names = raw.map((x) => (x != null ? String(x) : '')).filter(Boolean);
|
||||
const extras = names.filter((n) => n !== 'Remark');
|
||||
this.showRemark = names.includes('Remark');
|
||||
this.$set(this.unqualifiedDateCheckboxStates, idx, names.slice());
|
||||
this.$set(this.unqualifiedDateOtherRemarks, idx, extras.join('; '));
|
||||
if (this.bookingData) {
|
||||
this.bookingData.otherRemark = extras.join('; ');
|
||||
this.showRemark = show;
|
||||
// 存储到当前索引的otherRemark
|
||||
this.unqualifiedDateOtherRemarks[this.currentUnqualifiedIndex] = str;
|
||||
// 存储checkbox状态
|
||||
this.unqualifiedDateCheckboxStates[this.currentUnqualifiedIndex] = e;
|
||||
} else {
|
||||
this.showRemark = false;
|
||||
this.unqualifiedDateOtherRemarks[this.currentUnqualifiedIndex] = '';
|
||||
this.unqualifiedDateCheckboxStates[this.currentUnqualifiedIndex] = [];
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1721,16 +1671,6 @@
|
||||
},
|
||||
},
|
||||
computed:{
|
||||
waitlistRoomGroupValue() {
|
||||
if (!this.bookingData || !this.bookingData.roomRemark) {
|
||||
return [];
|
||||
}
|
||||
const r = this.bookingData.roomRemark;
|
||||
if (r === '2nd Room' || r === '3rd Room') {
|
||||
return [r];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
getStatusColor(){
|
||||
return function (booking) {
|
||||
let operaStatus = null;
|
||||
|
||||
@@ -14,7 +14,7 @@ class config {
|
||||
|
||||
//this.version = "beta 2.0";
|
||||
//ali ECS
|
||||
// this.internalUrl = 'https://mcrm.willtechmacau.com:9086';
|
||||
// this.internalUrl = 'https://sep.willtechmo.com';
|
||||
|
||||
this.externalUrl = 'https://mp.mixixili.cn';
|
||||
this.debugMode = true;
|
||||
@@ -37,3 +37,4 @@ class config {
|
||||
}
|
||||
}
|
||||
export default config
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
const countryDialCodes = [
|
||||
{ iso2: 'MO', country: 'Macau', code: '+853' },
|
||||
{ iso2: 'CN', country: 'China', code: '+86' },
|
||||
{ iso2: 'HK', country: 'Hong Kong', code: '+852' },
|
||||
{ iso2: 'AF', country: 'Afghanistan', code: '+93' },
|
||||
{ iso2: 'AX', country: 'Aland Islands', code: '+358' },
|
||||
{ iso2: 'AL', country: 'Albania', code: '+355' },
|
||||
{ iso2: 'DZ', country: 'Algeria', code: '+213' },
|
||||
{ iso2: 'AS', country: 'American Samoa', code: '+1' },
|
||||
{ iso2: 'AD', country: 'Andorra', code: '+376' },
|
||||
{ iso2: 'AO', country: 'Angola', code: '+244' },
|
||||
{ iso2: 'AI', country: 'Anguilla', code: '+1' },
|
||||
{ iso2: 'AG', country: 'Antigua and Barbuda', code: '+1' },
|
||||
{ iso2: 'AR', country: 'Argentina', code: '+54' },
|
||||
{ iso2: 'AM', country: 'Armenia', code: '+374' },
|
||||
{ iso2: 'AW', country: 'Aruba', code: '+297' },
|
||||
{ iso2: 'AC', country: 'Ascension Island', code: '+247' },
|
||||
{ iso2: 'AU', country: 'Australia', code: '+61' },
|
||||
{ iso2: 'AT', country: 'Austria', code: '+43' },
|
||||
{ iso2: 'AZ', country: 'Azerbaijan', code: '+994' },
|
||||
{ iso2: 'BS', country: 'Bahamas', code: '+1' },
|
||||
{ iso2: 'BH', country: 'Bahrain', code: '+973' },
|
||||
{ iso2: 'BD', country: 'Bangladesh', code: '+880' },
|
||||
{ iso2: 'BB', country: 'Barbados', code: '+1' },
|
||||
{ iso2: 'BY', country: 'Belarus', code: '+375' },
|
||||
{ iso2: 'BE', country: 'Belgium', code: '+32' },
|
||||
{ iso2: 'BZ', country: 'Belize', code: '+501' },
|
||||
{ iso2: 'BJ', country: 'Benin', code: '+229' },
|
||||
{ iso2: 'BM', country: 'Bermuda', code: '+1' },
|
||||
{ iso2: 'BT', country: 'Bhutan', code: '+975' },
|
||||
{ iso2: 'BO', country: 'Bolivia', code: '+591' },
|
||||
{ iso2: 'BA', country: 'Bosnia and Herzegovina', code: '+387' },
|
||||
{ iso2: 'BW', country: 'Botswana', code: '+267' },
|
||||
{ iso2: 'BR', country: 'Brazil', code: '+55' },
|
||||
{ iso2: 'IO', country: 'British Indian Ocean Territory', code: '+246' },
|
||||
{ iso2: 'VG', country: 'British Virgin Islands', code: '+1' },
|
||||
{ iso2: 'BN', country: 'Brunei', code: '+673' },
|
||||
{ iso2: 'BG', country: 'Bulgaria', code: '+359' },
|
||||
{ iso2: 'BF', country: 'Burkina Faso', code: '+226' },
|
||||
{ iso2: 'BI', country: 'Burundi', code: '+257' },
|
||||
{ iso2: 'KH', country: 'Cambodia', code: '+855' },
|
||||
{ iso2: 'CM', country: 'Cameroon', code: '+237' },
|
||||
{ iso2: 'CA', country: 'Canada', code: '+1' },
|
||||
{ iso2: 'CV', country: 'Cape Verde', code: '+238' },
|
||||
{ iso2: 'BQ', country: 'Caribbean Netherlands', code: '+599' },
|
||||
{ iso2: 'KY', country: 'Cayman Islands', code: '+1' },
|
||||
{ iso2: 'CF', country: 'Central African Republic', code: '+236' },
|
||||
{ iso2: 'TD', country: 'Chad', code: '+235' },
|
||||
{ iso2: 'CL', country: 'Chile', code: '+56' },
|
||||
{ iso2: 'CX', country: 'Christmas Island', code: '+61' },
|
||||
{ iso2: 'CC', country: 'Cocos (Keeling) Islands', code: '+61' },
|
||||
{ iso2: 'CO', country: 'Colombia', code: '+57' },
|
||||
{ iso2: 'KM', country: 'Comoros', code: '+269' },
|
||||
{ iso2: 'CG', country: 'Congo - Brazzaville', code: '+242' },
|
||||
{ iso2: 'CD', country: 'Congo - Kinshasa', code: '+243' },
|
||||
{ iso2: 'CK', country: 'Cook Islands', code: '+682' },
|
||||
{ iso2: 'CR', country: 'Costa Rica', code: '+506' },
|
||||
{ iso2: 'CI', country: 'Cote d\'Ivoire', code: '+225' },
|
||||
{ iso2: 'HR', country: 'Croatia', code: '+385' },
|
||||
{ iso2: 'CU', country: 'Cuba', code: '+53' },
|
||||
{ iso2: 'CW', country: 'Curacao', code: '+599' },
|
||||
{ iso2: 'CY', country: 'Cyprus', code: '+357' },
|
||||
{ iso2: 'CZ', country: 'Czechia', code: '+420' },
|
||||
{ iso2: 'DK', country: 'Denmark', code: '+45' },
|
||||
{ iso2: 'DJ', country: 'Djibouti', code: '+253' },
|
||||
{ iso2: 'DM', country: 'Dominica', code: '+1' },
|
||||
{ iso2: 'DO', country: 'Dominican Republic', code: '+1' },
|
||||
{ iso2: 'EC', country: 'Ecuador', code: '+593' },
|
||||
{ iso2: 'EG', country: 'Egypt', code: '+20' },
|
||||
{ iso2: 'SV', country: 'El Salvador', code: '+503' },
|
||||
{ iso2: 'GQ', country: 'Equatorial Guinea', code: '+240' },
|
||||
{ iso2: 'ER', country: 'Eritrea', code: '+291' },
|
||||
{ iso2: 'EE', country: 'Estonia', code: '+372' },
|
||||
{ iso2: 'SZ', country: 'Eswatini', code: '+268' },
|
||||
{ iso2: 'ET', country: 'Ethiopia', code: '+251' },
|
||||
{ iso2: 'FK', country: 'Falkland Islands', code: '+500' },
|
||||
{ iso2: 'FO', country: 'Faroe Islands', code: '+298' },
|
||||
{ iso2: 'FJ', country: 'Fiji', code: '+679' },
|
||||
{ iso2: 'FI', country: 'Finland', code: '+358' },
|
||||
{ iso2: 'FR', country: 'France', code: '+33' },
|
||||
{ iso2: 'GF', country: 'French Guiana', code: '+594' },
|
||||
{ iso2: 'PF', country: 'French Polynesia', code: '+689' },
|
||||
{ iso2: 'GA', country: 'Gabon', code: '+241' },
|
||||
{ iso2: 'GM', country: 'Gambia', code: '+220' },
|
||||
{ iso2: 'GE', country: 'Georgia', code: '+995' },
|
||||
{ iso2: 'DE', country: 'Germany', code: '+49' },
|
||||
{ iso2: 'GH', country: 'Ghana', code: '+233' },
|
||||
{ iso2: 'GI', country: 'Gibraltar', code: '+350' },
|
||||
{ iso2: 'GR', country: 'Greece', code: '+30' },
|
||||
{ iso2: 'GL', country: 'Greenland', code: '+299' },
|
||||
{ iso2: 'GD', country: 'Grenada', code: '+1' },
|
||||
{ iso2: 'GP', country: 'Guadeloupe', code: '+590' },
|
||||
{ iso2: 'GU', country: 'Guam', code: '+1' },
|
||||
{ iso2: 'GT', country: 'Guatemala', code: '+502' },
|
||||
{ iso2: 'GG', country: 'Guernsey', code: '+44' },
|
||||
{ iso2: 'GN', country: 'Guinea', code: '+224' },
|
||||
{ iso2: 'GW', country: 'Guinea-Bissau', code: '+245' },
|
||||
{ iso2: 'GY', country: 'Guyana', code: '+592' },
|
||||
{ iso2: 'HT', country: 'Haiti', code: '+509' },
|
||||
{ iso2: 'HN', country: 'Honduras', code: '+504' },
|
||||
{ iso2: 'HU', country: 'Hungary', code: '+36' },
|
||||
{ iso2: 'IS', country: 'Iceland', code: '+354' },
|
||||
{ iso2: 'IN', country: 'India', code: '+91' },
|
||||
{ iso2: 'ID', country: 'Indonesia', code: '+62' },
|
||||
{ iso2: 'IR', country: 'Iran', code: '+98' },
|
||||
{ iso2: 'IQ', country: 'Iraq', code: '+964' },
|
||||
{ iso2: 'IE', country: 'Ireland', code: '+353' },
|
||||
{ iso2: 'IM', country: 'Isle of Man', code: '+44' },
|
||||
{ iso2: 'IL', country: 'Israel', code: '+972' },
|
||||
{ iso2: 'IT', country: 'Italy', code: '+39' },
|
||||
{ iso2: 'JM', country: 'Jamaica', code: '+1' },
|
||||
{ iso2: 'JP', country: 'Japan', code: '+81' },
|
||||
{ iso2: 'JE', country: 'Jersey', code: '+44' },
|
||||
{ iso2: 'JO', country: 'Jordan', code: '+962' },
|
||||
{ iso2: 'KZ', country: 'Kazakhstan', code: '+7' },
|
||||
{ iso2: 'KE', country: 'Kenya', code: '+254' },
|
||||
{ iso2: 'KI', country: 'Kiribati', code: '+686' },
|
||||
{ iso2: 'XK', country: 'Kosovo', code: '+383' },
|
||||
{ iso2: 'KW', country: 'Kuwait', code: '+965' },
|
||||
{ iso2: 'KG', country: 'Kyrgyzstan', code: '+996' },
|
||||
{ iso2: 'LA', country: 'Laos', code: '+856' },
|
||||
{ iso2: 'LV', country: 'Latvia', code: '+371' },
|
||||
{ iso2: 'LB', country: 'Lebanon', code: '+961' },
|
||||
{ iso2: 'LS', country: 'Lesotho', code: '+266' },
|
||||
{ iso2: 'LR', country: 'Liberia', code: '+231' },
|
||||
{ iso2: 'LY', country: 'Libya', code: '+218' },
|
||||
{ iso2: 'LI', country: 'Liechtenstein', code: '+423' },
|
||||
{ iso2: 'LT', country: 'Lithuania', code: '+370' },
|
||||
{ iso2: 'LU', country: 'Luxembourg', code: '+352' },
|
||||
{ iso2: 'MG', country: 'Madagascar', code: '+261' },
|
||||
{ iso2: 'MW', country: 'Malawi', code: '+265' },
|
||||
{ iso2: 'MY', country: 'Malaysia', code: '+60' },
|
||||
{ iso2: 'MV', country: 'Maldives', code: '+960' },
|
||||
{ iso2: 'ML', country: 'Mali', code: '+223' },
|
||||
{ iso2: 'MT', country: 'Malta', code: '+356' },
|
||||
{ iso2: 'MH', country: 'Marshall Islands', code: '+692' },
|
||||
{ iso2: 'MQ', country: 'Martinique', code: '+596' },
|
||||
{ iso2: 'MR', country: 'Mauritania', code: '+222' },
|
||||
{ iso2: 'MU', country: 'Mauritius', code: '+230' },
|
||||
{ iso2: 'YT', country: 'Mayotte', code: '+262' },
|
||||
{ iso2: 'MX', country: 'Mexico', code: '+52' },
|
||||
{ iso2: 'FM', country: 'Micronesia', code: '+691' },
|
||||
{ iso2: 'MD', country: 'Moldova', code: '+373' },
|
||||
{ iso2: 'MC', country: 'Monaco', code: '+377' },
|
||||
{ iso2: 'MN', country: 'Mongolia', code: '+976' },
|
||||
{ iso2: 'ME', country: 'Montenegro', code: '+382' },
|
||||
{ iso2: 'MS', country: 'Montserrat', code: '+1' },
|
||||
{ iso2: 'MA', country: 'Morocco', code: '+212' },
|
||||
{ iso2: 'MZ', country: 'Mozambique', code: '+258' },
|
||||
{ iso2: 'MM', country: 'Myanmar (Burma)', code: '+95' },
|
||||
{ iso2: 'NA', country: 'Namibia', code: '+264' },
|
||||
{ iso2: 'NR', country: 'Nauru', code: '+674' },
|
||||
{ iso2: 'NP', country: 'Nepal', code: '+977' },
|
||||
{ iso2: 'NL', country: 'Netherlands', code: '+31' },
|
||||
{ iso2: 'NC', country: 'New Caledonia', code: '+687' },
|
||||
{ iso2: 'NZ', country: 'New Zealand', code: '+64' },
|
||||
{ iso2: 'NI', country: 'Nicaragua', code: '+505' },
|
||||
{ iso2: 'NE', country: 'Niger', code: '+227' },
|
||||
{ iso2: 'NG', country: 'Nigeria', code: '+234' },
|
||||
{ iso2: 'NU', country: 'Niue', code: '+683' },
|
||||
{ iso2: 'NF', country: 'Norfolk Island', code: '+672' },
|
||||
{ iso2: 'KP', country: 'North Korea', code: '+850' },
|
||||
{ iso2: 'MK', country: 'North Macedonia', code: '+389' },
|
||||
{ iso2: 'MP', country: 'Northern Mariana Islands', code: '+1' },
|
||||
{ iso2: 'NO', country: 'Norway', code: '+47' },
|
||||
{ iso2: 'OM', country: 'Oman', code: '+968' },
|
||||
{ iso2: 'PK', country: 'Pakistan', code: '+92' },
|
||||
{ iso2: 'PW', country: 'Palau', code: '+680' },
|
||||
{ iso2: 'PS', country: 'Palestinian Territories', code: '+970' },
|
||||
{ iso2: 'PA', country: 'Panama', code: '+507' },
|
||||
{ iso2: 'PG', country: 'Papua New Guinea', code: '+675' },
|
||||
{ iso2: 'PY', country: 'Paraguay', code: '+595' },
|
||||
{ iso2: 'PE', country: 'Peru', code: '+51' },
|
||||
{ iso2: 'PH', country: 'Philippines', code: '+63' },
|
||||
{ iso2: 'PL', country: 'Poland', code: '+48' },
|
||||
{ iso2: 'PT', country: 'Portugal', code: '+351' },
|
||||
{ iso2: 'PR', country: 'Puerto Rico', code: '+1' },
|
||||
{ iso2: 'QA', country: 'Qatar', code: '+974' },
|
||||
{ iso2: 'RE', country: 'Reunion', code: '+262' },
|
||||
{ iso2: 'RO', country: 'Romania', code: '+40' },
|
||||
{ iso2: 'RU', country: 'Russia', code: '+7' },
|
||||
{ iso2: 'RW', country: 'Rwanda', code: '+250' },
|
||||
{ iso2: 'WS', country: 'Samoa', code: '+685' },
|
||||
{ iso2: 'SM', country: 'San Marino', code: '+378' },
|
||||
{ iso2: 'ST', country: 'Sao Tome and Principe', code: '+239' },
|
||||
{ iso2: 'SA', country: 'Saudi Arabia', code: '+966' },
|
||||
{ iso2: 'SN', country: 'Senegal', code: '+221' },
|
||||
{ iso2: 'RS', country: 'Serbia', code: '+381' },
|
||||
{ iso2: 'SC', country: 'Seychelles', code: '+248' },
|
||||
{ iso2: 'SL', country: 'Sierra Leone', code: '+232' },
|
||||
{ iso2: 'SG', country: 'Singapore', code: '+65' },
|
||||
{ iso2: 'SX', country: 'Sint Maarten', code: '+1' },
|
||||
{ iso2: 'SK', country: 'Slovakia', code: '+421' },
|
||||
{ iso2: 'SI', country: 'Slovenia', code: '+386' },
|
||||
{ iso2: 'SB', country: 'Solomon Islands', code: '+677' },
|
||||
{ iso2: 'SO', country: 'Somalia', code: '+252' },
|
||||
{ iso2: 'ZA', country: 'South Africa', code: '+27' },
|
||||
{ iso2: 'KR', country: 'South Korea', code: '+82' },
|
||||
{ iso2: 'SS', country: 'South Sudan', code: '+211' },
|
||||
{ iso2: 'ES', country: 'Spain', code: '+34' },
|
||||
{ iso2: 'LK', country: 'Sri Lanka', code: '+94' },
|
||||
{ iso2: 'BL', country: 'St. Barthelemy', code: '+590' },
|
||||
{ iso2: 'SH', country: 'St. Helena', code: '+290' },
|
||||
{ iso2: 'KN', country: 'St. Kitts and Nevis', code: '+1' },
|
||||
{ iso2: 'LC', country: 'St. Lucia', code: '+1' },
|
||||
{ iso2: 'MF', country: 'St. Martin', code: '+590' },
|
||||
{ iso2: 'PM', country: 'St. Pierre and Miquelon', code: '+508' },
|
||||
{ iso2: 'VC', country: 'St. Vincent and Grenadines', code: '+1' },
|
||||
{ iso2: 'SD', country: 'Sudan', code: '+249' },
|
||||
{ iso2: 'SR', country: 'Suriname', code: '+597' },
|
||||
{ iso2: 'SJ', country: 'Svalbard and Jan Mayen', code: '+47' },
|
||||
{ iso2: 'SE', country: 'Sweden', code: '+46' },
|
||||
{ iso2: 'CH', country: 'Switzerland', code: '+41' },
|
||||
{ iso2: 'SY', country: 'Syria', code: '+963' },
|
||||
{ iso2: 'TW', country: 'Taiwan', code: '+886' },
|
||||
{ iso2: 'TJ', country: 'Tajikistan', code: '+992' },
|
||||
{ iso2: 'TZ', country: 'Tanzania', code: '+255' },
|
||||
{ iso2: 'TH', country: 'Thailand', code: '+66' },
|
||||
{ iso2: 'TL', country: 'Timor-Leste', code: '+670' },
|
||||
{ iso2: 'TG', country: 'Togo', code: '+228' },
|
||||
{ iso2: 'TK', country: 'Tokelau', code: '+690' },
|
||||
{ iso2: 'TO', country: 'Tonga', code: '+676' },
|
||||
{ iso2: 'TT', country: 'Trinidad and Tobago', code: '+1' },
|
||||
{ iso2: 'TA', country: 'Tristan da Cunha', code: '+290' },
|
||||
{ iso2: 'TN', country: 'Tunisia', code: '+216' },
|
||||
{ iso2: 'TR', country: 'Turkiye', code: '+90' },
|
||||
{ iso2: 'TM', country: 'Turkmenistan', code: '+993' },
|
||||
{ iso2: 'TC', country: 'Turks and Caicos Islands', code: '+1' },
|
||||
{ iso2: 'TV', country: 'Tuvalu', code: '+688' },
|
||||
{ iso2: 'VI', country: 'U.S. Virgin Islands', code: '+1' },
|
||||
{ iso2: 'UG', country: 'Uganda', code: '+256' },
|
||||
{ iso2: 'UA', country: 'Ukraine', code: '+380' },
|
||||
{ iso2: 'AE', country: 'United Arab Emirates', code: '+971' },
|
||||
{ iso2: 'GB', country: 'United Kingdom', code: '+44' },
|
||||
{ iso2: 'US', country: 'United States', code: '+1' },
|
||||
{ iso2: 'UY', country: 'Uruguay', code: '+598' },
|
||||
{ iso2: 'UZ', country: 'Uzbekistan', code: '+998' },
|
||||
{ iso2: 'VU', country: 'Vanuatu', code: '+678' },
|
||||
{ iso2: 'VA', country: 'Vatican City', code: '+39' },
|
||||
{ iso2: 'VE', country: 'Venezuela', code: '+58' },
|
||||
{ iso2: 'VN', country: 'Vietnam', code: '+84' },
|
||||
{ iso2: 'WF', country: 'Wallis and Futuna', code: '+681' },
|
||||
{ iso2: 'EH', country: 'Western Sahara', code: '+212' },
|
||||
{ iso2: 'YE', country: 'Yemen', code: '+967' },
|
||||
{ iso2: 'ZM', country: 'Zambia', code: '+260' },
|
||||
{ iso2: 'ZW', country: 'Zimbabwe', code: '+263' },
|
||||
];
|
||||
|
||||
export function getCountryDialCodeOptions() {
|
||||
return countryDialCodes.map(item => ({
|
||||
...item,
|
||||
label: item.code,
|
||||
value: item.code,
|
||||
}));
|
||||
}
|
||||
|
||||
export default countryDialCodes;
|
||||
@@ -121,10 +121,8 @@ module.exports = (vm) => {
|
||||
break;
|
||||
case 400:
|
||||
kickout()
|
||||
break;
|
||||
case 401:
|
||||
if(error.config.url.indexOf('refresh_token')==-1 && error.config.url.indexOf('logout')==-1 && !error.config.custom?.tokenRetried){
|
||||
error.config.custom = {...error.config.custom, tokenRetried: true};
|
||||
if(error.config.url.indexOf('refresh_token')==-1 && error.config.url.indexOf('logout')==-1){
|
||||
return tokenRefresh().then(_ => {
|
||||
error.config.header.Authorization = uni.getStorageSync("token");
|
||||
error.config.header.RefreshToken = uni.getStorageSync("refreshToken")
|
||||
@@ -143,22 +141,19 @@ module.exports = (vm) => {
|
||||
|
||||
}
|
||||
function tokenRefresh(){
|
||||
const storedRefreshToken = uni.getStorageSync("refreshToken");
|
||||
if (storedRefreshToken) {
|
||||
let oldToken = uni.getStorageSync("token");
|
||||
if (oldToken !== null && oldToken !== '') {
|
||||
return refreshToken({})
|
||||
.then((data) => {
|
||||
if (!data?.success || !data.accessToken) throw new Error('Token refresh failed');
|
||||
uni.setStorageSync("token",data.accessToken);
|
||||
uni.setStorageSync("tokenTime",dayjs().unix());
|
||||
return Promise.resolve(true)
|
||||
})
|
||||
.catch(error => {
|
||||
kickout()
|
||||
return Promise.reject(error);
|
||||
})
|
||||
} else {
|
||||
kickout()
|
||||
return Promise.reject(new Error('Missing RefreshToken'));
|
||||
}
|
||||
}
|
||||
function checkToken(){
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
bgColor="#C39A4B"
|
||||
titleStyle="max-width:none;width:auto;font-weight:bold;color:#ffffff;"
|
||||
>
|
||||
<view
|
||||
@tap="goNotification"
|
||||
style="margin-top:2px;margin-left:3px;"
|
||||
slot="left"
|
||||
>
|
||||
<u-icon name="bell" color="#FFFFFF" size="24"></u-icon>
|
||||
</view>
|
||||
<view @tap="logout"
|
||||
style="margin-top:2px;margin-right:3px;"
|
||||
slot="right"
|
||||
@@ -39,6 +46,11 @@
|
||||
this.isLogin();
|
||||
},
|
||||
methods:{
|
||||
goNotification() {
|
||||
uni.navigateTo({
|
||||
url: '/limo/notification/notification'
|
||||
});
|
||||
},
|
||||
updateUserData() {
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
if (this.userData) {
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -232,9 +232,9 @@
|
||||
"bookingDetail.failed":" Failed",
|
||||
"bookingDetail.confirmApprove":"Are you sure to approve booking?",
|
||||
"bookingDetail.confirmReject":"Are you sure to reject booking?",
|
||||
"bookingDetail.changeMiscChargeSuccess":"Change Misc Charge Success",
|
||||
"bookingDetail.changeMisChargeSuccess":"Change MisCharge Success",
|
||||
"bookingDetail.miscChargeLess":"Amount cannot be less than original.",
|
||||
"bookingDetail.changeMiscChargeFail":"Change Misc Charge Fail",
|
||||
"bookingDetail.changeMisChargeFail":"Change MisCharge Fail",
|
||||
"multipleDate.title":"Multiple Date",
|
||||
"multipleDate.addDate":"ADD DATE",
|
||||
"multipleDate.pleaseAddDate":"Please Add Date",
|
||||
@@ -295,7 +295,7 @@
|
||||
"hotel.title":"Room",
|
||||
"reservations.title":"Reservations",
|
||||
"approval.title":"Approval",
|
||||
"hotel.roombooking":"Room Booking",
|
||||
"hotel.roombooking":"Limo & Room Booking",
|
||||
"approval.pendingApproval":"Pending Approval",
|
||||
"approval.allRequest":"All Request",
|
||||
"approval.searchStr":"Search",
|
||||
@@ -319,5 +319,26 @@
|
||||
"notification.pendingApproval":"Pending Approval",
|
||||
"notification.pendingApprovalRequest": "Pending Approval Request",
|
||||
"playerDetail.confirm":"CONFIRM",
|
||||
"newBooking.validEta":"The ETA time format is incorrect. Please re-enter it, eg: HH:mm"
|
||||
"newBooking.validEta":"The ETA time format is incorrect. Please re-enter it, eg: HH:mm",
|
||||
"notification.title":"Notification",
|
||||
"approvalRouting.title":"Approval Routing",
|
||||
"limoBookingRecord.bookingType":"Booking Type",
|
||||
"limoBookingRecord.pickupDatetime":"Pick up Datetime",
|
||||
"limoBookingRecord.pickup":"Pick up",
|
||||
"limoBookingRecord.dropoff":"Drop off",
|
||||
"limoBookingRecord.extraDropoff":"Extra Drop off",
|
||||
"limoBookingDetail.carTypeAndPlate":"Car Type and Plate",
|
||||
"limoBookingDetail.overrideBy":"Override By",
|
||||
"limoBookingDetail.tripPrice":"Trip Price",
|
||||
"limoBookingDetail.driverSource":"Driver Source",
|
||||
"limoBookingDetail.remark":"Remark",
|
||||
"limoBookingDetail.driverContact":"Driver Contact",
|
||||
"limoBookingDetail.pickupPoint":"Pick up point",
|
||||
"limoBookingDetail.extraDropoff":"Extra Drop-off",
|
||||
"limoBookingDetail.dropoffPoint":"Drop off point",
|
||||
"limoBookingDetail.flightNo":"Flight No",
|
||||
"limoBookingDetail.greetType":"Greet Type",
|
||||
"limoBookingCopy.carType":"Car Type",
|
||||
"limoBookingCopy.carNo":"Car No",
|
||||
"limoBookingCopy.driverContact":"Driver Contact"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"common.appName": "MOBILE CRM APP",
|
||||
"common.userLogin": "用戶登入",
|
||||
"common.loginsso": "登入",
|
||||
@@ -13,7 +13,7 @@
|
||||
"common.room": "間",
|
||||
"common.rooms": "間",
|
||||
"common.bookingType": "預訂類型",
|
||||
"common.misCharge":"雜項費用",
|
||||
"common.misCharge": "雜項費用",
|
||||
"common.checkInDate": "入住日期",
|
||||
"common.checkOutDate": "退房日期",
|
||||
"common.roomType": "房型",
|
||||
@@ -29,12 +29,11 @@
|
||||
"common.confirm": "確認",
|
||||
"common.in": "入住",
|
||||
"common.out": "離開",
|
||||
"common.start":"開始",
|
||||
"common.start": "開始",
|
||||
"common.selected": "已選擇",
|
||||
"common.userLocked":"這個用戶賬戶已鎖定",
|
||||
"common.ipLocked":"這個IP已鎖定",
|
||||
"common.end":"終止",
|
||||
"common.rangeError":"日期範圍不正確",
|
||||
"common.userLocked": "這個用戶賬戶已鎖定",
|
||||
"common.end": "終止",
|
||||
"common.rangeError": "日期範圍不正確",
|
||||
"common.removeConfirm": "確認要刪除嗎?",
|
||||
"common.warning": "系統提示",
|
||||
"common.login": "登入",
|
||||
@@ -45,8 +44,9 @@
|
||||
"common.alterSharerExist": "該客人已添加",
|
||||
"common.alterSharerLimit": "同住人限制",
|
||||
"common.errorMsg": "錯誤信息",
|
||||
"common.misCharge":"雜項費用",
|
||||
"common.goBack": "返回",
|
||||
"common.back":"返回",
|
||||
"common.back": "返回",
|
||||
"common.language": "語言",
|
||||
"common.version": "版本",
|
||||
"common.user": "用戶",
|
||||
@@ -58,23 +58,23 @@
|
||||
"common.search": "查詢",
|
||||
"common.status": "狀態",
|
||||
"common.inputRemark": "請輸入備註",
|
||||
"common.nextBooking":"下一個預訂",
|
||||
"common.nextBooking": "下一個預訂",
|
||||
"common.to": "到",
|
||||
"common.close":"關閉",
|
||||
"common.save":"保存",
|
||||
"common.close": "關閉",
|
||||
"common.save": "保存",
|
||||
"common.inputUserNameAndPassword": "請輸入用戶名和密碼",
|
||||
"common.loginerror":"用戶名或密碼錯誤",
|
||||
"common.mfaerror":"登入失敗",
|
||||
"common.loginfail":"登入失敗",
|
||||
"common.connected":"已連接",
|
||||
"common.disconnected":"連接失敗",
|
||||
"common.submit":"遞交",
|
||||
"common.noPermission":"您沒有權限查看",
|
||||
"common.rangeTip":"日期范围无效",
|
||||
"common.jailBreakTitle":"禁止使用",
|
||||
"common.jailBreakMessage":"禁止越獄過的設備使用該APP",
|
||||
"common.noRecord":"沒有記錄",
|
||||
"common.etaTime":"預計時間",
|
||||
"common.loginerror": "用戶名或密碼錯誤",
|
||||
"common.mfaerror": "登入失敗",
|
||||
"common.loginfail": "登入失敗",
|
||||
"common.connected": "已連接",
|
||||
"common.disconnected": "連接失敗",
|
||||
"common.submit": "遞交",
|
||||
"common.noPermission": "您沒有權限查看",
|
||||
"common.rangeTip": "日期范围无效",
|
||||
"common.jailBreakTitle": "禁止使用",
|
||||
"common.jailBreakMessage": "禁止越獄過的設備使用該APP",
|
||||
"common.noRecord": "沒有記錄",
|
||||
"common.etaTime": "預計時間",
|
||||
"calendar.mon": "一",
|
||||
"calendar.tue": "二",
|
||||
"calendar.wed": "三",
|
||||
@@ -91,6 +91,8 @@
|
||||
"findPlayer.noPermission": "您沒有權限查看此客人.",
|
||||
"bookingRecord.title": "預定記錄",
|
||||
"bookingRecord.newsBooking": "預訂房間 / 候補名單",
|
||||
"bookingRecord.newLimo": "預訂車輛",
|
||||
"bookingRecord.calendar": "CALENDAR",
|
||||
"bookingRecord.extend": "續房",
|
||||
"bookingRecord.group": "關聯",
|
||||
"bookingRecord.sharer": "同住人",
|
||||
@@ -116,153 +118,12 @@
|
||||
"newBooking.alertBookingType": "必須選擇預訂類型",
|
||||
"newBooking.extension": "續房",
|
||||
"newBooking.preference": "注意:特殊需求均無法保證,須視乎實際状況安排",
|
||||
"newBooking.deposit":"押金",
|
||||
"newBooking.postCharge":"房賬",
|
||||
"newBooking.waiveDeposit":"免收押金",
|
||||
"newBooking.collectDeposit":"收取押金",
|
||||
"newBooking.yesPost":"掛房賬",
|
||||
"newBooking.noPost":"鎖房賬",
|
||||
"bookingConfirm.title": "預覽 & 確認",
|
||||
"bookingConfirm.submitBooking": "遞交預定",
|
||||
"bookingConfirm.createdOn": "預訂日期",
|
||||
"bookingConfirm.createdBy": "預訂者",
|
||||
"bookingConfirm.viewBooking": "預定詳情",
|
||||
"bookingConfirm.urgentApproval":"緊急審批請求",
|
||||
"bookingConfirm.submitApproval":"提交審批人",
|
||||
"bookingConfirm.alert10": "正在處理客人 ",
|
||||
"bookingConfirm.alert1": "預訂正在處理中",
|
||||
"bookingConfirm.alert1_1":" 的候補名單!",
|
||||
"bookingConfirm.alert2": " 的預定!",
|
||||
"bookingConfirm.alert3": "您的預定未能通過!",
|
||||
"bookingConfirm.alert4": "需放在候補名單",
|
||||
"bookingConfirm.alert5": "部分預定未能通過!",
|
||||
"bookingConfirm.IMAlert1":"請聯繫MSC預訂房間",
|
||||
"bookingConfirm.IMAlert2":"選擇的日期需放在候補名單, 請申請批准預訂房間",
|
||||
"bookingConfirm.putInWaitlist": "放入候補名單",
|
||||
"bookingConfirm.currentStay": "當前入住",
|
||||
"bookingConfirm.extending": "延長入住",
|
||||
"bookingConfirm.extensionEmail": "MSC正在處理續房",
|
||||
"bookingConfirm.extensionProccessing": "續房正在處理中",
|
||||
"bookingConfirm.addSharer": "新增",
|
||||
"bookingConfirm.canNotAddSharer": "不能新增同住人",
|
||||
"bookingConfirm.confirmBooking": "確認預定",
|
||||
"bookingConfirm.backToRecords": "返回主頁",
|
||||
"bookingConfirm.viewProceedBooking": "查看並繼續",
|
||||
"bookingConfirm.wantToWaitList": "是否放入候補名單?",
|
||||
"bookingConfirm.secondRoom1":"超過可預訂房間數量",
|
||||
"bookingConfirm.secondRoom2":"其中一晚已超過可預訂房間數量",
|
||||
"bookingConfirm.secondRoom3":"已預訂套房或以上房型",
|
||||
"bookingConfirm.secondRoom4":"只可預訂基本房型",
|
||||
"bookingConfirm.duplicateWaitlist":"已提交候補名單",
|
||||
"bookingConfirm.remark":"候補名單備註",
|
||||
"bookingConfirm.numOfRoom":"請求房間數量",
|
||||
"bookingConfirm.requestReason":"請求原因",
|
||||
"bookingConfirm.routeToApprover":"發送至審批員",
|
||||
"bookingConfirm.approvalRoutingRemark":"審批備注",
|
||||
"bookingDetail.title": "預定詳情",
|
||||
"bookingDetail.pendingAlert": "預定正在處理中!",
|
||||
"bookingDetail.waitlistAlert": "預定已列入候補名單!",
|
||||
"bookingDetail.confirmationNo": "預訂編號",
|
||||
"bookingDetail.saveImage": "保存圖片",
|
||||
"bookingDetail.extension": "續房",
|
||||
"bookingDetail.cancelSuccessful": "取消成功",
|
||||
"bookingDetail.cancelFailed": "取消失敗",
|
||||
"bookingDetail.confirmCancel": "你確定要取消預定嗎?",
|
||||
"bookingDetail.statusChange": "預定狀態已改變",
|
||||
"bookingDetail.approve":"審批",
|
||||
"bookingDetail.reject":"拒絕",
|
||||
"bookingDetail.changeMiscChargeSuccess":"修改雜項費用成功",
|
||||
"bookingDetail.changeMiscChargeFail":"修改雜項費用失敗",
|
||||
"bookingDetail.cancelTimeErr":"當前時間段不能取消預定",
|
||||
"bookingDetail.successfully":"成功",
|
||||
"bookingDetail.failed":"失敗",
|
||||
"bookingDetail.toCancelBooking": "確定要取消預訂嗎?",
|
||||
"bookingDetail.backToBooking": "返回預訂",
|
||||
"bookingDetail.backToDetail": "返回詳情",
|
||||
"bookingDetail.SelectDate": "選擇預訂日期",
|
||||
"bookingDetail.confirmApprove": "確定要批准此預訂嗎?",
|
||||
"bookingDetail.confirmReject": "確定要拒絕此預訂嗎?",
|
||||
"bookingDetail.errorDate":"必須選擇連續的日期!",
|
||||
"bookingDetail.cancelBooking":"取消預定",
|
||||
"bookingDetail.ETA":"預計時間",
|
||||
"bookingDetail.miscChargeLess":"金額不可低於原值.",
|
||||
"bookingDetail.cannotCancel":"不能取消这条记录",
|
||||
"multipleDate.title": "選擇多個日期",
|
||||
"multipleDate.addDate": "新增日期",
|
||||
"multipleDate.pleaseAddDate": "請新增日期",
|
||||
"multipleDate.reachMaxBookNum": "已達最大多個日期預定",
|
||||
"submitBooking.title": "遞交",
|
||||
"submitBooking.alert1": "TPD的狀態發生了改變,請重新選擇",
|
||||
"submitBooking.submitedSuccessful": "遞交成功",
|
||||
"submitBooking.roomCriteriaNotQualified":"不符合訂房條件",
|
||||
"submitBooking.underWaitlist":"放入候補名單",
|
||||
"submitBooking.copyRemark":"複製備註",
|
||||
"putInWaitlist.title": "候補名單",
|
||||
"newWaitlist.title": "创建候補名單",
|
||||
"newWaitlist.remark": "備註",
|
||||
"newWaitlist.submitWaitlist": "遞交候補名單",
|
||||
"newWaitlist.savesuccessful": "成功遞交候補名單!",
|
||||
"newWaitlist.viewSubmitedWaitlist": "查看候補名單",
|
||||
"setting.title": "設定",
|
||||
"region.title":"地區限制",
|
||||
"region.showMessage":"此應用程序僅限於澳門使用。",
|
||||
"region.reson":"禁用原因",
|
||||
"region.resonMsgNotInMacau":"您的定位不在澳門",
|
||||
"region.resonMsgOpenVPN":"您打開了VPN",
|
||||
"region.resonMsgNotInMacauOpenVpn":"您的定位不在澳門且打開了VPN",
|
||||
"region.resonMsglocationErr":"檢查定位時出錯",
|
||||
"region.resonMsgVPNErr":"檢查VPN時出錯",
|
||||
"region.resonMsgFunctionErr":"檢查定位和VPN時出錯",
|
||||
"region.retry":"重試",
|
||||
"region.commitTitle":"用戶使用協議及聲明",
|
||||
"region.commitment1":"本人在此承諾遵守所有適用於使用 Mobile CRM (以下簡稱MCRM) 的公司政策及法定義務。尤其,本人所在地不在澳門特別行政區時,本人同意不使用具有博彩數據的MCRM功能。此外,本人承諾不允許任何其他人(無論是否為澳門美高梅員工)使用安裝在本人移動裝置上的MCRM或存取其中的數據。本人亦承諾不將MCRM上的任何信息分享至其他個人設備。本人知悉此類行為將受到法律的刑事處分,並嚴重違反本人合同規定的責任義務。",
|
||||
"region.commitment2":"I hereby undertake to adhere to all Company’s policies and all legal obligations that are applicable to the usage of Mobile CRM (hereinafter called MCRM). In particular, I agree not to use MCRM functionality with gaming data whenever my location is outside of the Macau SAR. I further undertake not to allow anybody else, whether an MGM employee or not, to use MCRM on my mobile phone or to access the data therein. I also undertake not to share any of the information on MCRM to any other personal devices. I’m aware that such actions are criminally punished by law and constitute a serious breach of my contractual obligations.",
|
||||
"region.resonMsgNotInMacauIP":"您的IP不在澳門",
|
||||
"dashboard.title":"主頁",
|
||||
"dashboard.dataAsOf":"數據更新於:",
|
||||
"dashboard.achievement":"成就",
|
||||
"dashboard.kpi":"指標",
|
||||
"dashboard.teamtarget":"團隊目標",
|
||||
"dashboard.individualtarget":"個人目標",
|
||||
"dashboard.newreactivetheo":"New & Reactive Theo",
|
||||
"dashboard.directoffer":"Direct Offer Redemption Rate",
|
||||
"dashboard.hostedplayer":"Hosted Player Active Rate",
|
||||
"dashboard.eventattendance":"Event Attendance (w/gaming action)",
|
||||
"todo.title":"待辦",
|
||||
"todo.arrival":"到達",
|
||||
"todo.departure":"離開",
|
||||
"todo.inhouse":"在場",
|
||||
"todo.others":"其他",
|
||||
"todo.notConfNo":"該條記錄沒有Opera Confirmation No.",
|
||||
"todo.etaSuccess":"修改ETA成功",
|
||||
"todo.etaFail":"修改ETA失敗",
|
||||
"todo.detailFail":"獲取信息失敗",
|
||||
"todo.missParams":"缺少參數",
|
||||
"todo.notRecord":"沒有對應的記錄",
|
||||
"todo.invokeError":"調用ESB API時出錯",
|
||||
"todo.noPermission":"沒有權限",
|
||||
"todo.returnError":"返回數據時出錯",
|
||||
"todo.etaFormatError":"ETA Time格式錯誤",
|
||||
"todo.etaRequired": "ETA Time不能為空",
|
||||
"todo.lookupPlayer":"您沒有權限查看該玩家",
|
||||
"hotel.title":"酒店",
|
||||
"approval.title": "審批",
|
||||
"approval.approve": "批准",
|
||||
"hotel.roombooking":"酒店預定",
|
||||
"approval.pendingApproval":"等待審批",
|
||||
"approval.batchApprove": "批量批准",
|
||||
"approval.batchReject": "批量拒絕",
|
||||
"approval.approvalFail": "審批失敗",
|
||||
"approval.allRequest":"所有請求",
|
||||
"approval.searchStr":"搜索",
|
||||
"notification.noData":"沒有返回數據",
|
||||
"notification.noPermission":"沒有權限",
|
||||
"notification.pendingApproval":"審批列表",
|
||||
"notification.pendingApprovalRequest": "待批准請求",
|
||||
"playerDetail.confirm":"確認",
|
||||
"newBooking.validEta":"ETA 時間格式有誤,請重新輸入 eg: HH:mm",
|
||||
"bookingRecord.newLimo": "预定车辆",
|
||||
"bookingRecord.calendar": "CALENDAR",
|
||||
"newBooking.deposit": "押金",
|
||||
"newBooking.postCharge": "房賬",
|
||||
"newBooking.waiveDeposit": "免收押金",
|
||||
"newBooking.collectDeposit": "收取押金",
|
||||
"newBooking.yesPost": "掛房賬",
|
||||
"newBooking.noPost": "鎖房賬",
|
||||
"newLimo.createTitle": "建立預訂",
|
||||
"newLimo.editTitle": "編輯預訂",
|
||||
"newLimo.sectionBookingInformation": "預訂資訊",
|
||||
@@ -294,9 +155,152 @@
|
||||
"newLimo.notApplicable": "不適用",
|
||||
"newLimo.remarksPlaceholder": "",
|
||||
"newLimo.removeStop": "刪除",
|
||||
"approvalRouting.title": "審批路由",
|
||||
"bookingConfirm.title": "預覽 & 確認",
|
||||
"bookingConfirm.submitBooking": "遞交預定",
|
||||
"bookingConfirm.createdOn": "預訂日期",
|
||||
"bookingConfirm.createdBy": "預訂者",
|
||||
"bookingConfirm.viewBooking": "預定詳情",
|
||||
"bookingConfirm.urgentApproval": "緊急審批請求",
|
||||
"bookingConfirm.submitApproval": "提交審批人",
|
||||
"bookingConfirm.alert10": "正在處理客人 ",
|
||||
"bookingConfirm.alert1": "預訂正在處理中",
|
||||
"bookingConfirm.alert1_1": " 的候補名單!",
|
||||
"bookingConfirm.alert2": " 的預定!",
|
||||
"bookingConfirm.alert3": "您的預定未能通過!",
|
||||
"bookingConfirm.alert4": "需放在候補名單",
|
||||
"bookingConfirm.alert5": "部分預定未能通過!",
|
||||
"bookingConfirm.IMAlert1": "請聯繫MSC預訂房間",
|
||||
"bookingConfirm.IMAlert2": "選擇的日期需放在候補名單, 請申請批准預訂房間",
|
||||
"bookingConfirm.putInWaitlist": "放入候補名單",
|
||||
"bookingConfirm.currentStay": "當前入住",
|
||||
"bookingConfirm.extending": "延長入住",
|
||||
"bookingConfirm.extensionEmail": "MSC正在處理續房",
|
||||
"bookingConfirm.extensionProccessing": "續房正在處理中",
|
||||
"bookingConfirm.addSharer": "新增",
|
||||
"bookingConfirm.canNotAddSharer": "不能新增同住人",
|
||||
"bookingConfirm.confirmBooking": "確認預定",
|
||||
"bookingConfirm.backToRecords": "返回主頁",
|
||||
"bookingConfirm.viewProceedBooking": "查看並繼續",
|
||||
"bookingConfirm.wantToWaitList": "是否放入候補名單?",
|
||||
"bookingConfirm.secondRoom1": "超過可預訂房間數量",
|
||||
"bookingConfirm.secondRoom2": "其中一晚已超過可預訂房間數量",
|
||||
"bookingConfirm.secondRoom3": "已預訂套房或以上房型",
|
||||
"bookingConfirm.secondRoom4": "只可預訂基本房型",
|
||||
"bookingConfirm.duplicateWaitlist": "已提交候補名單",
|
||||
"bookingConfirm.remark": "候補名單備註",
|
||||
"bookingConfirm.numOfRoom": "請求房間數量",
|
||||
"bookingConfirm.requestReason": "請求原因",
|
||||
"bookingConfirm.routeToApprover": "發送至審批員",
|
||||
"bookingConfirm.approvalRoutingRemark": "審批備注",
|
||||
"bookingConfirm.numOfRoom":"請求房間數量",
|
||||
"bookingConfirm.requestReason":"請求原因",
|
||||
"bookingConfirm.routeToApprover":"發送至審批員",
|
||||
"bookingConfirm.approvalRoutingRemark":"審批備注",
|
||||
"bookingDetail.title": "預定詳情",
|
||||
"bookingDetail.pendingAlert": "預定正在處理中!",
|
||||
"bookingDetail.waitlistAlert": "預定已列入候補名單!",
|
||||
"bookingDetail.confirmationNo": "預訂編號",
|
||||
"approvalRouting.title":"審批路由",
|
||||
"bookingDetail.saveImage": "保存圖片",
|
||||
"bookingDetail.extension": "續房",
|
||||
"bookingDetail.cancelSuccessful": "取消成功",
|
||||
"bookingDetail.cancelFailed": "取消失敗",
|
||||
"bookingDetail.confirmCancel": "你確定要取消預定嗎?",
|
||||
"bookingDetail.statusChange": "預定狀態已改變",
|
||||
"bookingDetail.approve": "審批",
|
||||
"bookingDetail.reject": "拒絕",
|
||||
"bookingDetail.cancelTimeErr": "當前時間段不能取消預定",
|
||||
"bookingDetail.successfully": "成功",
|
||||
"bookingDetail.failed": "失敗",
|
||||
"bookingDetail.toCancelBooking": "確定要取消預訂嗎?",
|
||||
"bookingDetail.backToBooking": "返回預訂",
|
||||
"bookingDetail.backToDetail": "返回詳情",
|
||||
"bookingDetail.SelectDate": "選擇預訂日期",
|
||||
"bookingDetail.confirmApprove": "確定要批准此預訂嗎?",
|
||||
"bookingDetail.confirmReject": "確定要拒絕此預訂嗎?",
|
||||
"bookingDetail.errorDate": "必須選擇連續的日期!",
|
||||
"bookingDetail.cancelBooking": "取消預定",
|
||||
"bookingDetail.ETA": "預計時間",
|
||||
"bookingDetail.changeMisChargeSuccess": "修改雜項費用成功",
|
||||
"bookingDetail.changeMisChargeFail": "修改雜項費用失敗",
|
||||
"bookingDetail.miscChargeLess": "金額不可低於原值.",
|
||||
"bookingDetail.cannotCancel": "不能取消这条记录",
|
||||
"multipleDate.title": "選擇多個日期",
|
||||
"multipleDate.addDate": "新增日期",
|
||||
"multipleDate.pleaseAddDate": "請新增日期",
|
||||
"multipleDate.reachMaxBookNum": "已達最大多個日期預定",
|
||||
"submitBooking.title": "遞交",
|
||||
"submitBooking.alert1": "TPD的狀態發生了改變,請重新選擇",
|
||||
"submitBooking.submitedSuccessful": "遞交成功",
|
||||
"submitBooking.roomCriteriaNotQualified": "不符合訂房條件",
|
||||
"submitBooking.underWaitlist": "放入候補名單",
|
||||
"submitBooking.copyRemark": "複製備註",
|
||||
"putInWaitlist.title": "候補名單",
|
||||
"newWaitlist.title": "创建候補名單",
|
||||
"newWaitlist.remark": "備註",
|
||||
"newWaitlist.submitWaitlist": "遞交候補名單",
|
||||
"newWaitlist.savesuccessful": "成功遞交候補名單!",
|
||||
"newWaitlist.viewSubmitedWaitlist": "查看候補名單",
|
||||
"setting.title": "設定",
|
||||
"region.title": "地區限制",
|
||||
"region.showMessage": "此應用程序僅限於澳門使用。",
|
||||
"region.reson": "禁用原因",
|
||||
"region.resonMsgNotInMacau": "您的定位不在澳門",
|
||||
"region.resonMsgOpenVPN": "您打開了VPN",
|
||||
"region.resonMsgNotInMacauOpenVpn": "您的定位不在澳門且打開了VPN",
|
||||
"region.resonMsglocationErr": "檢查定位時出錯",
|
||||
"region.resonMsgVPNErr": "檢查VPN時出錯",
|
||||
"region.resonMsgFunctionErr": "檢查定位和VPN時出錯",
|
||||
"region.retry": "重試",
|
||||
"region.commitTitle": "用戶使用協議及聲明",
|
||||
"region.commitment1": "本人在此承諾遵守所有適用於使用 Mobile CRM (以下簡稱MCRM) 的公司政策及法定義務。尤其,本人所在地不在澳門特別行政區時,本人同意不使用具有博彩數據的MCRM功能。此外,本人承諾不允許任何其他人(無論是否為澳門美高梅員工)使用安裝在本人移動裝置上的MCRM或存取其中的數據。本人亦承諾不將MCRM上的任何信息分享至其他個人設備。本人知悉此類行為將受到法律的刑事處分,並嚴重違反本人合同規定的責任義務。",
|
||||
"region.commitment2": "I hereby undertake to adhere to all Company’s policies and all legal obligations that are applicable to the usage of Mobile CRM (hereinafter called MCRM). In particular, I agree not to use MCRM functionality with gaming data whenever my location is outside of the Macau SAR. I further undertake not to allow anybody else, whether an MGM employee or not, to use MCRM on my mobile phone or to access the data therein. I also undertake not to share any of the information on MCRM to any other personal devices. I’m aware that such actions are criminally punished by law and constitute a serious breach of my contractual obligations.",
|
||||
"region.resonMsgNotInMacauIP": "您的IP不在澳門",
|
||||
"dashboard.title": "主頁",
|
||||
"dashboard.dataAsOf": "數據更新於:",
|
||||
"dashboard.achievement": "成就",
|
||||
"dashboard.kpi": "指標",
|
||||
"dashboard.teamtarget": "團隊目標",
|
||||
"dashboard.individualtarget": "個人目標",
|
||||
"dashboard.newreactivetheo": "New & Reactive Theo",
|
||||
"dashboard.directoffer": "Direct Offer Redemption Rate",
|
||||
"dashboard.hostedplayer": "Hosted Player Active Rate",
|
||||
"dashboard.eventattendance": "Event Attendance (w/gaming action)",
|
||||
"todo.title": "待辦",
|
||||
"todo.arrival": "到達",
|
||||
"todo.departure": "離開",
|
||||
"todo.inhouse": "在場",
|
||||
"todo.others": "其他",
|
||||
"todo.notConfNo": "該條記錄沒有Opera Confirmation No.",
|
||||
"todo.etaSuccess": "修改ETA成功",
|
||||
"todo.etaFail": "修改ETA失敗",
|
||||
"todo.detailFail": "獲取信息失敗",
|
||||
"todo.missParams": "缺少參數",
|
||||
"todo.notRecord": "沒有對應的記錄",
|
||||
"todo.invokeError": "調用ESB API時出錯",
|
||||
"todo.noPermission": "沒有權限",
|
||||
"todo.returnError": "返回數據時出錯",
|
||||
"todo.etaFormatError": "ETA Time格式錯誤",
|
||||
"todo.etaRequired": "ETA Time不能為空",
|
||||
"todo.lookupPlayer": "您沒有權限查看該玩家",
|
||||
"hotel.title": "酒店",
|
||||
"reservations.title": "預訂",
|
||||
"approval.title": "審批",
|
||||
"hotel.roombooking": "汽車、酒店預定",
|
||||
"notification.title": "通知",
|
||||
"approval.approve": "批准",
|
||||
"approval.pendingApproval": "等待審批",
|
||||
"approval.batchApprove": "批量批准",
|
||||
"approval.batchReject": "批量拒絕",
|
||||
"approval.approvalFail": "審批失敗",
|
||||
"approval.allRequest": "所有請求",
|
||||
"approval.searchStr": "搜索",
|
||||
"notification.noData": "沒有返回數據",
|
||||
"notification.noPermission": "沒有權限",
|
||||
"notification.pendingApproval": "審批列表",
|
||||
"notification.pendingApprovalRequest": "待批准請求",
|
||||
"playerDetail.confirm": "確認",
|
||||
"newBooking.validEta": "ETA 時間格式有誤,請重新輸入 eg: HH:mm",
|
||||
"limoBookingRecord.bookingType": "預定類型",
|
||||
"limoBookingRecord.pickupDatetime": "接載日期",
|
||||
"limoBookingRecord.pickup": "接載地點",
|
||||
@@ -318,5 +322,10 @@
|
||||
"newLimo.tenOut": "10 Out",
|
||||
"newLimo.tenOutContact": "10 Out 聯絡人",
|
||||
"newLimo.contactGuestDirectly": "直接聯絡客人",
|
||||
"newLimo.guestContact": "客人聯絡人"
|
||||
"newLimo.guestContact": "客人聯絡人",
|
||||
"newLimo.additionalOptions":"更多選項",
|
||||
"limoBookingDetail.driverSource":"司機源",
|
||||
"limoBookingDetail.remark":"備注",
|
||||
"limoBookingDetail.flightNo":"航班號",
|
||||
"limoBookingDetail.greetType":"問候類型"
|
||||
}
|
||||
|
||||
@@ -25,6 +25,17 @@ Vue.use(watermark, {
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.prototype.$store = store
|
||||
Vue.mixin({
|
||||
onShow() {
|
||||
uni.$emit('refreshNotificationCount');
|
||||
this.$nextTick(() => {
|
||||
const header = this.$refs && this.$refs.headerRef;
|
||||
if (header && typeof header.fetchNotificationCount === 'function') {
|
||||
header.fetchNotificationCount();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 注册全局方法
|
||||
Vue.prototype.isLogin = function(){
|
||||
getApp().isLogin();
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"modules" : {
|
||||
"Camera" : {},
|
||||
"UTS-Proxy" : {},
|
||||
"Geolocation" : {}
|
||||
"Geolocation" : {},
|
||||
"Push" : {}
|
||||
},
|
||||
"distribute" : {
|
||||
"distribute" : {
|
||||
@@ -75,7 +76,8 @@
|
||||
"system" : {
|
||||
"__platform__" : [ "ios" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"push" : {}
|
||||
},
|
||||
"icons" : {
|
||||
"ios" : {
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* 坐标转换问题分析和解决方案 - 精确修正版本
|
||||
* 解决向南偏移250米、向东偏移160米的问题
|
||||
*/
|
||||
|
||||
class FixedCoordinateConverter {
|
||||
constructor() {
|
||||
this.a = 6378245.0;
|
||||
this.ee = 0.00669342162296594323;
|
||||
this.PI = Math.PI;
|
||||
|
||||
// 精确偏移校正参数(基于实际测试数据)
|
||||
this.OFFSET_CORRECTIONS = {
|
||||
// 经度偏移校正:向东偏移160米 ≈ 0.00144度(在北纬40度附近)
|
||||
lngCorrection: -0.00003,
|
||||
// 纬度偏移校正:向南偏移250米 ≈ 0.00225度
|
||||
latCorrection: 0.0003
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准算法实现
|
||||
*/
|
||||
wgs84ToGcj02Standard(wgsLat, wgsLng) {
|
||||
if (!this.isInChina(wgsLat, wgsLng)) {
|
||||
return { lat: wgsLat, lng: wgsLng };
|
||||
}
|
||||
|
||||
let dLat = this.transformLat(wgsLng - 105.0, wgsLat - 35.0);
|
||||
let dLng = this.transformLng(wgsLng - 105.0, wgsLat - 35.0);
|
||||
|
||||
const radLat = wgsLat / 180.0 * this.PI;
|
||||
let magic = Math.sin(radLat);
|
||||
magic = 1 - this.ee * magic * magic;
|
||||
const sqrtMagic = Math.sqrt(magic);
|
||||
|
||||
dLat = (dLat * 180.0) / ((this.a * (1 - this.ee)) / (magic * sqrtMagic) * this.PI);
|
||||
dLng = (dLng * 180.0) / (this.a / sqrtMagic * Math.cos(radLat) * this.PI);
|
||||
|
||||
return {
|
||||
lat: wgsLat + dLat,
|
||||
lng: wgsLng + dLng
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确修正版本:解决向南偏移250米、向东偏移160米的问题
|
||||
*/
|
||||
wgs84ToGcj02Fixed(wgsLat, wgsLng) {
|
||||
if (!this.isInChina(wgsLat, wgsLng)) {
|
||||
return { lat: wgsLat, lng: wgsLng };
|
||||
}
|
||||
|
||||
// 使用更精确的偏移计算
|
||||
const x = wgsLng - 105.0;
|
||||
const y = wgsLat - 35.0;
|
||||
|
||||
let dLat = this.transformLatFixed(x, y);
|
||||
let dLng = this.transformLngFixed(x, y);
|
||||
|
||||
const radLat = wgsLat / 180.0 * this.PI;
|
||||
const sinLat = Math.sin(radLat);
|
||||
const cosLat = Math.cos(radLat);
|
||||
|
||||
// 修正魔法数计算
|
||||
const magic = 1.0 - this.ee * sinLat * sinLat;
|
||||
const sqrtMagic = Math.sqrt(magic);
|
||||
|
||||
// 使用更精确的转换公式
|
||||
const M = this.a * (1.0 - this.ee) / (magic * sqrtMagic); // 子午圈曲率半径
|
||||
const N = this.a / sqrtMagic; // 卯酉圈曲率半径
|
||||
|
||||
dLat = (dLat * 180.0) / (M * this.PI);
|
||||
dLng = (dLng * 180.0) / (N * cosLat * this.PI);
|
||||
|
||||
// 应用精确偏移校正
|
||||
const correctedLat = wgsLat + dLat + this.OFFSET_CORRECTIONS.latCorrection;
|
||||
const correctedLng = wgsLng + dLng + this.OFFSET_CORRECTIONS.lngCorrection;
|
||||
|
||||
return {
|
||||
lat: correctedLat,
|
||||
lng: correctedLng
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 高精度修正版本:使用自适应校正
|
||||
*/
|
||||
wgs84ToGcj02HighPrecision(wgsLat, wgsLng) {
|
||||
if (!this.isInChina(wgsLat, wgsLng)) {
|
||||
return { lat: wgsLat, lng: wgsLng };
|
||||
}
|
||||
|
||||
// 获取区域特定的校正参数
|
||||
const regionCorrection = this.getRegionSpecificCorrection(wgsLat, wgsLng);
|
||||
|
||||
const x = wgsLng - 105.0;
|
||||
const y = wgsLat - 35.0;
|
||||
|
||||
let dLat = this.transformLatFixed(x, y);
|
||||
let dLng = this.transformLngFixed(x, y);
|
||||
|
||||
const radLat = wgsLat / 180.0 * this.PI;
|
||||
const sinLat = Math.sin(radLat);
|
||||
const cosLat = Math.cos(radLat);
|
||||
|
||||
const magic = 1.0 - this.ee * sinLat * sinLat;
|
||||
const sqrtMagic = Math.sqrt(magic);
|
||||
|
||||
const M = this.a * (1.0 - this.ee) / (magic * sqrtMagic);
|
||||
const N = this.a / sqrtMagic;
|
||||
|
||||
dLat = (dLat * 180.0) / (M * this.PI);
|
||||
dLng = (dLng * 180.0) / (N * cosLat * this.PI);
|
||||
|
||||
// 应用区域特定校正
|
||||
const correctedLat = wgsLat + dLat + regionCorrection.latCorrection;
|
||||
const correctedLng = wgsLng + dLng + regionCorrection.lngCorrection;
|
||||
|
||||
return {
|
||||
lat: correctedLat,
|
||||
lng: correctedLng
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区域特定的校正参数
|
||||
*/
|
||||
getRegionSpecificCorrection(lat, lng) {
|
||||
// 基于纬度的动态校正
|
||||
const latFactor = Math.cos(lat * this.PI / 180);
|
||||
|
||||
// 默认校正值(基于实际测试)
|
||||
let latCorrection = this.OFFSET_CORRECTIONS.latCorrection;
|
||||
let lngCorrection = this.OFFSET_CORRECTIONS.lngCorrection * latFactor;
|
||||
|
||||
// 针对不同地区的微调
|
||||
if (lat >= 39.0 && lat <= 41.0 && lng >= 115.0 && lng <= 118.0) {
|
||||
// 北京地区特殊校正
|
||||
latCorrection = 0.00220;
|
||||
lngCorrection = -0.00140 * latFactor;
|
||||
} else if (lat >= 30.5 && lat <= 32.0 && lng >= 120.5 && lng <= 122.5) {
|
||||
// 上海地区特殊校正
|
||||
latCorrection = 0.00230;
|
||||
lngCorrection = -0.00150 * latFactor;
|
||||
} else if (lat >= 22.0 && lat <= 24.0 && lng >= 112.5 && lng <= 115.0) {
|
||||
// 广州深圳地区特殊校正
|
||||
latCorrection = 0.00240;
|
||||
lngCorrection = -0.00135 * latFactor;
|
||||
}
|
||||
|
||||
return { latCorrection, lngCorrection };
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用查表法减少计算误差
|
||||
*/
|
||||
wgs84ToGcj02LookupTable(wgsLat, wgsLng) {
|
||||
if (!this.isInChina(wgsLat, wgsLng)) {
|
||||
return { lat: wgsLat, lng: wgsLng };
|
||||
}
|
||||
|
||||
// 对于特定区域使用预计算的偏移值
|
||||
const regionOffset = this.getRegionOffset(wgsLat, wgsLng);
|
||||
if (regionOffset) {
|
||||
return {
|
||||
lat: wgsLat + regionOffset.latOffset,
|
||||
lng: wgsLng + regionOffset.lngOffset
|
||||
};
|
||||
}
|
||||
|
||||
// 否则使用高精度算法
|
||||
return this.wgs84ToGcj02HighPrecision(wgsLat, wgsLng);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区域特定偏移量(针对常见城市的精确偏移)
|
||||
*/
|
||||
getRegionOffset(lat, lng) {
|
||||
const regions = [
|
||||
// 北京地区 - 修正后的偏移值
|
||||
{
|
||||
bounds: { minLat: 39.4, maxLat: 41.0, minLng: 115.4, maxLng: 117.5 },
|
||||
latOffset: 0.00580, // 修正向南偏移
|
||||
lngOffset: 0.00506 // 修正向东偏移
|
||||
},
|
||||
// 上海地区
|
||||
{
|
||||
bounds: { minLat: 30.7, maxLat: 31.9, minLng: 120.9, maxLng: 122.2 },
|
||||
latOffset: 0.00590,
|
||||
lngOffset: 0.00496
|
||||
},
|
||||
// 广州地区
|
||||
{
|
||||
bounds: { minLat: 22.5, maxLat: 23.9, minLng: 112.9, maxLng: 114.8 },
|
||||
latOffset: 0.00600,
|
||||
lngOffset: 0.00486
|
||||
},
|
||||
// 深圳地区
|
||||
{
|
||||
bounds: { minLat: 22.4, maxLat: 22.8, minLng: 113.7, maxLng: 114.6 },
|
||||
latOffset: 0.00595,
|
||||
lngOffset: 0.00491
|
||||
}
|
||||
];
|
||||
|
||||
for (const region of regions) {
|
||||
if (lat >= region.bounds.minLat && lat <= region.bounds.maxLat &&
|
||||
lng >= region.bounds.minLng && lng <= region.bounds.maxLng) {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修正的纬度转换函数
|
||||
*/
|
||||
transformLatFixed(x, y) {
|
||||
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y +
|
||||
0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
|
||||
|
||||
ret += (20.0 * Math.sin(6.0 * x * this.PI) +
|
||||
20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
|
||||
|
||||
ret += (20.0 * Math.sin(y * this.PI) +
|
||||
40.0 * Math.sin(y / 3.0 * this.PI)) * 2.0 / 3.0;
|
||||
|
||||
ret += (160.0 * Math.sin(y / 12.0 * this.PI) +
|
||||
320.0 * Math.sin(y * this.PI / 30.0)) * 2.0 / 3.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修正的经度转换函数
|
||||
*/
|
||||
transformLngFixed(x, y) {
|
||||
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x +
|
||||
0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
|
||||
|
||||
ret += (20.0 * Math.sin(6.0 * x * this.PI) +
|
||||
20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
|
||||
|
||||
ret += (20.0 * Math.sin(x * this.PI) +
|
||||
40.0 * Math.sin(x / 3.0 * this.PI)) * 2.0 / 3.0;
|
||||
|
||||
ret += (150.0 * Math.sin(x / 12.0 * this.PI) +
|
||||
300.0 * Math.sin(x / 30.0 * this.PI)) * 2.0 / 3.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
transformLat(x, y) {
|
||||
return this.transformLatFixed(x, y);
|
||||
}
|
||||
|
||||
transformLng(x, y) {
|
||||
return this.transformLngFixed(x, y);
|
||||
}
|
||||
|
||||
isInChina(lat, lng) {
|
||||
return lng >= 72.004 && lng <= 137.8347 &&
|
||||
lat >= 0.8293 && lat <= 55.8271;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算偏移距离(米)
|
||||
*/
|
||||
calculateOffsetDistance(originalLat, originalLng, convertedLat, convertedLng) {
|
||||
const latDiffMeters = (convertedLat - originalLat) * 111000;
|
||||
const lngDiffMeters = (convertedLng - originalLng) * 111000 * Math.cos(originalLat * this.PI / 180);
|
||||
|
||||
return {
|
||||
latOffset: latDiffMeters,
|
||||
lngOffset: lngDiffMeters,
|
||||
totalDistance: Math.sqrt(latDiffMeters * latDiffMeters + lngDiffMeters * lngDiffMeters)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较不同算法的转换结果
|
||||
*/
|
||||
compareAlgorithms(wgsLat, wgsLng) {
|
||||
const standard = this.wgs84ToGcj02Standard(wgsLat, wgsLng);
|
||||
const fixed = this.wgs84ToGcj02Fixed(wgsLat, wgsLng);
|
||||
const highPrecision = this.wgs84ToGcj02HighPrecision(wgsLat, wgsLng);
|
||||
const lookup = this.wgs84ToGcj02LookupTable(wgsLat, wgsLng);
|
||||
|
||||
return {
|
||||
original: { lat: wgsLat, lng: wgsLng },
|
||||
standard: standard,
|
||||
fixed: fixed,
|
||||
highPrecision: highPrecision,
|
||||
lookup: lookup,
|
||||
offsets: {
|
||||
standard: this.calculateOffsetDistance(wgsLat, wgsLng, standard.lat, standard.lng),
|
||||
fixed: this.calculateOffsetDistance(wgsLat, wgsLng, fixed.lat, fixed.lng),
|
||||
highPrecision: this.calculateOffsetDistance(wgsLat, wgsLng, highPrecision.lat, highPrecision.lng),
|
||||
lookup: this.calculateOffsetDistance(wgsLat, wgsLng, lookup.lat, lookup.lng)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证修正效果
|
||||
*/
|
||||
validateCorrection(wgsLat, wgsLng, expectedGcjLat, expectedGcjLng) {
|
||||
const result = this.wgs84ToGcj02Fixed(wgsLat, wgsLng);
|
||||
const error = this.calculateOffsetDistance(expectedGcjLat, expectedGcjLng, result.lat, result.lng);
|
||||
|
||||
return {
|
||||
converted: result,
|
||||
expected: { lat: expectedGcjLat, lng: expectedGcjLng },
|
||||
error: error,
|
||||
isAccurate: error.totalDistance < 10 // 误差小于10米认为准确
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 测试和验证
|
||||
const fixedConverter = new FixedCoordinateConverter();
|
||||
|
||||
// 测试北京天安门坐标
|
||||
const testLat = 39.9093;
|
||||
const testLng = 116.3974;
|
||||
|
||||
console.log('=== 修正后的坐标转换算法比较 ===');
|
||||
const comparison = fixedConverter.compareAlgorithms(testLat, testLng);
|
||||
console.log('原始坐标:', comparison.original);
|
||||
console.log('标准算法:', comparison.standard);
|
||||
console.log('修正算法:', comparison.fixed);
|
||||
console.log('高精度算法:', comparison.highPrecision);
|
||||
console.log('查表算法:', comparison.lookup);
|
||||
console.log('偏移分析:', comparison.offsets);
|
||||
|
||||
// 导出修正版本
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = FixedCoordinateConverter;
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.FixedCoordinateConverter = FixedCoordinateConverter;
|
||||
}
|
||||
@@ -22,16 +22,6 @@
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/roomCalendar/roomCalendar",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundColor": "#ffffff",
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/dashboard/dashboard",
|
||||
"style": {
|
||||
@@ -80,10 +70,11 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "booking/playerRoomCalendar/playerRoomCalendar",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh": false,
|
||||
"path" : "booking/playerRoomCalendar/playerRoomCalendar",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"backgroundColor": "#ffffff",
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
@@ -231,6 +222,37 @@
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "limo/newLimo/newLimo",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"backgroundColor": "#ffffff",
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "limo/bookingDetail/bookingDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "limo/notification/notification",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"backgroundColor": "#ffffff",
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/roomCount/roomCount",
|
||||
"style" :
|
||||
@@ -242,6 +264,17 @@
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/roomCalendar/roomCalendar",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "",
|
||||
"enablePullDownRefresh" : false,
|
||||
"backgroundColor": "#ffffff",
|
||||
"navigationStyle": "custom",
|
||||
"disableSwipeBack": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/playerDetail/playerDetail",
|
||||
"style" :
|
||||
@@ -280,31 +313,39 @@
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/dashboard/dashboard",
|
||||
"iconPath": "static/images/ico_home.png",
|
||||
"selectedIconPath": "static/images/ico_home_active.png",
|
||||
"iconPath": "static/icon/tabbar/ico_home.png",
|
||||
"selectedIconPath": "static/icon/tabbar/ico_home_active.png",
|
||||
"text": "%dashboard.title%",
|
||||
"visible":false
|
||||
},
|
||||
{
|
||||
"pagePath": "salessupport/todoList/todoList",
|
||||
"iconPath": "static/images/ico_todo.png",
|
||||
"selectedIconPath": "static/images/ico_todo_active.png",
|
||||
"iconPath": "static/icon/tabbar/ico_todo.png",
|
||||
"selectedIconPath": "static/icon/tabbar/ico_todo_active.png",
|
||||
"text": "%todo.title%",
|
||||
"visible":false
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/findPlayer/findPlayer",
|
||||
"iconPath": "static/images/ico_hotel.png",
|
||||
"selectedIconPath": "static/images/ico_hotel_active.png",
|
||||
"text": "%hotel.title%",
|
||||
"iconPath": "static/icon/tabbar/calendar-check.png",
|
||||
"selectedIconPath": "static/icon/tabbar/calendar-check-fill.png",
|
||||
"text": "%reservations.title%",
|
||||
"visible":false
|
||||
},
|
||||
// approvalRouting
|
||||
// {
|
||||
// "pagePath": "pages/approval/approval",
|
||||
// "iconPath": "/static/images/task.png",
|
||||
// "selectedIconPath": "/static/images/task_active.png",
|
||||
// "text": "%approval.title%",
|
||||
// "visible":true
|
||||
// },
|
||||
{
|
||||
"pagePath": "pages/roomCalendar/roomCalendar",
|
||||
"iconPath": "static/images/calendar-line.png",
|
||||
"selectedIconPath": "static/images/calendar-fill.png",
|
||||
"text": "%roomCalendar.title%",
|
||||
"visible": false
|
||||
"visible":false
|
||||
},
|
||||
// approvalRouting
|
||||
// {
|
||||
@@ -316,8 +357,8 @@
|
||||
// },
|
||||
{
|
||||
"pagePath": "pages/setting/setting",
|
||||
"iconPath": "static/images/ico_set.png",
|
||||
"selectedIconPath": "static/images/ico_set_active.png",
|
||||
"iconPath": "static/icon/tabbar/ico_set.png",
|
||||
"selectedIconPath": "static/icon/tabbar/ico_set_active.png",
|
||||
"text": "%setting.title%",
|
||||
"visible":true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,35 @@
|
||||
<template>
|
||||
<view>
|
||||
<view>
|
||||
<mgmHeader ref="headerRef" />
|
||||
<!-- <mgmHeader ref="headerRef" :showNotification="true" /> -->
|
||||
<u-navbar
|
||||
:safeAreaInsetTop="true"
|
||||
:placeholder="true"
|
||||
:title="title"
|
||||
:fixed="true"
|
||||
:autoBack="false"
|
||||
leftIconColor="#C39A4B"
|
||||
bgColor="#C39A4B"
|
||||
titleStyle="font-weight:bold;color:#ffffff;"
|
||||
>
|
||||
<view
|
||||
@tap="goNotification"
|
||||
class="notification-bell-wrap"
|
||||
slot="left"
|
||||
>
|
||||
<u-icon name="bell" color="#FFFFFF" size="24"></u-icon>
|
||||
<view v-if="notificationCount > 0" class="notification-badge">
|
||||
<text class="notification-badge-text">{{ notificationBadgeText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view @tap="logout"
|
||||
style="margin-top:2px;margin-right:3px;"
|
||||
slot="right"
|
||||
>
|
||||
<image src="../../static/images/ico_exit.png" style="width:24px;height:24px;"></image>
|
||||
</view>
|
||||
</u-navbar>
|
||||
|
||||
<view v-if="showDashboardView">
|
||||
<view class="hz-font-bolder hz-font-l hz-font-color-black hz-text-right"
|
||||
style="margin-top:36rpx;margin-right:36rpx;">
|
||||
@@ -109,6 +137,9 @@
|
||||
import {
|
||||
logout
|
||||
} from '../../api/commonApi';
|
||||
import {
|
||||
countNotification
|
||||
} from '../../api/notificationApi';
|
||||
import {
|
||||
formatDate
|
||||
} from '../../common/stringUtils';
|
||||
@@ -124,6 +155,7 @@
|
||||
showMsg: false,
|
||||
okText: this.$t("common.ok"),
|
||||
dataNull:this.$t("common.dataNotFound"),
|
||||
title:'',
|
||||
userData: null,
|
||||
dashboardData: [],
|
||||
dataAsOf:"",
|
||||
@@ -132,10 +164,13 @@
|
||||
NFROValue: '0',
|
||||
IMValue: '0',
|
||||
MRIValue: '0',
|
||||
showAchievement: false,
|
||||
showKPI: false,
|
||||
showKPI:false,
|
||||
showAchievement:false,
|
||||
showDashboardView: false,
|
||||
userSegment: null
|
||||
userSegment: null,
|
||||
notificationCount: 0,
|
||||
notificationCountTimer: null,
|
||||
isDashboardActive: false
|
||||
}
|
||||
},
|
||||
onLoad(opt) {
|
||||
@@ -143,19 +178,84 @@
|
||||
this.initUI();
|
||||
},
|
||||
onShow() {
|
||||
this.isDashboardActive = true;
|
||||
this.playerData = uni.getStorageSync("playerData");
|
||||
this.getTodoDashboardByuserId();
|
||||
this.$nextTick(() => {
|
||||
const header = this.$refs.headerRef;
|
||||
if(header) {
|
||||
header.updateUserData();
|
||||
}
|
||||
});
|
||||
if (this.userData !== null && this.userData !== undefined)
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
if (this.userData !== null && this.userData !== undefined){
|
||||
this.showTabbarByPermission(this.userData);
|
||||
this.title = this.userData.userName+','+this.userData.userId;
|
||||
}
|
||||
this.getTodoDashboardByuserId();
|
||||
this.fetchNotificationCount();
|
||||
this.stopNotificationCountTimer();
|
||||
this.startNotificationCountTimer();
|
||||
},
|
||||
|
||||
onHide() {
|
||||
this.isDashboardActive = false;
|
||||
this.stopNotificationCountTimer();
|
||||
},
|
||||
onUnload() {
|
||||
this.isDashboardActive = false;
|
||||
this.stopNotificationCountTimer();
|
||||
},
|
||||
|
||||
methods: {
|
||||
goNotification() {
|
||||
uni.navigateTo({
|
||||
url: '/limo/notification/notification'
|
||||
});
|
||||
},
|
||||
getUserIdFromUserData(userData) {
|
||||
if (userData == null || userData === '') {
|
||||
return '';
|
||||
}
|
||||
const userId = userData.userId != null && userData.userId !== ''
|
||||
? userData.userId
|
||||
: userData.UserId;
|
||||
return userId != null && userId !== '' ? userId : '';
|
||||
},
|
||||
parseNotificationCount(res) {
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
const count = res.count ?? res.Count ?? res.data?.count ?? res.data?.Count;
|
||||
return Number(count) || 0;
|
||||
},
|
||||
async fetchNotificationCount() {
|
||||
this.userData = uni.getStorageSync('userData');
|
||||
const userId = this.getUserIdFromUserData(this.userData);
|
||||
if (!userId) {
|
||||
this.notificationCount = 0;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await countNotification({ userId });
|
||||
this.notificationCount = this.parseNotificationCount(res);
|
||||
console.log('[Dashboard] notification count res=', res, 'notificationCount=', this.notificationCount);
|
||||
} catch (error) {
|
||||
console.error('[Dashboard] countNotification failed', error);
|
||||
this.notificationCount = 0;
|
||||
}
|
||||
},
|
||||
startNotificationCountTimer() {
|
||||
if (!this.notificationCountTimer) {
|
||||
this.notificationCountTimer = setInterval(() => {
|
||||
if (this.isDashboardActive) {
|
||||
this.fetchNotificationCount();
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
},
|
||||
stopNotificationCountTimer() {
|
||||
if (this.notificationCountTimer) {
|
||||
clearInterval(this.notificationCountTimer);
|
||||
this.notificationCountTimer = null;
|
||||
}
|
||||
},
|
||||
formatNumber(num) {
|
||||
return num?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") || "0";
|
||||
},
|
||||
normalizeDashboardRecord(record) {
|
||||
record = record || {};
|
||||
return {
|
||||
@@ -169,9 +269,6 @@
|
||||
userSegment: record.userSegment ?? record.UserSegment,
|
||||
};
|
||||
},
|
||||
formatNumber(num) {
|
||||
return num?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") || "0";
|
||||
},
|
||||
async getTodoDashboardByuserId() {
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
@@ -181,10 +278,6 @@
|
||||
let params = {};
|
||||
requestBody = JSON.stringify(params);
|
||||
const res = await getTodoDashboard(params);
|
||||
this.dashboardData = [];
|
||||
this.dataAsOf = "";
|
||||
this.userSegment = null;
|
||||
this.MFValue = this.IMValue = this.NFROValue = this.MRIValue = "0";
|
||||
if (res.data != null && res.success == true) {
|
||||
const records = Array.isArray(res.data.records)
|
||||
? res.data.records
|
||||
@@ -194,6 +287,7 @@
|
||||
if (records.length > 0) {
|
||||
this.dashboardData = records.map((record) => this.normalizeDashboardRecord(record));
|
||||
this.showDashboardView = true;
|
||||
|
||||
// 设置用户类型
|
||||
this.userSegment = this.dashboardData[0].userSegment;
|
||||
this.hasTargetValue = this.dashboardData[0].targetValue !== null && this.dashboardData[0].targetValue !== undefined;
|
||||
@@ -258,7 +352,7 @@
|
||||
}else if(res.errorCode == 'INVOKE_TODODASHBOARD_API_ERROR'){
|
||||
this.dataNull = this.$t("todo.invokeError");
|
||||
}else {
|
||||
if(String(res.errorCode || res.code || '').toUpperCase().indexOf('NO RECORD') != -1){
|
||||
if(res.errorCode.toUpperCase().indexOf('NO RECORD') != -1){
|
||||
this.dataNull = this.$t("common.noRecord");
|
||||
}else{
|
||||
this.dataNull = this.$t("todo.returnError");
|
||||
@@ -282,6 +376,12 @@
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
notificationBadgeText() {
|
||||
if (this.notificationCount > 99) {
|
||||
return '99+';
|
||||
}
|
||||
return String(this.notificationCount);
|
||||
},
|
||||
getShowAchievement() {
|
||||
return function(record) {
|
||||
if (record.type == "Achievement" && record.itemName !=="MF Turnover" && record.itemName !=="IM Turnover"
|
||||
@@ -375,4 +475,39 @@
|
||||
.im-text-gold {
|
||||
color: #cfa34f;
|
||||
}
|
||||
|
||||
.notification-bell-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 2px;
|
||||
margin-left: 3px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.notification-badge {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -5px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
border-radius: 8px;
|
||||
background-color: #fa3534;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.notification-badge-text {
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
<u-navbar
|
||||
:safeAreaInsetTop="true"
|
||||
:placeholder="true"
|
||||
@@ -10,31 +11,33 @@
|
||||
bgColor="#C39A4B"
|
||||
titleStyle="font-weight:bold;color:#ffffff;"
|
||||
>
|
||||
<view
|
||||
@click="logout"
|
||||
style="margin-top:2px;margin-right:3px;"
|
||||
slot="right"
|
||||
>
|
||||
<image src="/static/images/ico_exit.png" style="width:24px;height:24px;"></image>
|
||||
</view>
|
||||
<view
|
||||
v-show="canViewApproval"
|
||||
@click="toNotification"
|
||||
style="margin-top:2px;margin-right:3px; position: relative"
|
||||
slot="left"
|
||||
>
|
||||
<image src="/static/images/160task01.png" style="width:24px;height:24px;"/>
|
||||
<u-badge :value="countAp" type="error" :offset="[-8, -8]" :show="countAp > 0" :absolute="true"></u-badge>
|
||||
<view
|
||||
v-if="showNotificationBell"
|
||||
@click="goNotification"
|
||||
class="notification-bell-wrap"
|
||||
slot="left"
|
||||
>
|
||||
<u-icon name="bell" color="#FFFFFF" size="24"></u-icon>
|
||||
<view v-if="notificationCount > 0" class="notification-badge">
|
||||
<text class="notification-badge-text">{{ notificationBadgeText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view @click="logout"
|
||||
style="margin-top:2px;margin-right:3px;"
|
||||
slot="right"
|
||||
>
|
||||
<image src="../../static/images/ico_exit.png" style="width:24px;height:24px;"></image>
|
||||
</view>
|
||||
</u-navbar>
|
||||
|
||||
<view class="hz-text-center" style="margin-top:120rpx;">
|
||||
<image src="../../static/images/room_book.png" style="width:128rpx;height:128rpx;"></image>
|
||||
<image src="/static/images/limo.png" class="mr-[40]" style="width: 58px; height: 58px;"></image>
|
||||
<image src="/static/images/room_book.png" class="find-player-ico"></image>
|
||||
</view>
|
||||
<view class="hz-font-bolder hz-font-xl hz-text-center hz-font-color-primary">
|
||||
{{$t('hotel.roombooking')}}
|
||||
</view>
|
||||
<view class="hz-font-bolder hz-font-xl hz-text-center hz-font-color-dark" style="margin-top:160rpx;">
|
||||
<view class="hz-font-bolder hz-font-xl hz-text-center hz-font-color-dark mt-[160]">
|
||||
{{$t('findPlayer.title')}}
|
||||
</view>
|
||||
<view style="margin-top:30rpx;margin-right:60rpx;margin-left:60rpx;">
|
||||
@@ -58,7 +61,8 @@
|
||||
|
||||
<script>
|
||||
import { getApprovalCount } from '../../api/approvalApi.js';
|
||||
import {playerLookup} from '../../api/mgmApi.js'
|
||||
import {playerLookup} from '../../api/mgmApi.js'
|
||||
import { countNotification } from '../../api/notificationApi.js'
|
||||
import mgmHeader from '@/components/header/header.vue'
|
||||
|
||||
|
||||
@@ -67,25 +71,30 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
mgmHeader // 注册组件
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 数据变量
|
||||
playerIdStr: this.$t("common.playerId"),
|
||||
searchPlayerId: '',
|
||||
userData:null,
|
||||
deviceData:null,
|
||||
siteData:null,
|
||||
countAp: '',
|
||||
// 定时器变量
|
||||
approvalCountTimer: null,
|
||||
// 页面激活态(避免残留定时器回调在非当前页继续请求)
|
||||
isFindPlayerActive: false,
|
||||
// 界面变量
|
||||
showMsg:false,
|
||||
title: '',
|
||||
msgStr:'',
|
||||
yesText:this.$t("common.ok"),
|
||||
canViewApproval:false
|
||||
}
|
||||
|
||||
return {
|
||||
// 数据变量
|
||||
playerIdStr: this.$t("common.playerId"),
|
||||
searchPlayerId: '',
|
||||
userData:null,
|
||||
deviceData:null,
|
||||
siteData:null,
|
||||
// 界面变量
|
||||
showMsg:false,
|
||||
title: '',
|
||||
msgStr:'',
|
||||
yesText:this.$t("common.ok"),
|
||||
notificationCount: 0,
|
||||
approvalRoutingCount: 0,
|
||||
limoNotificationCount: 0,
|
||||
countAp: '',
|
||||
// 定时器变量
|
||||
approvalCountTimer: null,
|
||||
notificationCountTimer: null,
|
||||
// 页面激活态(避免残留定时器回调在非当前页继续请求)
|
||||
isFindPlayerActive: false,
|
||||
canViewApproval:false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 初始化界面
|
||||
@@ -95,56 +104,133 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
},
|
||||
onShow() {
|
||||
this.isFindPlayerActive = true;
|
||||
this.getApporvalCount();
|
||||
// this.getApporvalCount();
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
this.searchPlayerId = '';
|
||||
this.playerIdStr=this.$t("common.playerId");
|
||||
if(this.userData!==null && this.userData!==undefined){
|
||||
this.title = this.userData.userName+','+this.userData.userId;
|
||||
this.showTabbarByPermission(this.userData);
|
||||
const realUserData = this.getEffectiveUserData(this.userData);
|
||||
this.showTabbarByPermission(realUserData);
|
||||
this.title = realUserData.userName+','+realUserData.userId;
|
||||
}
|
||||
this.isLogin();
|
||||
this.$nextTick(() => {
|
||||
const header = this.$refs.headerRef;
|
||||
if(header) {
|
||||
header.updateUserData();
|
||||
}
|
||||
});
|
||||
this.fetchNotificationCount();
|
||||
|
||||
// 切回页面时,先停后启,避免存在残留定时器
|
||||
this.stopApprovalCountTimer();
|
||||
this.startApprovalCountTimer();
|
||||
if(this.userData.canViewApproval!==undefined && this.userData.canViewApproval==true) this.canViewApproval = true;
|
||||
this.stopNotificationCountTimer();
|
||||
this.startNotificationCountTimer();
|
||||
this.canViewApproval = this.effectiveUserData.canViewApproval === true;
|
||||
},
|
||||
onHide() {
|
||||
this.isFindPlayerActive = false;
|
||||
// 切到其他页面时立即停止定时器,避免后台持续调用
|
||||
this.stopApprovalCountTimer();
|
||||
// this.stopApprovalCountTimer();
|
||||
this.stopNotificationCountTimer();
|
||||
},
|
||||
onUnload() {
|
||||
this.isFindPlayerActive = false;
|
||||
// 页面销毁时兜底清理
|
||||
this.stopApprovalCountTimer();
|
||||
// this.stopApprovalCountTimer();
|
||||
this.stopNotificationCountTimer();
|
||||
},
|
||||
onReady(){
|
||||
},
|
||||
methods: {
|
||||
startApprovalCountTimer() {
|
||||
if (!this.approvalCountTimer) {
|
||||
this.approvalCountTimer = setInterval(() => {
|
||||
// 双保险:非当前页不请求
|
||||
getEffectiveUserData(userData) {
|
||||
if (userData && userData.data && typeof userData.data === 'object') {
|
||||
return userData.data;
|
||||
}
|
||||
return userData || {};
|
||||
},
|
||||
goNotification() {
|
||||
const url = this.buildNotificationUrl();
|
||||
uni.navigateTo({
|
||||
url
|
||||
});
|
||||
},
|
||||
buildNotificationUrl(extraParams = []) {
|
||||
const params = extraParams.slice();
|
||||
if (this.effectiveUserData.canViewNotification === true) {
|
||||
params.push('notificationCount=' + encodeURIComponent(this.limoNotificationCount));
|
||||
}
|
||||
if (this.effectiveUserData.canViewApproval === true) {
|
||||
params.push('approvalRoutingCount=' + encodeURIComponent(this.approvalRoutingCount));
|
||||
}
|
||||
return params.length
|
||||
? '/limo/notification/notification?' + params.join('&')
|
||||
: '/limo/notification/notification';
|
||||
},
|
||||
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 : '';
|
||||
},
|
||||
parseNotificationCounts(res) {
|
||||
const data = res && res.data && typeof res.data === 'object' ? res.data : (res || {});
|
||||
return {
|
||||
count: Number(data.count ?? data.Count) || 0,
|
||||
notificationCount: Number(data.notificationCount ?? data.NotificationCount) || 0,
|
||||
approvalRoutingCount: Number(data.approvalRoutingCount ?? data.ApprovalRoutingCount) || 0,
|
||||
};
|
||||
},
|
||||
async fetchNotificationCount() {
|
||||
this.userData = uni.getStorageSync('userData');
|
||||
const userId = this.getUserIdFromUserData(this.userData);
|
||||
if (!userId) {
|
||||
this.notificationCount = 0;
|
||||
this.limoNotificationCount = 0;
|
||||
this.approvalRoutingCount = 0;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await countNotification({ userId });
|
||||
const counts = this.parseNotificationCounts(res);
|
||||
this.notificationCount = counts.count;
|
||||
this.limoNotificationCount = counts.notificationCount;
|
||||
this.approvalRoutingCount = counts.approvalRoutingCount;
|
||||
} catch (error) {
|
||||
console.error('[FindPlayer] countNotification failed', error);
|
||||
this.notificationCount = 0;
|
||||
this.limoNotificationCount = 0;
|
||||
this.approvalRoutingCount = 0;
|
||||
}
|
||||
},
|
||||
startNotificationCountTimer() {
|
||||
if (!this.notificationCountTimer) {
|
||||
this.notificationCountTimer = setInterval(() => {
|
||||
if (this.isFindPlayerActive) {
|
||||
this.getApporvalCount();
|
||||
this.fetchNotificationCount();
|
||||
}
|
||||
}, 30000); // 30秒
|
||||
}, 30000);
|
||||
}
|
||||
},
|
||||
stopApprovalCountTimer() {
|
||||
if (this.approvalCountTimer) {
|
||||
clearInterval(this.approvalCountTimer);
|
||||
this.approvalCountTimer = null;
|
||||
stopNotificationCountTimer() {
|
||||
if (this.notificationCountTimer) {
|
||||
clearInterval(this.notificationCountTimer);
|
||||
this.notificationCountTimer = null;
|
||||
}
|
||||
},
|
||||
// startApprovalCountTimer() {
|
||||
// if (!this.approvalCountTimer) {
|
||||
// this.approvalCountTimer = setInterval(() => {
|
||||
// // 双保险:非当前页不请求
|
||||
// if (this.isFindPlayerActive) {
|
||||
// // this.getApporvalCount();
|
||||
// }
|
||||
// }, 30000); // 30秒
|
||||
// }
|
||||
// },
|
||||
// stopApprovalCountTimer() {
|
||||
// if (this.approvalCountTimer) {
|
||||
// clearInterval(this.approvalCountTimer);
|
||||
// this.approvalCountTimer = null;
|
||||
// }
|
||||
// },
|
||||
// 数据方法
|
||||
async getProfileByPlayerId(){
|
||||
if(!this.searchPlayerId){
|
||||
@@ -155,7 +241,7 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
try{
|
||||
let params = {playerId:this.searchPlayerId,userId:this.userData.userId};
|
||||
let params = {playerId:this.searchPlayerId,userId:this.effectiveUserData.userId};
|
||||
const res = await playerLookup(params);
|
||||
if(res.success == true){
|
||||
if(res.data !== null){
|
||||
@@ -177,38 +263,39 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
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 getApporvalCount(){
|
||||
if (!this.isFindPlayerActive) return;
|
||||
try{
|
||||
let params = {};
|
||||
const res = await getApprovalCount(params);
|
||||
if(res.success == true){
|
||||
if(res.data !== null){
|
||||
this.countAp = res.data;
|
||||
}
|
||||
}
|
||||
}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);
|
||||
await this.writeLog(this.effectiveUserData.userId,"find_player","","[APP][findPlayer.vue][getProfileByPlayerId][Catch Exception]"+e.errMsg,request,response,1,false);
|
||||
}finally{
|
||||
uni.hideLoading();
|
||||
}
|
||||
},
|
||||
|
||||
// async getApporvalCount(){
|
||||
// if (!this.isFindPlayerActive) return;
|
||||
// try{
|
||||
// let params = {};
|
||||
// const res = await getApprovalCount(params);
|
||||
// if(res.success == true){
|
||||
// if(res.data !== null){
|
||||
// this.countAp = res.data;
|
||||
// }
|
||||
// }
|
||||
// }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.effectiveUserData.userId,"find_player","","[APP][findPlayer.vue][getProfileByPlayerId][Catch Exception]"+e.errMsg,request,response,1,false);
|
||||
// }finally{
|
||||
// uni.hideLoading();
|
||||
// }
|
||||
// },
|
||||
// 界面方法
|
||||
confirmMsg(){
|
||||
this.msgStr = '';
|
||||
this.showMsg = false;
|
||||
},
|
||||
toNotification(){
|
||||
this.navTo("/pages/notification/notification",0,false)
|
||||
this.navTo(this.buildNotificationUrl(['tab=1']),0,false)
|
||||
},
|
||||
clearSearchInput(){
|
||||
this.searchPlayerId = '';
|
||||
@@ -222,6 +309,24 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
wv.show();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
effectiveUserData() {
|
||||
return this.getEffectiveUserData(this.userData);
|
||||
},
|
||||
showNotificationBell() {
|
||||
return !!(
|
||||
this.effectiveUserData &&
|
||||
(this.effectiveUserData.canViewApproval === true ||
|
||||
this.effectiveUserData.canViewNotification === true)
|
||||
);
|
||||
},
|
||||
notificationBadgeText() {
|
||||
if (this.notificationCount > 99) {
|
||||
return '99+';
|
||||
}
|
||||
return String(this.notificationCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -232,4 +337,39 @@ import {playerLookup} from '../../api/mgmApi.js'
|
||||
border-style: solid;
|
||||
height:30px;
|
||||
}
|
||||
|
||||
.notification-bell-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 2px;
|
||||
margin-left: 3px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.notification-badge {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -5px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
padding: 0 4px;
|
||||
border-radius: 8px;
|
||||
background-color: #fa3534;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.notification-badge-text {
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,13 +44,13 @@
|
||||
|
||||
<view style="width: 100%;">
|
||||
<u-popup :show="showCommitment" :round="10" mode="center" customStyle="margin:0rpx 40rpx;">
|
||||
<view class="commitment-dialog" style="padding: 20px 22px 32px 22px;">
|
||||
<h4 class="commitment-title" style="font-size: 18px; display: flex; justify-content: center; padding: 7px;">{{commitTitle}}</h4>
|
||||
<view class="commitment-body" style="height:490px;font-size:13px;color:#333;">
|
||||
<view style="padding: 20px 22px 32px 22px;">
|
||||
<h4 style="font-size: 18px; display: flex; justify-content: center; padding: 7px;">{{commitTitle}}</h4>
|
||||
<view style="height:490px;font-size:13px;color:#333;">
|
||||
<view style="margin-bottom: 24rpx;line-height: 1.7;">{{commitmentText1}}</view>
|
||||
<view >{{commitmentText2}}</view>
|
||||
</view>
|
||||
<view class="commitment-footer">
|
||||
<view >
|
||||
<view @click="handleConfirm()" class="hz-btn hz-font-color-white hz-font-lg hz-font-bold hz-text-center" >{{confirmText}}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -141,6 +141,18 @@
|
||||
userName : userData.userName
|
||||
};
|
||||
const res = await userConfirm(params);
|
||||
// #ifdef APP-PLUS
|
||||
if (userData != null && userData.userId != null) {
|
||||
const app = getApp();
|
||||
if (app) {
|
||||
app.syncPushDeviceTokenFromNative();
|
||||
await app.syncPendingPushNotificationsFromNative();
|
||||
if (app.tryConsumePendingPushNavigation()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
this.checkInMacau();
|
||||
},
|
||||
checkInMacau(){
|
||||
@@ -331,6 +343,7 @@
|
||||
async goLogin(){
|
||||
await this.$onLaunched;
|
||||
await this.getSetting();
|
||||
|
||||
const userData = uni.getStorageSync("userData");
|
||||
let loginTag = false;
|
||||
uni.setStorageSync("todoSwitch","true");
|
||||
@@ -345,6 +358,7 @@
|
||||
|
||||
// 模拟开启,没有code,默认进来的情况
|
||||
if(this.siteData.mockSSO==true && this.code=='' && loginTag===false){
|
||||
|
||||
// 模拟SSO
|
||||
uni.redirectTo({
|
||||
url:'/pages/ssoLogin/ssoLogin'
|
||||
@@ -391,45 +405,6 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* #ifdef H5 */
|
||||
.commitment-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
max-height: calc(100vh - 48px);
|
||||
max-height: calc(100dvh - 48px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.commitment-title,
|
||||
.commitment-footer {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.commitment-body {
|
||||
min-height: 0;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
overflow-wrap: anywhere;
|
||||
padding-right: 10px;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
.commitment-body::-webkit-scrollbar {
|
||||
/* uView globally sets scrollbar width to 0 !important. */
|
||||
width: 2px !important;
|
||||
height: 2px !important;
|
||||
display: block;
|
||||
}
|
||||
.commitment-body::-webkit-scrollbar-track {
|
||||
background: #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.commitment-body::-webkit-scrollbar-thumb {
|
||||
background: #a67c30;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.commitment-footer {
|
||||
padding-top: 16px;
|
||||
}
|
||||
/* #endif */
|
||||
.commit-content{
|
||||
line-height: 1.5; /* 增加行间距提升可读性 */
|
||||
color: #333; /* 深灰提升阅读舒适度 */
|
||||
|
||||
@@ -1,235 +1,13 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-navbar
|
||||
:safeAreaInsetTop="true"
|
||||
:placeholder="true"
|
||||
:title="title"
|
||||
:fixed="true"
|
||||
:autoBack="true"
|
||||
leftIconColor="#000000"
|
||||
bgColor="#ffffff"
|
||||
titleStyle="font-weight:bold;color:#000000;"
|
||||
>
|
||||
<view style="margin-top:2px;margin-right:3px;" slot="right">
|
||||
<u-icon
|
||||
v-if="hasSelectedDate"
|
||||
@click="clearDateFilter"
|
||||
size="28px" name="../../static/images/filter-clear.svg"
|
||||
></u-icon>
|
||||
</view>
|
||||
</u-navbar>
|
||||
<!-- 搜索栏 -->
|
||||
<view class="hz-spacing hz-mr-t-20 hz-flex-row">
|
||||
<u-search :placeholder="searchHolder" v-model="searchInputStr" :showAction="false" bgColor="#ffffff" :label="searchLabel"
|
||||
borderColor="gray" style="padding-right: 8px" @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" style="justify-content: center;margin-top:80px;">
|
||||
<image src="/static/images/datanull.png" style="width:160px;height:160px;"></image>
|
||||
</view>
|
||||
<view class="hz-flex-row hz-font-bolder hz-font-md" style="justify-content: center;margin:20px;">
|
||||
{{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>
|
||||
|
||||
<u-calendar :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>
|
||||
</view>
|
||||
|
||||
<view></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getApprovalList} from '../../api/approvalApi.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title:this.$t("notification.pendingApproval"),
|
||||
searchInputStr:'',
|
||||
userData:'',
|
||||
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")
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
this.getApprovalList();
|
||||
},
|
||||
methods: {
|
||||
handleFilterDate(e) {
|
||||
this.selectedDate = e;
|
||||
this.showCalendar = false;
|
||||
|
||||
if (Array.isArray(this.selectedDate) && this.selectedDate.length > 0) {
|
||||
this.calendarIconColor = '#C39A4B';
|
||||
} else {
|
||||
this.calendarIconColor = '#000000';
|
||||
}
|
||||
|
||||
this.getApprovalList();
|
||||
},
|
||||
clearDateFilter() {
|
||||
this.selectedDate = [];
|
||||
this.calendarIconColor = '#000000';
|
||||
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(){
|
||||
uni.showLoading({
|
||||
title: this.$t("common.loading")
|
||||
});
|
||||
try{
|
||||
let params = {
|
||||
userId: this.userData.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;
|
||||
// 提取所有 playerId 到新的 playerList 并去重
|
||||
const playerIds = this.approvalList.map(item => item.playerId);
|
||||
const uniquePlayerIds = [...new Set(playerIds)];
|
||||
this.playerList = uniquePlayerIds.map(playerId => ({ playerId }));
|
||||
uni.setStorageSync("approvalPlayerList",this.playerList);
|
||||
this.showApprovalList = true;
|
||||
} else {
|
||||
this.showApprovalList = false;
|
||||
this.dataNull = this.$t("notification.noData");
|
||||
}
|
||||
}else{
|
||||
this.msgStr = res.message;
|
||||
this.showMsg = true;
|
||||
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);
|
||||
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();
|
||||
}
|
||||
},
|
||||
// 搜索玩家審批請求
|
||||
searchApprovalByPlayerId() {
|
||||
this.getApprovalList();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasSelectedDate() {
|
||||
return Array.isArray(this.selectedDate) && this.selectedDate.length > 0;
|
||||
}
|
||||
onLoad() {
|
||||
uni.redirectTo({
|
||||
url: '/limo/notification/notification?tab=1'
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.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>
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
const currentRoom = this.roomList[this.currentRoomIndex];
|
||||
if (currentRoom && currentRoom.id) {
|
||||
const approvalData = this.approvalGamingDataList.find(
|
||||
item => item.bookingId == currentRoom.id
|
||||
item => (item.bookingId != null ? item.bookingId : item.BookingId) == currentRoom.id
|
||||
);
|
||||
return approvalData || {};
|
||||
}
|
||||
@@ -401,6 +401,26 @@
|
||||
return value;
|
||||
},
|
||||
// 将形如:2025-03-18 +12 (W +2) | 2025-03-16 + 16 ... 按日期升序排序
|
||||
normalizeApprovalGamingData(item) {
|
||||
if (!item) return {};
|
||||
return {
|
||||
bookingId: item.bookingId != null ? item.bookingId : item.BookingId,
|
||||
playerId: item.playerId != null ? item.playerId : item.PlayerId,
|
||||
currentTripTheoWinAmount: item.currentTripTheoWinAmount != null ? item.currentTripTheoWinAmount : item.CurrentTripTheoWinAmount,
|
||||
last2DayTheoWinAmount: item.last2DayTheoWinAmount != null ? item.last2DayTheoWinAmount : item.Last2DayTheoWinAmount,
|
||||
r3TheoWin: item.r3TheoWin != null ? item.r3TheoWin : item.R3TheoWin,
|
||||
r3TPD: item.r3TPD != null ? item.r3TPD : item.R3TPD,
|
||||
r3ActualWin: item.r3ActualWin != null ? item.r3ActualWin : item.R3ActualWin,
|
||||
r6TheoWin: item.r6TheoWin != null ? item.r6TheoWin : item.R6TheoWin,
|
||||
r6TPD: item.r6TPD != null ? item.r6TPD : item.R6TPD,
|
||||
r6ActualWin: item.r6ActualWin != null ? item.r6ActualWin : item.R6ActualWin,
|
||||
r12TheoWin: item.r12TheoWin != null ? item.r12TheoWin : item.R12TheoWin,
|
||||
r12TPD: item.r12TPD != null ? item.r12TPD : item.R12TPD,
|
||||
r12ActualWin: item.r12ActualWin != null ? item.r12ActualWin : item.R12ActualWin,
|
||||
overlapBooking: item.overlapBooking != null ? item.overlapBooking : item.OverlapBooking,
|
||||
roomCount: item.roomCount != null ? item.roomCount : item.RoomCount
|
||||
};
|
||||
},
|
||||
sortRoomCountByDate(roomCountValue) {
|
||||
if (roomCountValue === null || roomCountValue === undefined || roomCountValue === '') return '-';
|
||||
const input = String(roomCountValue).trim();
|
||||
@@ -524,7 +544,9 @@
|
||||
if (res.success == true) {
|
||||
if (res.data !== null) {
|
||||
this.bookingListData = res.data.bookingsViewList;
|
||||
this.approvalGamingDataList = res.data.approvalGamingData || [];
|
||||
this.approvalGamingDataList = Array.isArray(res.data.approvalGamingData)
|
||||
? res.data.approvalGamingData.map(item => this.normalizeApprovalGamingData(item))
|
||||
: [];
|
||||
const routingList = res.data.cfgApprovalRoutingList;
|
||||
if (Array.isArray(routingList) && routingList.length > 0) {
|
||||
this.approvalRoutingList = routingList;
|
||||
|
||||
@@ -165,13 +165,11 @@
|
||||
propertyTabItemStyle() {
|
||||
return {
|
||||
height: '78rpx',
|
||||
padding: '0 24rpx',
|
||||
flexShrink: 0,
|
||||
padding: '0',
|
||||
};
|
||||
},
|
||||
propertyTabActiveStyle() {
|
||||
return {
|
||||
whiteSpace: 'nowrap',
|
||||
color: '#C39A4B',
|
||||
fontFamily: 'Inter-Bold',
|
||||
fontSize: '30rpx',
|
||||
@@ -180,7 +178,6 @@
|
||||
},
|
||||
propertyTabInactiveStyle() {
|
||||
return {
|
||||
whiteSpace: 'nowrap',
|
||||
color: '#111111',
|
||||
fontFamily: 'Inter-Bold',
|
||||
fontSize: '30rpx',
|
||||
@@ -197,12 +194,6 @@
|
||||
this.title = this.$t("roomCalendar.title");
|
||||
this.userData = uni.getStorageSync("userData");
|
||||
this.showTabbarByPermission(this.userData);
|
||||
if (!this.userData || this.userData.canViewCalendar !== true) {
|
||||
this.calendarNoPermission = true;
|
||||
this.calendarReady = false;
|
||||
return;
|
||||
}
|
||||
this.calendarNoPermission = false;
|
||||
this.loadPropertiesRoomTypes();
|
||||
},
|
||||
onUnload() {
|
||||
@@ -211,10 +202,6 @@
|
||||
},
|
||||
methods: {
|
||||
async loadPropertiesRoomTypes() {
|
||||
if (!this.userData || this.userData.canViewCalendar !== true) {
|
||||
this.showCalendarNoPermission();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.calendarReady = false;
|
||||
uni.showLoading({
|
||||
@@ -222,19 +209,14 @@
|
||||
});
|
||||
await this.loadCalendarSetting();
|
||||
const res = await getPropertiesRoomTypes({});
|
||||
if (this.isNoPermissionResponse(res)) {
|
||||
this.showCalendarNoPermission();
|
||||
return;
|
||||
}
|
||||
this.propertyList = Array.isArray(res && res.propertyList) ? res.propertyList : [];
|
||||
if (!this.propertyList.length) throw new Error('No calendar properties configured');
|
||||
this.propertyList = res.propertyList;
|
||||
this.selectedPropertyCode = this.propertyList[0].code;
|
||||
this.selectDefaultOptions();
|
||||
this.buildCalendar();
|
||||
await this.loadAvailabilityData();
|
||||
this.calendarRenderKey += 1;
|
||||
this.$nextTick(() => {
|
||||
this.calendarReady = !this.calendarNoPermission;
|
||||
this.calendarReady = true;
|
||||
});
|
||||
} catch (e) {
|
||||
uni.$u.toast(e.message || e.errMsg || 'Load property room types failed');
|
||||
@@ -437,7 +419,6 @@
|
||||
}));
|
||||
},
|
||||
refreshCalendar() {
|
||||
if (!this.userData || this.userData.canViewCalendar !== true || this.calendarNoPermission) return;
|
||||
this.ensureSelectedOptionsForRefresh(true);
|
||||
this.loadAvailabilityData();
|
||||
},
|
||||
@@ -520,7 +501,7 @@
|
||||
});
|
||||
},
|
||||
isNoPermissionResponse(res) {
|
||||
return res && res.success === false && (res.errorCode || res.code) === 'NO_PERMISSION';
|
||||
return res && res.success === false && res.errorCode === 'NO_PERMISSION';
|
||||
},
|
||||
showCalendarNoPermission() {
|
||||
this.availabilityMap = {};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<!--sso login-->
|
||||
<template>
|
||||
<view class="container">
|
||||
<web-view :src="url"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
@@ -11,26 +10,46 @@
|
||||
url:'',
|
||||
intervalId:null,
|
||||
newUrl:'',
|
||||
siteData:null
|
||||
siteData:null,
|
||||
samlWebview:null
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.siteData = uni.getStorageSync("siteData");
|
||||
if(options && options.uid && options.pwd){
|
||||
let username = options.uid.replaceAll(" ", "+");
|
||||
let password = options.pwd.replaceAll(" ", "+");
|
||||
this.url = this.siteData.internalUrl + this.siteData.apiPath + "/app/sso/login_saml_with_mfa?username="+encodeURIComponent(username)+"&password="+encodeURIComponent(password);
|
||||
}
|
||||
if (options && options.url){
|
||||
this.url = options.url;
|
||||
}
|
||||
this.listenUrl()
|
||||
},
|
||||
this.siteData = uni.getStorageSync("siteData");
|
||||
if(options && options.uid && options.pwd){
|
||||
let username = options.uid.replaceAll(" ", "+");
|
||||
let password = options.pwd.replaceAll(" ", "+");
|
||||
const loginUrl = this.siteData.internalUrl + this.siteData.apiPath + "/app/sso/login_saml_with_mfa?username="+encodeURIComponent(username)+"&password="+encodeURIComponent(password);
|
||||
this.url = loginUrl;
|
||||
this.openWebview(loginUrl);
|
||||
}
|
||||
if (options && options.url){
|
||||
this.url = options.url;
|
||||
this.openWebview(options.url);
|
||||
}
|
||||
this.listenUrl()
|
||||
},
|
||||
onShow() {
|
||||
this.siteData = uni.getStorageSync("siteData");
|
||||
},
|
||||
methods: {
|
||||
listenUrl() {
|
||||
openWebview(loginUrl) {
|
||||
// #ifdef APP-PLUS
|
||||
const wv = plus.webview.create(loginUrl, 'saml-login-webview', {
|
||||
'uni-app': 'none',
|
||||
top: '0px',
|
||||
bottom: '0px',
|
||||
additionalHttpHeaders: {
|
||||
'Origin': 'MGM_MCRM_APP'
|
||||
}
|
||||
});
|
||||
this.samlWebview = wv;
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
page.$getAppWebview().append(wv);
|
||||
// #endif
|
||||
},
|
||||
listenUrl() {
|
||||
var that = this;
|
||||
var count = 0;
|
||||
this.intervalId = setInterval(() => {
|
||||
@@ -75,6 +94,11 @@
|
||||
}
|
||||
},
|
||||
getCurrentUrl(){
|
||||
if (this.samlWebview) {
|
||||
var url = this.samlWebview.getURL();
|
||||
console.log("=======当前地址======", url);
|
||||
return url;
|
||||
}
|
||||
var pages = getCurrentPages();
|
||||
var page = pages[pages.length - 1];
|
||||
var currentWebview = page.$getAppWebview();
|
||||
|
||||
@@ -217,6 +217,7 @@
|
||||
|
||||
<script>
|
||||
import {logout} from '../../api/commonApi.js'
|
||||
import {updateDeviceToken} from '../../api/notificationApi.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -251,19 +252,6 @@
|
||||
single: "2021-04-3",
|
||||
today: new Date(),
|
||||
range: [],
|
||||
selectData:[{
|
||||
value: '1',
|
||||
label: 'Corso'
|
||||
},
|
||||
{
|
||||
value: '2',
|
||||
label: 'Mauve',
|
||||
},
|
||||
{
|
||||
value: '3',
|
||||
label: 'Calmi',
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
@@ -356,7 +344,7 @@
|
||||
showDelegate() {
|
||||
this.showMsgBox = true;
|
||||
},
|
||||
confirmLang(e){
|
||||
async confirmLang(e){
|
||||
uni.setLocale(e.value[0].code);
|
||||
this.$i18n.locale = e.value[0].code;
|
||||
this.lang = e.value[0].name;
|
||||
@@ -378,6 +366,10 @@
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
//这里加上接口,切换语言时 更新DeviceToken中的useLanguage字段
|
||||
const useLanguage = e.value[0].code === 'en'? 0 : 1;
|
||||
console.log(useLanguage);
|
||||
await updateDeviceToken({userId : this.userData.userId,useLanguage});
|
||||
// #endif
|
||||
this.showPicker = false;
|
||||
},
|
||||
|
||||
@@ -117,8 +117,6 @@
|
||||
<image
|
||||
v-show="index == 0 && currentIndex !== 2 && rowRecord.hasLimoRecord =='-1'"
|
||||
src="../../static/images/limo_warn.png" class="icon-img-limo"></image>
|
||||
<span v-show="index === 0 && rowRecord.isQueue"> (In Queue) </span>
|
||||
<span v-show="index === 0 && rowRecord.roomReady"> (Room Ready) </span>
|
||||
</span>
|
||||
</view>
|
||||
<!-- 直接使用v-if配合CSS动画类 -->
|
||||
@@ -237,7 +235,7 @@
|
||||
</u-col>
|
||||
<u-col span="6">
|
||||
<view class="hz-font-12px">R6M TPD: {{formatNumber(rowRecord.detailData.r6MTPD)}}</view>
|
||||
<view class="hz-font-12px">R6M Win: {{formatNumber(rowRecord.detailData.r6MWin)}}</view>
|
||||
<view class="hz-font-12px">R6M Win: {{formatNumber(rowRecord.detailData.r6MWin)}}</view>:
|
||||
<view class="hz-font-12px">R6M RI:
|
||||
{{getPercentFormat(rowRecord.detailData.r6MRIPercentage)}}</view>
|
||||
<view v-show="currentIndex === 2 && filterType ==='MASS'" class="hz-font-12px">R6M Theo : {{formatNumber(rowRecord.detailData.r6MTheo)}}
|
||||
@@ -320,9 +318,6 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="currentIndex === 2 && rowRecord.roomReady" class="hz-font-12px todo-description-text" >
|
||||
[Room Ready]
|
||||
</view>
|
||||
</uni-card>
|
||||
<template v-slot:right>
|
||||
<view v-if="currentIndex === 0" class="hz-flex-row" style="height:100%;align-items: center;margin-left:15px;"
|
||||
@@ -447,7 +442,7 @@
|
||||
getSetting,
|
||||
getExtendBooking
|
||||
} from '../../api/configApi.js';
|
||||
import { normalizeApiKeys } from '../../common/normalizeApiKeys.js';
|
||||
import { normalizeApiKeys, getApiRecords } from '../../common/normalizeApiKeys.js';
|
||||
export default {
|
||||
components: {
|
||||
mgmHeader, // 注册组件
|
||||
@@ -736,7 +731,12 @@
|
||||
return num?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") || "0";
|
||||
},
|
||||
formarHour(num){
|
||||
let hourStr = num > 1 ? num + ' hours' : num + ' hour';
|
||||
let hourStr = '';
|
||||
if(num!==null && num!==0){
|
||||
hourStr = num > 1 ? num + ' hours' : num + ' hour';
|
||||
}else{
|
||||
hourStr = 0 + ' hour'
|
||||
}
|
||||
return hourStr;
|
||||
},
|
||||
checkPassEtaTime(record) {
|
||||
@@ -1254,6 +1254,7 @@
|
||||
|
||||
if (requestSeq !== this.todoListRequestSeq) return;
|
||||
this.currentTask = null;
|
||||
|
||||
const records = res && res.data && Array.isArray(res.data.records) ? res.data.records : [];
|
||||
if (res && res.success == true && records.length > 0) {
|
||||
this.showTodoListView=true;
|
||||
@@ -1272,8 +1273,8 @@
|
||||
}))
|
||||
}));
|
||||
}else{
|
||||
const errorCode = res && (res.errorCode || res.code) ? String(res.errorCode || res.code).toUpperCase() : '';
|
||||
if(errorCode.indexOf('NO RECORD') !== -1 || (res && res.success == true && records.length === 0)){
|
||||
const errorCode = res && res.errorCode ? res.errorCode.toUpperCase() : "";
|
||||
if(errorCode.indexOf('NO RECORD') != -1 || (res && res.success == true && records.length == 0)){
|
||||
this.dataNull = this.$t("common.noRecord");
|
||||
}else{
|
||||
this.dataNull = this.$t("todo.returnError");
|
||||
@@ -1283,7 +1284,6 @@
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
if (requestSeq !== this.todoListRequestSeq) return;
|
||||
if (e.errMsg && e.errMsg.includes("abort")) {
|
||||
|
||||
} else if (e.data!==null&&e.data!==undefined&&e.data.message!==undefined){
|
||||
@@ -1330,6 +1330,7 @@
|
||||
const res = await getTodoDetail(params);
|
||||
if (res != null && res.success == true) {
|
||||
record.detailData = normalizeApiKeys(res.data);
|
||||
console.log(record.detailData.r3MTOD);
|
||||
if(record.detailData.descriptions!==null){
|
||||
for(let i=0;i<record.detailData.descriptions.length;i++){
|
||||
if(record.detailData.descriptions[i].itemRecordType == 'Offer'){
|
||||
@@ -1599,7 +1600,8 @@
|
||||
getETALable() {
|
||||
return function(record) {
|
||||
if (this.currentIndex !== 1 && this.currentIndex !== 2) {
|
||||
return record.eta;
|
||||
console.log(record);
|
||||
return record.eTA;
|
||||
} else if (record.bigLossFlag === 1) {
|
||||
return "BIGLOSS";
|
||||
} else if (record.bigWinFlag === 1) {
|
||||
@@ -1657,7 +1659,11 @@
|
||||
},
|
||||
getPercentFormat() {
|
||||
return function(val) {
|
||||
return Math.trunc((val * 100)) + "%";
|
||||
if(val){
|
||||
return Math.trunc((val * 100)) + "%";
|
||||
}else{
|
||||
return "0%"
|
||||
}
|
||||
}
|
||||
},
|
||||
getOtherDescription(){
|
||||
|
||||
@@ -373,6 +373,241 @@ page{
|
||||
border-top:1rpx solid #f4f4f4;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
/* bookingRecord.vue */
|
||||
.hz-nav-right {
|
||||
margin-top: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.hz-nav-right-group {
|
||||
border: 1rpx solid #ccc;
|
||||
border-radius: 14px;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
.hz-nav-right-divider {
|
||||
height: 20px;
|
||||
border-left: 1px solid #ccc;
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.hz-record-card {
|
||||
margin-top: 20rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hz-row-gap {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.hz-w-40 {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.hz-w-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.hz-w-55 {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.hz-w-60 {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.hz-w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hz-sharer-wrap {
|
||||
width: 50%;
|
||||
text-align: right;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.hz-sharer-tag {
|
||||
width: 40%;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.hz-limo-dropoff-wrap {
|
||||
padding-right: 50rpx;
|
||||
}
|
||||
|
||||
.hz-book-btn-wrap {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
.hz-limo-status {
|
||||
color: #ff9b9b;
|
||||
}
|
||||
|
||||
.hz-booking-type-row {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hz-booking-type-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.hz-booking-type-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* newLimo.vue */
|
||||
.limo-text-input[disabled],
|
||||
.limo-text-input--disabled {
|
||||
background-color: #F5F7FA;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
|
||||
.limo-booking-contact-row {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.limo-booking-contact-row + .limo-booking-contact-row {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.limo-booking-contact-label {
|
||||
color: #4D4D4D;
|
||||
align-self: center;
|
||||
flex: 0 0 38%;
|
||||
font-size: 26rpx;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.limo-booking-contact-controls {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
flex: 0 0 62%;
|
||||
flex-direction: row;
|
||||
gap: 2%;
|
||||
justify-content: flex-end;
|
||||
min-height: 36px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.limo-booking-contact-code-picker {
|
||||
align-self: stretch;
|
||||
flex: 0 0 38%;
|
||||
min-width: 0;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.limo-booking-contact-code-picker ::v-deep .lu-data-select-box {
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e5e5e5 !important;
|
||||
border-radius: 4rpx;
|
||||
box-sizing: border-box;
|
||||
color: #4D4D4D;
|
||||
display: flex;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
height: 36px !important;
|
||||
justify-content: center;
|
||||
min-height: 36px !important;
|
||||
padding: 0 5% !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.limo-booking-contact-code-picker ::v-deep .wid {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.limo-booking-contact-code-picker ::v-deep .lu-select-text,
|
||||
.limo-booking-contact-code-picker ::v-deep .lu-data-select-input,
|
||||
.limo-booking-contact-code-picker ::v-deep .placeholder-class {
|
||||
color: #4D4D4D !important;
|
||||
font-size: 24rpx !important;
|
||||
font-weight: 600 !important;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 0 !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.limo-booking-contact-code-picker ::v-deep .lu-data-select-close {
|
||||
margin-left: 4%;
|
||||
}
|
||||
|
||||
.limo-text-input.limo-booking-contact-phone {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 4rpx;
|
||||
box-sizing: border-box;
|
||||
color: #4D4D4D;
|
||||
flex: 0 0 47%;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
height: 36px;
|
||||
min-width: 0;
|
||||
min-height: 36px;
|
||||
padding: 0 3%;
|
||||
}
|
||||
|
||||
.limo-booking-contact-btn {
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 4rpx;
|
||||
box-sizing: border-box;
|
||||
color: #4D4D4D;
|
||||
display: flex;
|
||||
flex: 0 0 10%;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
height: 36px;
|
||||
justify-content: center;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.limo-booking-contact-disabled {
|
||||
background-color: #F5F7FA;
|
||||
color: #4D4D4D;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.limo-booking-contact-disabled ::v-deep .lu-data-select-box {
|
||||
background-color: #F5F7FA;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
|
||||
.limo-additional-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.limo-additional-options ::v-deep .u-checkbox-group {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.limo-additional-options .limo-booking-contact-row {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.limo-additional-options .limo-booking-contact-row + .limo-booking-contact-row {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* textarea */
|
||||
.uni-textarea{
|
||||
width:100%;
|
||||
@@ -446,3 +681,27 @@ page{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.find-player-ico {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
// spacing utilities
|
||||
@for $i from 0 through 2000 {
|
||||
.p-\[#{$i}\] { padding: #{$i}rpx !important; }
|
||||
.px-\[#{$i}\] { padding-left: #{$i}rpx !important; padding-right: #{$i}rpx !important; }
|
||||
.py-\[#{$i}\] { padding-top: #{$i}rpx !important; padding-bottom: #{$i}rpx !important; }
|
||||
.pt-\[#{$i}\] { padding-top: #{$i}rpx !important; }
|
||||
.pr-\[#{$i}\] { padding-right: #{$i}rpx !important; }
|
||||
.pb-\[#{$i}\] { padding-bottom: #{$i}rpx !important; }
|
||||
.pl-\[#{$i}\] { padding-left: #{$i}rpx !important; }
|
||||
.m-\[#{$i}\] { margin: #{$i}rpx !important; }
|
||||
.mx-\[#{$i}\] { margin-left: #{$i}rpx !important; margin-right: #{$i}rpx !important; }
|
||||
.my-\[#{$i}\] { margin-top: #{$i}rpx !important; margin-bottom: #{$i}rpx !important; }
|
||||
.mt-\[#{$i}\] { margin-top: #{$i}rpx !important; }
|
||||
.mr-\[#{$i}\] { margin-right: #{$i}rpx !important; }
|
||||
.mb-\[#{$i}\] { margin-bottom: #{$i}rpx !important; }
|
||||
.ml-\[#{$i}\] { margin-left: #{$i}rpx !important; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
.mandatory {
|
||||
color: #ff0000;
|
||||
margin-left: 3px;
|
||||
}
|
||||
.limo-field-label {
|
||||
font-size: 28rpx;
|
||||
color: #808080;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.limo-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.limo-form-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.limo-form-cell {
|
||||
width: 50%;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 16px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.limo-form-cell:nth-child(2n) {
|
||||
padding-right: 0;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.limo-form-col-full {
|
||||
margin-top: 0;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.limo-control-wrap {
|
||||
margin-top: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
.limo-tap-field {
|
||||
box-sizing: border-box;
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 16rpx;
|
||||
background-color: #fff;
|
||||
gap: 8px;
|
||||
}
|
||||
.limo-tap-field text {
|
||||
font-size: 13px;
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
}
|
||||
.limo-tap-field ::v-deep .u-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.limo-text-input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 16rpx;
|
||||
background-color: #fff;
|
||||
font-size: 13px;
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
}
|
||||
.limo-readonly-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.limo-page-with-tabbar .limo-text-input[disabled],
|
||||
.limo-page-with-tabbar .limo-text-input--disabled {
|
||||
background-color: #F5F7FA !important;
|
||||
border-color: #E4E7ED !important;
|
||||
color: #333333 !important;
|
||||
-webkit-text-fill-color: #333333;
|
||||
opacity: 1;
|
||||
}
|
||||
.limo-page-with-tabbar {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.limo-content-bottom-pad {
|
||||
padding-bottom: 64rpx;
|
||||
}
|
||||
.limo-label-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.limo-dropoff-block {
|
||||
margin-top: 0;
|
||||
}
|
||||
.limo-other-dropoff-field {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
.limo-remark-wrap {
|
||||
margin-top: 4px;
|
||||
padding-bottom: 16rpx;
|
||||
}
|
||||
.limo-hourly-row {
|
||||
margin-top: 4px;
|
||||
min-height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .lu-data-select .lu-data-select-box {
|
||||
height: 36px !important;
|
||||
min-height: 36px !important;
|
||||
box-sizing: border-box;
|
||||
padding: 0 7px !important;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-location-select.lu-data-select .lu-data-select-box {
|
||||
height: auto !important;
|
||||
min-height: 36px !important;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-location-select.lu-data-select .lu-data-select-content {
|
||||
min-height: 36px;
|
||||
align-items: stretch;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-location-select.lu-data-select .wid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-location-select.lu-data-select .lu-select-text {
|
||||
white-space: normal !important;
|
||||
word-break: break-word !important;
|
||||
overflow: visible !important;
|
||||
text-overflow: clip !important;
|
||||
line-height: 18px !important;
|
||||
padding: 8px 0 !important;
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-location-select.lu-data-select .lu-data-select-close {
|
||||
align-self: center;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .lu-data-select-box {
|
||||
height: auto !important;
|
||||
min-height: 36px !important;
|
||||
box-sizing: border-box;
|
||||
padding: 0 7px !important;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .lu-data-select-content {
|
||||
min-height: 36px;
|
||||
align-items: center;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .wid1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .lu-data-multiple {
|
||||
min-height: 36px;
|
||||
padding: 3px 0;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .lu-data-select-input-multiple {
|
||||
height: 24px !important;
|
||||
min-height: 24px !important;
|
||||
line-height: 24px !important;
|
||||
padding: 0 !important;
|
||||
margin: 2px !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
.limo-control-wrap ::v-deep .limo-greet-select.lu-data-select .lu-data-select-close {
|
||||
align-self: center;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .lu-select-text,
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .lu-data-select-input,
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .lu-data-select-input-multiple,
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .placeholder-class,
|
||||
.limo-remark-wrap ::v-deep .u-textarea__field,
|
||||
.limo-remark-wrap ::v-deep textarea {
|
||||
font-size: 13px !important;
|
||||
color: #333333 !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .arrow {
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-top: 6px solid #a8abb2;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-data-select .arrow::before {
|
||||
top: -6px;
|
||||
left: -5px;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid rgb(255, 255, 255);
|
||||
}
|
||||
.limo-remark-wrap ::v-deep .u-textarea {
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
.limo-remark-wrap ::v-deep .u-textarea__field,
|
||||
.limo-remark-wrap ::v-deep textarea {
|
||||
min-height: 160rpx !important;
|
||||
}
|
||||
|
||||
/* lu-data-select 下拉面板优化(仅作用于本页) */
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector {
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12), 0 2rpx 6rpx rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector .lu-popper__arrow {
|
||||
display: none;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector_bottom {
|
||||
top: calc(100% + 6rpx);
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector_top {
|
||||
bottom: calc(100% + 6rpx);
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector .lu-select__selector-item {
|
||||
padding: 10px 14px;
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector .lu-select__selector-item:first-child {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector .lu-select__selector-item:last-child {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.limo-page-with-tabbar ::v-deep .lu-select__selector .lu-select_selector-item_active {
|
||||
background-color: rgba(195, 154, 75, 0.1);
|
||||
color: #C39A4B;
|
||||
font-weight: 500;
|
||||
}
|
||||
.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-note {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.booking-popup-note-text {
|
||||
color: #333333;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.booking-popup-override {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.booking-popup-field-label {
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
}
|
||||
.booking-popup-override-select {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.booking-popup-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.booking-popup-button--primary {
|
||||
background-color: #C39A4B;
|
||||
}
|
||||
.booking-popup-button--secondary {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.booking-popup-card--criteria {
|
||||
min-height: 0;
|
||||
}
|
||||
.booking-popup-card--success {
|
||||
min-height: 0;
|
||||
}
|
||||
.booking-popup-title--criteria {
|
||||
line-height: 26px;
|
||||
}
|
||||
.booking-popup-title--success {
|
||||
line-height: 1.4;
|
||||
}
|
||||
.booking-popup-note--criteria {
|
||||
line-height: 22px;
|
||||
}
|
||||
.booking-popup-override--criteria {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.booking-popup-button--criteria {
|
||||
width: 100%;
|
||||
}
|
||||
.booking-popup-button--success {
|
||||
width: 100%;
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 865 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 747 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 672 B |
|
After Width: | Height: | Size: 846 B |
|
After Width: | Height: | Size: 883 B |
|
After Width: | Height: | Size: 630 B |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 692 B |
@@ -28,11 +28,6 @@ export default {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
},
|
||||
// 过滤输入框占位符;为空时沿用 placeholder
|
||||
filterPlaceholder: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
// 是否可清空
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
## 2.2.42(2025-08-20)
|
||||
- 修复 datetime-picker 小程序样式警告
|
||||
## 2.2.41(2025-08-20)
|
||||
- 修复 uni-datetime-picker组件时间对比报错问题
|
||||
## 2.2.40(2025-04-14)
|
||||
- 修复 绑定字符串值的时,日历面板选中状态未重置到默认值的问题
|
||||
## 2.2.39(2025-04-14)
|
||||
- 修复 在 iOS 微信小程序上type='daterange'时,传入'YYYY-MM-DD'格式不生效的问题
|
||||
|
||||
## 2.2.38(2024-10-15)
|
||||
- 修复 微信小程序中的getSystemInfo警告
|
||||
## 2.2.35(2024-09-21)
|
||||
- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
|
||||
## 2.2.34(2024-04-24)
|
||||
- 新增 日期点击事件,在点击日期时会触发该事件。
|
||||
## 2.2.33(2024-04-15)
|
||||
- 修复 抖音小程序事件传递失效bug
|
||||
## 2.2.32(2024-02-20)
|
||||
- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
|
||||
## 2.2.31(2024-02-20)
|
||||
- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
|
||||
## 2.2.30(2024-01-31)
|
||||
- 修复 隐藏“秒”时,在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
|
||||
## 2.2.29(2024-01-20)
|
||||
- 新增 show事件,弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694)
|
||||
## 2.2.28(2024-01-18)
|
||||
- 去除 noChange事件,当进行日期范围选择时,若只选了一天,则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815)
|
||||
## 2.2.27(2024-01-10)
|
||||
- 优化 增加noChange事件,当进行日期范围选择时,若有空值,则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815)
|
||||
## 2.2.26(2024-01-08)
|
||||
- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834)
|
||||
## 2.2.25(2023-10-18)
|
||||
- 修复 PC端初次修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||
## 2.2.24(2023-06-02)
|
||||
- 修复 部分情况修改时间,开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
|
||||
- 优化 当前月可以选择上月、下月的日期的Bug
|
||||
## 2.2.23(2023-05-02)
|
||||
- 修复 部分情况修改时间,开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||
- 修复 部分平台及设备第一次点击无法显示弹框的Bug
|
||||
- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.22(2023-03-30)
|
||||
- 修复 日历 picker 修改年月后,自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937)
|
||||
- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.21(2023-02-20)
|
||||
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
|
||||
## 2.2.20(2023-02-17)
|
||||
- 优化 值为空依然选中当天问题
|
||||
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
|
||||
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
|
||||
- 优化 字节小程序日期时间范围选择,底部日期换行的Bug
|
||||
## 2.2.19(2023-02-09)
|
||||
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
|
||||
## 2.2.18(2023-02-08)
|
||||
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
|
||||
- 优化 PC端输入日期格式错误时返回当前日期时间
|
||||
- 优化 PC端输入日期时间超出 start、end 限制的Bug
|
||||
- 优化 移动端日期时间范围用法时间展示不完整问题
|
||||
## 2.2.17(2023-02-04)
|
||||
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
|
||||
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
|
||||
## 2.2.16(2023-02-02)
|
||||
- 修复 字节小程序报错的Bug
|
||||
## 2.2.15(2023-02-02)
|
||||
- 修复 某些情况切换月份错误的Bug
|
||||
## 2.2.14(2023-01-30)
|
||||
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
|
||||
## 2.2.13(2023-01-10)
|
||||
- 修复 多次加载组件造成内存占用的Bug
|
||||
## 2.2.12(2022-12-01)
|
||||
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
|
||||
## 2.2.11(2022-09-19)
|
||||
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
|
||||
## 2.2.10(2022-09-19)
|
||||
- 修复 反向选择日期范围,日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
|
||||
## 2.2.9(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
## 2.2.8(2022-09-08)
|
||||
- 修复 close事件无效的Bug
|
||||
## 2.2.7(2022-09-05)
|
||||
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
|
||||
## 2.2.6(2022-06-30)
|
||||
- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
|
||||
## 2.2.5(2022-06-24)
|
||||
- 修复 日历顶部年月及底部确认未国际化的Bug
|
||||
## 2.2.4(2022-03-31)
|
||||
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
|
||||
## 2.2.3(2022-03-28)
|
||||
- 修复 Vue3 下动态赋值未响应的Bug
|
||||
## 2.2.2(2021-12-10)
|
||||
- 修复 clear-icon 属性在小程序平台不生效的Bug
|
||||
## 2.2.1(2021-12-10)
|
||||
- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的Bug
|
||||
## 2.2.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||
## 2.1.5(2021-11-09)
|
||||
- 新增 提供组件设计资源,组件样式调整
|
||||
## 2.1.4(2021-09-10)
|
||||
- 修复 hide-second 在移动端的Bug
|
||||
- 修复 单选赋默认值时,赋值日期未高亮的Bug
|
||||
- 修复 赋默认值时,移动端未正确显示时间的Bug
|
||||
## 2.1.3(2021-09-09)
|
||||
- 新增 hide-second 属性,支持只使用时分,隐藏秒
|
||||
## 2.1.2(2021-09-03)
|
||||
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
|
||||
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
|
||||
- 优化 调整字号大小,美化日历界面
|
||||
- 修复 因国际化导致的 placeholder 失效的Bug
|
||||
## 2.1.1(2021-08-24)
|
||||
- 新增 支持国际化
|
||||
- 优化 范围选择器在 pc 端过宽的问题
|
||||
## 2.1.0(2021-08-09)
|
||||
- 新增 适配 vue3
|
||||
## 2.0.19(2021-08-09)
|
||||
- 新增 支持作为 uni-forms 子组件相关功能
|
||||
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
|
||||
## 2.0.18(2021-08-05)
|
||||
- 修复 type 属性动态赋值无效的Bug
|
||||
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
|
||||
- 修复 组件未赋值时范围选左、右日历相同的Bug
|
||||
## 2.0.17(2021-08-04)
|
||||
- 修复 范围选未正确显示当前值的Bug
|
||||
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
|
||||
## 2.0.16(2021-07-21)
|
||||
- 新增 return-type 属性支持返回 date 日期对象
|
||||
## 2.0.15(2021-07-14)
|
||||
- 修复 单选日期类型,初始赋值后不在当前日历的Bug
|
||||
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
|
||||
- 优化 移动端移除显示框的清空按钮,无实际用途
|
||||
## 2.0.14(2021-07-14)
|
||||
- 修复 组件赋值为空,界面未更新的Bug
|
||||
- 修复 start 和 end 不能动态赋值的Bug
|
||||
- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的Bug
|
||||
## 2.0.13(2021-07-08)
|
||||
- 修复 范围选择不能动态赋值的Bug
|
||||
## 2.0.12(2021-07-08)
|
||||
- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
|
||||
## 2.0.11(2021-07-08)
|
||||
- 优化 弹出层在超出视窗边缘定位不准确的问题
|
||||
## 2.0.10(2021-07-08)
|
||||
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的Bug
|
||||
- 优化 弹出层在超出视窗边缘被遮盖的问题
|
||||
## 2.0.9(2021-07-07)
|
||||
- 新增 maskClick 事件
|
||||
- 修复 特殊情况日历 rpx 布局错误的Bug,rpx -> px
|
||||
- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
|
||||
## 2.0.8(2021-07-07)
|
||||
- 新增 日期时间显示框支持插槽
|
||||
## 2.0.7(2021-07-01)
|
||||
- 优化 添加 uni-icons 依赖
|
||||
## 2.0.6(2021-05-22)
|
||||
- 修复 图标在小程序上不显示的Bug
|
||||
- 优化 重命名引用组件,避免潜在组件命名冲突
|
||||
## 2.0.5(2021-05-20)
|
||||
- 优化 代码目录扁平化
|
||||
## 2.0.4(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 2.0.3(2021-05-10)
|
||||
- 修复 ios 下不识别 '-' 日期格式的Bug
|
||||
- 优化 pc 下弹出层添加边框和阴影
|
||||
## 2.0.2(2021-05-08)
|
||||
- 修复 在 admin 中获取弹出层定位错误的bug
|
||||
## 2.0.1(2021-05-08)
|
||||
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
|
||||
## 2.0.0(2021-04-30)
|
||||
- 支持日历形式的日期+时间的范围选择
|
||||
> 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
|
||||
## 1.0.6(2021-03-18)
|
||||
- 新增 hide-second 属性,时间支持仅选择时、分
|
||||
- 修复 选择跟显示的日期不一样的Bug
|
||||
- 修复 chang事件触发2次的Bug
|
||||
- 修复 分、秒 end 范围错误的Bug
|
||||
- 优化 更好的 nvue 适配
|
||||
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<view class="uni-calendar-item__weeks-box" :class="{
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked-x':weeks.afterMultiple,
|
||||
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
|
||||
<view class="uni-calendar-item__weeks-box-item" :class="{
|
||||
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
|
||||
'uni-calendar-item--checked-range-text': checkHover,
|
||||
'uni-calendar-item--before-checked':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked':weeks.afterMultiple,
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
}">
|
||||
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
|
||||
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
|
||||
</view>
|
||||
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
weeks: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
},
|
||||
handleMousemove(weeks) {
|
||||
this.$emit('handleMouse', weeks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" >
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 1px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-text {
|
||||
font-size: 14px;
|
||||
// font-family: Lato-Bold, Lato;
|
||||
font-weight: bold;
|
||||
color: darken($color: $uni-primary, $amount: 40%);
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
.uni-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: #dd524d;
|
||||
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
|
||||
color: #D1D1D1;
|
||||
}
|
||||
|
||||
.uni-calendar-item--today {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 17%;
|
||||
background-color: #dd524d;
|
||||
width:6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-calendar-item--extra {
|
||||
color: #dd524d;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
|
||||
background-color: $uni-primary;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--checked .uni-calendar-item--checked-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple {
|
||||
background-color: #F6F7FC;
|
||||
// color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple .uni-calendar-item--before-checked,
|
||||
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
|
||||
background-color: $uni-primary;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 3px solid #F6F7FC;
|
||||
}
|
||||
|
||||
.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
|
||||
.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--before-checked-x {
|
||||
border-top-left-radius: 50px;
|
||||
border-bottom-left-radius: 50px;
|
||||
box-sizing: border-box;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
|
||||
.uni-calendar-item--after-checked-x {
|
||||
border-top-right-radius: 50px;
|
||||
border-bottom-right-radius: 50px;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,947 @@
|
||||
<template>
|
||||
<view class="uni-calendar" @mouseleave="leaveCale">
|
||||
|
||||
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
|
||||
@click="maskClick"></view>
|
||||
|
||||
<view v-if="insert || show" class="uni-calendar__content"
|
||||
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
|
||||
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--left"></view>
|
||||
</view>
|
||||
|
||||
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
|
||||
<text
|
||||
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
|
||||
</picker>
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert" class="dialog-close" @click="maskClick">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-calendar__box">
|
||||
|
||||
<view v-if="showMonth" class="uni-calendar__box-bg">
|
||||
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
|
||||
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
|
||||
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
|
||||
:checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
|
||||
</calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
|
||||
style="padding: 0 80px;">
|
||||
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
|
||||
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
|
||||
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
|
||||
<view class="uni-date-changed--time-start">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
|
||||
</view>
|
||||
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
<view style="line-height: 50px;">
|
||||
<uni-icons type="arrowthinright" color="#999"></uni-icons>
|
||||
</view>
|
||||
<view class="uni-date-changed--time-end">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
|
||||
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
|
||||
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
Calendar,
|
||||
getDate,
|
||||
getTime
|
||||
} from './util.js';
|
||||
import calendarItem from './calendar-item.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(i18nMessages)
|
||||
|
||||
/**
|
||||
* Calendar 日历
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
|
||||
* @property {String} date 自定义当前时间,默认为今天
|
||||
* @property {String} startDate 日期选择范围-开始日期
|
||||
* @property {String} endDate 日期选择范围-结束日期
|
||||
* @property {Boolean} range 范围选择
|
||||
* @property {Boolean} insert = [true|false] 插入模式,默认为false
|
||||
* @value true 弹窗模式
|
||||
* @value false 插入模式
|
||||
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
|
||||
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||
* @property {Boolean} showMonth 是否选择月份为背景
|
||||
* @property {[String} defaultValue 选择器打开时默认显示的时间
|
||||
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||
* @event {Function} monthSwitch 切换月份时触发
|
||||
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
calendarItem,
|
||||
timePicker
|
||||
},
|
||||
|
||||
options: {
|
||||
// #ifdef MP-TOUTIAO
|
||||
virtualHost: false,
|
||||
// #endif
|
||||
// #ifndef MP-TOUTIAO
|
||||
virtualHost: true
|
||||
// #endif
|
||||
},
|
||||
props: {
|
||||
date: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
defTime: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
selectableTimes: {
|
||||
type: [Object],
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
startPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hasTime: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
pleStatus: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
before: '',
|
||||
after: '',
|
||||
data: [],
|
||||
fulldate: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Object, Array],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
weeks: [],
|
||||
calendar: {},
|
||||
nowDate: {},
|
||||
aniMaskShow: false,
|
||||
firstEnter: true,
|
||||
time: '',
|
||||
timeRange: {
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
tempSingleDate: '',
|
||||
tempRange: {
|
||||
before: '',
|
||||
after: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
date: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!this.range) {
|
||||
this.tempSingleDate = newVal
|
||||
setTimeout(() => {
|
||||
this.init(newVal)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
defTime: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!this.range) {
|
||||
this.time = newVal
|
||||
} else {
|
||||
this.timeRange.startTime = newVal.start
|
||||
this.timeRange.endTime = newVal.end
|
||||
}
|
||||
}
|
||||
},
|
||||
startDate(val) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if (!this.cale) {
|
||||
return
|
||||
}
|
||||
this.cale.setStartDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
endDate(val) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if (!this.cale) {
|
||||
return
|
||||
}
|
||||
this.cale.setEndDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
selected(newVal) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if (!this.cale) {
|
||||
return
|
||||
}
|
||||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
pleStatus: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
const {
|
||||
before,
|
||||
after,
|
||||
fulldate,
|
||||
which
|
||||
} = newVal
|
||||
this.tempRange.before = before
|
||||
this.tempRange.after = after
|
||||
setTimeout(() => {
|
||||
if (fulldate) {
|
||||
this.cale.setHoverMultiple(fulldate)
|
||||
if (before && after) {
|
||||
this.cale.lastHover = true
|
||||
if (this.rangeWithinMonth(after, before)) return
|
||||
this.setDate(before)
|
||||
} else {
|
||||
this.cale.setMultiple(fulldate)
|
||||
this.setDate(this.nowDate.fullDate)
|
||||
this.calendar.fullDate = ''
|
||||
this.cale.lastHover = false
|
||||
}
|
||||
} else {
|
||||
// 字节小程序 watch 早于 created
|
||||
if (!this.cale) {
|
||||
return
|
||||
}
|
||||
|
||||
this.cale.setDefaultMultiple(before, after)
|
||||
if (which === 'left' && before) {
|
||||
this.setDate(before)
|
||||
this.weeks = this.cale.weeks
|
||||
} else if (after) {
|
||||
this.setDate(after)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
this.cale.lastHover = true
|
||||
}
|
||||
}, 16)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
timepickerStartTime() {
|
||||
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
|
||||
return activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||
},
|
||||
timepickerEndTime() {
|
||||
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
|
||||
return activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||
},
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
selectDateText() {
|
||||
return t("uni-datetime-picker.selectDate")
|
||||
},
|
||||
startDateText() {
|
||||
return this.startPlaceholder || t("uni-datetime-picker.startDate")
|
||||
},
|
||||
endDateText() {
|
||||
return this.endPlaceholder || t("uni-datetime-picker.endDate")
|
||||
},
|
||||
okText() {
|
||||
return t("uni-datetime-picker.ok")
|
||||
},
|
||||
yearText() {
|
||||
return t("uni-datetime-picker.year")
|
||||
},
|
||||
monthText() {
|
||||
return t("uni-datetime-picker.month")
|
||||
},
|
||||
MONText() {
|
||||
return t("uni-calender.MON")
|
||||
},
|
||||
TUEText() {
|
||||
return t("uni-calender.TUE")
|
||||
},
|
||||
WEDText() {
|
||||
return t("uni-calender.WED")
|
||||
},
|
||||
THUText() {
|
||||
return t("uni-calender.THU")
|
||||
},
|
||||
FRIText() {
|
||||
return t("uni-calender.FRI")
|
||||
},
|
||||
SATText() {
|
||||
return t("uni-calender.SAT")
|
||||
},
|
||||
SUNText() {
|
||||
return t("uni-calender.SUN")
|
||||
},
|
||||
confirmText() {
|
||||
return t("uni-calender.confirm")
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 获取日历方法实例
|
||||
this.cale = new Calendar({
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
})
|
||||
// 选中某一天
|
||||
this.init(this.date)
|
||||
},
|
||||
methods: {
|
||||
leaveCale() {
|
||||
this.firstEnter = true
|
||||
},
|
||||
handleMouse(weeks) {
|
||||
if (weeks.disable) return
|
||||
if (this.cale.lastHover) return
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.cale.multipleStatus
|
||||
if (!before) return
|
||||
this.calendar = weeks
|
||||
// 设置范围选
|
||||
this.cale.setHoverMultiple(this.calendar.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
// hover时,进入一个日历,更新另一个
|
||||
if (this.firstEnter) {
|
||||
this.$emit('firstEnterCale', this.cale.multipleStatus)
|
||||
this.firstEnter = false
|
||||
}
|
||||
},
|
||||
rangeWithinMonth(A, B) {
|
||||
const [yearA, monthA] = A.split('-')
|
||||
const [yearB, monthB] = B.split('-')
|
||||
return yearA === yearB && monthA === monthB
|
||||
},
|
||||
// 蒙版点击事件
|
||||
maskClick() {
|
||||
this.close()
|
||||
this.$emit('maskClose')
|
||||
},
|
||||
|
||||
clearCalender() {
|
||||
if (this.range) {
|
||||
this.timeRange.startTime = ''
|
||||
this.timeRange.endTime = ''
|
||||
this.tempRange.before = ''
|
||||
this.tempRange.after = ''
|
||||
this.cale.multipleStatus.before = ''
|
||||
this.cale.multipleStatus.after = ''
|
||||
this.cale.multipleStatus.data = []
|
||||
this.cale.lastHover = false
|
||||
} else {
|
||||
this.time = ''
|
||||
this.tempSingleDate = ''
|
||||
}
|
||||
this.calendar.fullDate = ''
|
||||
this.setDate(new Date())
|
||||
},
|
||||
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.setDate(value)
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if (!this.cale) {
|
||||
return
|
||||
}
|
||||
this.cale.setDate(date || new Date())
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
this.calendar = {
|
||||
...this.nowDate
|
||||
}
|
||||
if (!date) {
|
||||
// 优化date为空默认不选中今天
|
||||
this.calendar.fullDate = ''
|
||||
if (this.defaultValue && !this.range) {
|
||||
// 暂时只支持移动端非范围选择
|
||||
const defaultDate = new Date(this.defaultValue)
|
||||
const fullDate = getDate(defaultDate)
|
||||
const year = defaultDate.getFullYear()
|
||||
const month = defaultDate.getMonth() + 1
|
||||
const date = defaultDate.getDate()
|
||||
const day = defaultDate.getDay()
|
||||
this.calendar = {
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
day
|
||||
},
|
||||
this.tempSingleDate = fullDate
|
||||
this.time = getTime(defaultDate, this.hideSecond)
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 打开日历弹窗
|
||||
*/
|
||||
open() {
|
||||
// 弹窗模式并且清理数据
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanMultipleStatus()
|
||||
this.init(this.date)
|
||||
}
|
||||
this.show = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.aniMaskShow = true
|
||||
}, 50)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 关闭日历弹窗
|
||||
*/
|
||||
close() {
|
||||
this.aniMaskShow = false
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$emit('close')
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
confirm() {
|
||||
this.setEmit('confirm')
|
||||
this.close()
|
||||
},
|
||||
/**
|
||||
* 变化触发
|
||||
*/
|
||||
change(isSingleChange) {
|
||||
if (!this.insert && !isSingleChange) return
|
||||
this.setEmit('change')
|
||||
},
|
||||
/**
|
||||
* 选择月份触发
|
||||
*/
|
||||
monthSwitch() {
|
||||
let {
|
||||
year,
|
||||
month
|
||||
} = this.nowDate
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month: Number(month)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 派发事件
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
if (!this.range) {
|
||||
if (!this.calendar.fullDate) {
|
||||
this.calendar = this.cale.getInfo(new Date())
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
}
|
||||
if (this.hasTime && !this.time) {
|
||||
this.time = getTime(new Date(), this.hideSecond)
|
||||
}
|
||||
}
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
range: this.cale.multipleStatus,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
time: this.time,
|
||||
timeRange: this.timeRange,
|
||||
fulldate: fullDate,
|
||||
extraInfo: extraInfo || {}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 选择天触发
|
||||
* @param {Object} weeks
|
||||
*/
|
||||
choiceDate(weeks) {
|
||||
if (weeks.disable) return
|
||||
this.calendar = weeks
|
||||
this.calendar.userChecked = true
|
||||
// 设置多选
|
||||
this.cale.setMultiple(this.calendar.fullDate, true)
|
||||
this.weeks = this.cale.weeks
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
|
||||
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
|
||||
if (beforeDate > afterDate && afterDate) {
|
||||
this.tempRange.before = this.cale.multipleStatus.after
|
||||
this.tempRange.after = this.cale.multipleStatus.before
|
||||
} else {
|
||||
this.tempRange.before = this.cale.multipleStatus.before
|
||||
this.tempRange.after = this.cale.multipleStatus.after
|
||||
}
|
||||
this.change(true)
|
||||
},
|
||||
changeMonth(type) {
|
||||
let newDate
|
||||
if (type === 'pre') {
|
||||
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
|
||||
} else if (type === 'next') {
|
||||
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
|
||||
}
|
||||
|
||||
this.setDate(newDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-calendar {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.uni-calendar__mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.3s;
|
||||
opacity: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--mask-show {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.uni-calendar--fixed {
|
||||
position: fixed;
|
||||
bottom: calc(var(--window-bottom));
|
||||
left: 0;
|
||||
right: 0;
|
||||
transition-property: transform;
|
||||
transition-duration: 0.3s;
|
||||
transform: translateY(460px);
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--ani-show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-calendar__content {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar__content-mobile {
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.uni-calendar__header {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__header-mobile {
|
||||
padding: 10px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-top {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border-top-color: rgba(0, 0, 0, 0.4);
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-width {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 25rpx;
|
||||
padding: 0 5px;
|
||||
padding-left: 10px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 12px;
|
||||
border-top-left-radius: 25px;
|
||||
border-bottom-left-radius: 25px;
|
||||
color: #fff;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.uni-calendar__header-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.uni-calendar__button-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: 14px;
|
||||
color: $uni-primary;
|
||||
/* #ifndef APP-NVUE */
|
||||
letter-spacing: 3px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-left-color: #808080;
|
||||
border-left-style: solid;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #555555;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--left {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-calendar--right {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
|
||||
.uni-calendar__weeks {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
border-bottom-color: #F5F5F5;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day-text {
|
||||
font-size: 12px;
|
||||
color: #B2B2B2;
|
||||
}
|
||||
|
||||
.uni-calendar__box {
|
||||
position: relative;
|
||||
// padding: 0 10px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg-text {
|
||||
font-size: 200px;
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-date-changed {
|
||||
padding: 0 10px;
|
||||
// line-height: 50px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-top-color: #DCDCDC;
|
||||
;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-date-btn--ok {
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-start {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-end {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-date {
|
||||
color: #999;
|
||||
line-height: 50px;
|
||||
/* #ifdef MP-TOUTIAO */
|
||||
font-size: 16px;
|
||||
/* #endif */
|
||||
margin-right: 5px;
|
||||
// opacity: 0.6;
|
||||
}
|
||||
|
||||
.time-picker-style {
|
||||
// width: 62px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.mr-10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 25px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dialog-close-plus {
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background-color: #737987;
|
||||
border-radius: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.dialog-close-rotate {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-datetime-picker--btn {
|
||||
border-radius: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background-color: $uni-primary;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-datetime-picker--btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "select date",
|
||||
"uni-datetime-picker.selectTime": "select time",
|
||||
"uni-datetime-picker.selectDateTime": "select date and time",
|
||||
"uni-datetime-picker.startDate": "start date",
|
||||
"uni-datetime-picker.endDate": "end date",
|
||||
"uni-datetime-picker.startTime": "start time",
|
||||
"uni-datetime-picker.endTime": "end time",
|
||||
"uni-datetime-picker.ok": "ok",
|
||||
"uni-datetime-picker.clear": "clear",
|
||||
"uni-datetime-picker.cancel": "cancel",
|
||||
"uni-datetime-picker.year": "-",
|
||||
"uni-datetime-picker.month": "",
|
||||
"uni-calender.MON": "MON",
|
||||
"uni-calender.TUE": "TUE",
|
||||
"uni-calender.WED": "WED",
|
||||
"uni-calender.THU": "THU",
|
||||
"uni-calender.FRI": "FRI",
|
||||
"uni-calender.SAT": "SAT",
|
||||
"uni-calender.SUN": "SUN",
|
||||
"uni-calender.confirm": "confirm"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import en from './en.json'
|
||||
import zhHans from './zh-Hans.json'
|
||||
import zhHant from './zh-Hant.json'
|
||||
export default {
|
||||
en,
|
||||
'zh-Hans': zhHans,
|
||||
'zh-Hant': zhHant
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "选择日期",
|
||||
"uni-datetime-picker.selectTime": "选择时间",
|
||||
"uni-datetime-picker.selectDateTime": "选择日期时间",
|
||||
"uni-datetime-picker.startDate": "开始日期",
|
||||
"uni-datetime-picker.endDate": "结束日期",
|
||||
"uni-datetime-picker.startTime": "开始时间",
|
||||
"uni-datetime-picker.endTime": "结束时间",
|
||||
"uni-datetime-picker.ok": "确定",
|
||||
"uni-datetime-picker.clear": "清除",
|
||||
"uni-datetime-picker.cancel": "取消",
|
||||
"uni-datetime-picker.year": "年",
|
||||
"uni-datetime-picker.month": "月",
|
||||
"uni-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六",
|
||||
"uni-calender.confirm": "确认"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "選擇日期",
|
||||
"uni-datetime-picker.selectTime": "選擇時間",
|
||||
"uni-datetime-picker.selectDateTime": "選擇日期時間",
|
||||
"uni-datetime-picker.startDate": "開始日期",
|
||||
"uni-datetime-picker.endDate": "結束日期",
|
||||
"uni-datetime-picker.startTime": "開始时间",
|
||||
"uni-datetime-picker.endTime": "結束时间",
|
||||
"uni-datetime-picker.ok": "確定",
|
||||
"uni-datetime-picker.clear": "清除",
|
||||
"uni-datetime-picker.cancel": "取消",
|
||||
"uni-datetime-picker.year": "年",
|
||||
"uni-datetime-picker.month": "月",
|
||||
"uni-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六",
|
||||
"uni-calender.confirm": "確認"
|
||||
}
|
||||
@@ -0,0 +1,940 @@
|
||||
<template>
|
||||
<view class="uni-datetime-picker">
|
||||
<view @click="initTimePicker">
|
||||
<slot>
|
||||
<view class="uni-datetime-picker-timebox-pointer"
|
||||
:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
|
||||
<text class="uni-datetime-picker-text">{{time}}</text>
|
||||
<view v-if="!time" class="uni-datetime-picker-time">
|
||||
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
|
||||
<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
|
||||
:style="fixNvueBug">
|
||||
<view class="uni-title">
|
||||
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||
</view>
|
||||
<view v-if="dateShow" class="uni-datetime-picker__container-box">
|
||||
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
|
||||
@change="bindDateChange">
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<!-- 兼容 nvue 不支持伪类 -->
|
||||
<text class="uni-datetime-picker-sign sign-left">-</text>
|
||||
<text class="uni-datetime-picker-sign sign-right">-</text>
|
||||
</view>
|
||||
<view v-if="timeShow" class="uni-datetime-picker__container-box">
|
||||
<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
|
||||
:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column v-if="!hideSecond">
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<!-- 兼容 nvue 不支持伪类 -->
|
||||
<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
|
||||
<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
|
||||
</view>
|
||||
<view class="uni-datetime-picker-btn">
|
||||
<view @click="clearTime">
|
||||
<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
|
||||
</view>
|
||||
<view class="uni-datetime-picker-btn-group">
|
||||
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
|
||||
<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
|
||||
</view>
|
||||
<view @click="setTime">
|
||||
<text class="uni-datetime-picker-btn-text">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(i18nMessages)
|
||||
import {
|
||||
fixIosDateFormat
|
||||
} from './util'
|
||||
|
||||
/**
|
||||
* DatetimePicker 时间选择器
|
||||
* @description 可以同时选择日期和时间的选择器
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
||||
* @property {String} type = [datetime | date | time] 显示模式
|
||||
* @property {Boolean} multiple = [true|false] 是否多选
|
||||
* @property {String|Number} value 默认值
|
||||
* @property {String|Number} start 起始日期或时间
|
||||
* @property {String|Number} end 起始日期或时间
|
||||
* @property {String} return-type = [timestamp | string]
|
||||
* @event {Function} change 选中发生变化触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'UniDatetimePicker',
|
||||
data() {
|
||||
return {
|
||||
indicatorStyle: `height: 50px;`,
|
||||
visible: false,
|
||||
fixNvueBug: {},
|
||||
dateShow: true,
|
||||
timeShow: true,
|
||||
title: '日期和时间',
|
||||
// 输入框当前时间
|
||||
time: '',
|
||||
// 当前的年月日时分秒
|
||||
year: 1920,
|
||||
month: 0,
|
||||
day: 0,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
// 起始时间
|
||||
startYear: 1920,
|
||||
startMonth: 1,
|
||||
startDay: 1,
|
||||
startHour: 0,
|
||||
startMinute: 0,
|
||||
startSecond: 0,
|
||||
// 结束时间
|
||||
endYear: 2120,
|
||||
endMonth: 12,
|
||||
endDay: 31,
|
||||
endHour: 23,
|
||||
endMinute: 59,
|
||||
endSecond: 59,
|
||||
}
|
||||
},
|
||||
options: {
|
||||
// #ifdef MP-TOUTIAO
|
||||
virtualHost: false,
|
||||
// #endif
|
||||
// #ifndef MP-TOUTIAO
|
||||
virtualHost: true
|
||||
// #endif
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'datetime'
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
start: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
end: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
returnType: {
|
||||
type: String,
|
||||
default: 'string'
|
||||
},
|
||||
disabled: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: [Boolean, String],
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// #ifndef VUE3
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
this.parseValue(Date.now())
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
modelValue: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
this.parseValue(Date.now())
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
// #endif
|
||||
type: {
|
||||
handler(newValue) {
|
||||
if (newValue === 'date') {
|
||||
this.dateShow = true
|
||||
this.timeShow = false
|
||||
this.title = '日期'
|
||||
} else if (newValue === 'time') {
|
||||
this.dateShow = false
|
||||
this.timeShow = true
|
||||
this.title = '时间'
|
||||
} else {
|
||||
this.dateShow = true
|
||||
this.timeShow = true
|
||||
this.title = '日期和时间'
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
start: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
end: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
// 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||
months(newVal) {
|
||||
this.checkValue('month', this.month, newVal)
|
||||
},
|
||||
days(newVal) {
|
||||
this.checkValue('day', this.day, newVal)
|
||||
},
|
||||
hours(newVal) {
|
||||
this.checkValue('hour', this.hour, newVal)
|
||||
},
|
||||
minutes(newVal) {
|
||||
this.checkValue('minute', this.minute, newVal)
|
||||
},
|
||||
seconds(newVal) {
|
||||
this.checkValue('second', this.second, newVal)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前年、月、日、时、分、秒选择范围
|
||||
years() {
|
||||
return this.getCurrentRange('year')
|
||||
},
|
||||
|
||||
months() {
|
||||
return this.getCurrentRange('month')
|
||||
},
|
||||
|
||||
days() {
|
||||
return this.getCurrentRange('day')
|
||||
},
|
||||
|
||||
hours() {
|
||||
return this.getCurrentRange('hour')
|
||||
},
|
||||
|
||||
minutes() {
|
||||
return this.getCurrentRange('minute')
|
||||
},
|
||||
|
||||
seconds() {
|
||||
return this.getCurrentRange('second')
|
||||
},
|
||||
|
||||
// picker 当前值数组
|
||||
ymd() {
|
||||
return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
|
||||
},
|
||||
hms() {
|
||||
return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
|
||||
},
|
||||
|
||||
// 当前 date 是 start
|
||||
currentDateIsStart() {
|
||||
return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
|
||||
},
|
||||
|
||||
// 当前 date 是 end
|
||||
currentDateIsEnd() {
|
||||
return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
|
||||
},
|
||||
|
||||
// 当前年、月、日、时、分、秒的最小值和最大值
|
||||
minYear() {
|
||||
return this.startYear
|
||||
},
|
||||
maxYear() {
|
||||
return this.endYear
|
||||
},
|
||||
minMonth() {
|
||||
if (this.year === this.startYear) {
|
||||
return this.startMonth
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
maxMonth() {
|
||||
if (this.year === this.endYear) {
|
||||
return this.endMonth
|
||||
} else {
|
||||
return 12
|
||||
}
|
||||
},
|
||||
minDay() {
|
||||
if (this.year === this.startYear && this.month === this.startMonth) {
|
||||
return this.startDay
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
maxDay() {
|
||||
if (this.year === this.endYear && this.month === this.endMonth) {
|
||||
return this.endDay
|
||||
} else {
|
||||
return this.daysInMonth(this.year, this.month)
|
||||
}
|
||||
},
|
||||
minHour() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart) {
|
||||
return this.startHour
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
return this.startHour
|
||||
}
|
||||
},
|
||||
maxHour() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd) {
|
||||
return this.endHour
|
||||
} else {
|
||||
return 23
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
return this.endHour
|
||||
}
|
||||
},
|
||||
minMinute() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart && this.hour === this.startHour) {
|
||||
return this.startMinute
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.startHour) {
|
||||
return this.startMinute
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
maxMinute() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd && this.hour === this.endHour) {
|
||||
return this.endMinute
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.endHour) {
|
||||
return this.endMinute
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
},
|
||||
minSecond() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
|
||||
return this.startSecond
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.startHour && this.minute === this.startMinute) {
|
||||
return this.startSecond
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
maxSecond() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
|
||||
return this.endSecond
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.endHour && this.minute === this.endMinute) {
|
||||
return this.endSecond
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
selectTimeText() {
|
||||
return t("uni-datetime-picker.selectTime")
|
||||
},
|
||||
okText() {
|
||||
return t("uni-datetime-picker.ok")
|
||||
},
|
||||
clearText() {
|
||||
return t("uni-datetime-picker.clear")
|
||||
},
|
||||
cancelText() {
|
||||
return t("uni-datetime-picker.cancel")
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// #ifdef APP-NVUE
|
||||
const res = uni.getSystemInfoSync();
|
||||
this.fixNvueBug = {
|
||||
top: res.windowHeight / 2,
|
||||
left: res.windowWidth / 2
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* @param {Object} item
|
||||
* 小于 10 在前面加个 0
|
||||
*/
|
||||
|
||||
lessThanTen(item) {
|
||||
return item < 10 ? '0' + item : item
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析时分秒字符串,例如:00:00:00
|
||||
* @param {String} timeString
|
||||
*/
|
||||
parseTimeType(timeString) {
|
||||
if (timeString) {
|
||||
let timeArr = timeString.split(':')
|
||||
this.hour = Number(timeArr[0])
|
||||
this.minute = Number(timeArr[1])
|
||||
this.second = Number(timeArr[2])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
|
||||
* @param {String | Number} datetime
|
||||
*/
|
||||
initPickerValue(datetime) {
|
||||
let defaultValue = null
|
||||
if (datetime) {
|
||||
defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
|
||||
} else {
|
||||
defaultValue = Date.now()
|
||||
defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
|
||||
}
|
||||
this.parseValue(defaultValue)
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始值规则:
|
||||
* - 用户设置初始值 value
|
||||
* - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
|
||||
* - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
|
||||
* - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
|
||||
* - 无起始终止时间,则初始值为 value
|
||||
* - 无初始值 value,则初始值为当前本地时间 Date.now()
|
||||
* @param {Object} value
|
||||
* @param {Object} dateBase
|
||||
*/
|
||||
compareValueWithStartAndEnd(value, start, end) {
|
||||
let winner = null
|
||||
value = this.superTimeStamp(value)
|
||||
start = this.superTimeStamp(start)
|
||||
end = this.superTimeStamp(end)
|
||||
|
||||
if (start && end) {
|
||||
if (value < start) {
|
||||
winner = new Date(start)
|
||||
} else if (value > end) {
|
||||
winner = new Date(end)
|
||||
} else {
|
||||
winner = new Date(value)
|
||||
}
|
||||
} else if (start && !end) {
|
||||
winner = start <= value ? new Date(value) : new Date(start)
|
||||
} else if (!start && end) {
|
||||
winner = value <= end ? new Date(value) : new Date(end)
|
||||
} else {
|
||||
winner = new Date(value)
|
||||
}
|
||||
|
||||
return winner
|
||||
},
|
||||
|
||||
/**
|
||||
* 转换为可比较的时间戳,接受日期、时分秒、时间戳
|
||||
* @param {Object} value
|
||||
*/
|
||||
superTimeStamp(value) {
|
||||
let dateBase = ''
|
||||
if (this.type === 'time' && value && typeof value === 'string') {
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = now.getMonth() + 1
|
||||
const day = now.getDate()
|
||||
dateBase = year + '/' + month + '/' + day + ' '
|
||||
}
|
||||
if (Number(value)) {
|
||||
value = parseInt(value)
|
||||
dateBase = 0
|
||||
}
|
||||
return this.createTimeStamp(dateBase + value)
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析默认值 value,字符串、时间戳
|
||||
* @param {Object} defaultTime
|
||||
*/
|
||||
parseValue(value) {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (this.type === 'time' && typeof value === "string") {
|
||||
this.parseTimeType(value)
|
||||
} else {
|
||||
let defaultDate = null
|
||||
defaultDate = new Date(value)
|
||||
if (this.type !== 'time') {
|
||||
this.year = defaultDate.getFullYear()
|
||||
this.month = defaultDate.getMonth() + 1
|
||||
this.day = defaultDate.getDate()
|
||||
}
|
||||
if (this.type !== 'date') {
|
||||
this.hour = defaultDate.getHours()
|
||||
this.minute = defaultDate.getMinutes()
|
||||
this.second = defaultDate.getSeconds()
|
||||
}
|
||||
}
|
||||
if (this.hideSecond) {
|
||||
this.second = 0
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析可选择时间范围 start、end,年月日字符串、时间戳
|
||||
* @param {Object} defaultTime
|
||||
*/
|
||||
parseDatetimeRange(point, pointType) {
|
||||
// 时间为空,则重置为初始值
|
||||
if (!point) {
|
||||
if (pointType === 'start') {
|
||||
this.startYear = 1920
|
||||
this.startMonth = 1
|
||||
this.startDay = 1
|
||||
this.startHour = 0
|
||||
this.startMinute = 0
|
||||
this.startSecond = 0
|
||||
}
|
||||
if (pointType === 'end') {
|
||||
this.endYear = 2120
|
||||
this.endMonth = 12
|
||||
this.endDay = 31
|
||||
this.endHour = 23
|
||||
this.endMinute = 59
|
||||
this.endSecond = 59
|
||||
}
|
||||
return
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
const pointArr = point.split(':')
|
||||
this[pointType + 'Hour'] = Number(pointArr[0])
|
||||
this[pointType + 'Minute'] = Number(pointArr[1])
|
||||
this[pointType + 'Second'] = Number(pointArr[2])
|
||||
} else {
|
||||
if (!point) {
|
||||
pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
|
||||
return
|
||||
}
|
||||
if (Number(point)) {
|
||||
point = parseInt(point)
|
||||
}
|
||||
// datetime 的 end 没有时分秒, 则不限制
|
||||
const hasTime = /[0-9]:[0-9]/
|
||||
if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
|
||||
point)) {
|
||||
point = point + ' 23:59:59'
|
||||
}
|
||||
const pointDate = new Date(point)
|
||||
this[pointType + 'Year'] = pointDate.getFullYear()
|
||||
this[pointType + 'Month'] = pointDate.getMonth() + 1
|
||||
this[pointType + 'Day'] = pointDate.getDate()
|
||||
if (this.type === 'datetime') {
|
||||
this[pointType + 'Hour'] = pointDate.getHours()
|
||||
this[pointType + 'Minute'] = pointDate.getMinutes()
|
||||
this[pointType + 'Second'] = pointDate.getSeconds()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 获取 年、月、日、时、分、秒 当前可选范围
|
||||
getCurrentRange(value) {
|
||||
const range = []
|
||||
for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
|
||||
range.push(i)
|
||||
}
|
||||
return range
|
||||
},
|
||||
|
||||
// 字符串首字母大写
|
||||
capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
},
|
||||
|
||||
// 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||
checkValue(name, value, values) {
|
||||
if (values.indexOf(value) === -1) {
|
||||
this[name] = values[0]
|
||||
}
|
||||
},
|
||||
|
||||
// 每个月的实际天数
|
||||
daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
|
||||
return new Date(year, month, 0).getDate();
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成时间戳
|
||||
* @param {Object} time
|
||||
*/
|
||||
createTimeStamp(time) {
|
||||
if (!time) return
|
||||
if (typeof time === "number") {
|
||||
return time
|
||||
} else {
|
||||
time = time.replace(/-/g, '/')
|
||||
if (this.type === 'date') {
|
||||
time = time + ' ' + '00:00:00'
|
||||
}
|
||||
return Date.parse(time)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成日期或时间的字符串
|
||||
*/
|
||||
createDomSting() {
|
||||
const yymmdd = this.year +
|
||||
'-' +
|
||||
this.lessThanTen(this.month) +
|
||||
'-' +
|
||||
this.lessThanTen(this.day)
|
||||
|
||||
let hhmmss = this.lessThanTen(this.hour) +
|
||||
':' +
|
||||
this.lessThanTen(this.minute)
|
||||
|
||||
if (!this.hideSecond) {
|
||||
hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
|
||||
}
|
||||
|
||||
if (this.type === 'date') {
|
||||
return yymmdd
|
||||
} else if (this.type === 'time') {
|
||||
return hhmmss
|
||||
} else {
|
||||
return yymmdd + ' ' + hhmmss
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化返回值,并抛出 change 事件
|
||||
*/
|
||||
initTime(emit = true) {
|
||||
this.time = this.createDomSting()
|
||||
if (!emit) return
|
||||
if (this.returnType === 'timestamp' && this.type !== 'time') {
|
||||
this.$emit('change', this.createTimeStamp(this.time))
|
||||
this.$emit('input', this.createTimeStamp(this.time))
|
||||
this.$emit('update:modelValue', this.createTimeStamp(this.time))
|
||||
} else {
|
||||
this.$emit('change', this.time)
|
||||
this.$emit('input', this.time)
|
||||
this.$emit('update:modelValue', this.time)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户选择日期或时间更新 data
|
||||
* @param {Object} e
|
||||
*/
|
||||
bindDateChange(e) {
|
||||
const val = e.detail.value
|
||||
this.year = this.years[val[0]]
|
||||
this.month = this.months[val[1]]
|
||||
this.day = this.days[val[2]]
|
||||
},
|
||||
bindTimeChange(e) {
|
||||
const val = e.detail.value
|
||||
this.hour = this.hours[val[0]]
|
||||
this.minute = this.minutes[val[1]]
|
||||
this.second = this.seconds[val[2]]
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化弹出层
|
||||
*/
|
||||
initTimePicker() {
|
||||
if (this.disabled) return
|
||||
const value = fixIosDateFormat(this.time)
|
||||
this.initPickerValue(value)
|
||||
this.visible = !this.visible
|
||||
},
|
||||
|
||||
/**
|
||||
* 触发或关闭弹框
|
||||
*/
|
||||
tiggerTimePicker(e) {
|
||||
this.visible = !this.visible
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击“清空”按钮,清空当前值
|
||||
*/
|
||||
clearTime() {
|
||||
this.time = ''
|
||||
this.$emit('change', this.time)
|
||||
this.$emit('input', this.time)
|
||||
this.$emit('update:modelValue', this.time)
|
||||
this.tiggerTimePicker()
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击“确定”按钮
|
||||
*/
|
||||
setTime() {
|
||||
this.initTime()
|
||||
this.tiggerTimePicker()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-datetime-picker {
|
||||
/* #ifndef APP-NVUE */
|
||||
/* width: 100%; */
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-view {
|
||||
height: 130px;
|
||||
width: 270px;
|
||||
/* #ifndef APP-NVUE */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-item {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn {
|
||||
margin-top: 60px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-text {
|
||||
font-size: 14px;
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-group {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-cancel {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-mask {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-popup {
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
width: 270px;
|
||||
/* #ifdef APP-NVUE */
|
||||
height: 500px;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 330px;
|
||||
/* #endif */
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.fix-nvue-height {
|
||||
/* #ifdef APP-NVUE */
|
||||
height: 330px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-column {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-timebox {
|
||||
|
||||
border: 1px solid #E5E5E5;
|
||||
border-radius: 5px;
|
||||
padding: 7px 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-timebox-pointer {
|
||||
/* #ifndef APP-NVUE */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
.uni-datetime-picker-disabled {
|
||||
opacity: 0.4;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed !important;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-text {
|
||||
font-size: 14px;
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.uni-datetime-picker-sign {
|
||||
position: absolute;
|
||||
top: 53px;
|
||||
/* 减掉 10px 的元素高度,兼容nvue */
|
||||
color: #999;
|
||||
/* #ifdef APP-NVUE */
|
||||
font-size: 16px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.sign-left {
|
||||
left: 86px;
|
||||
}
|
||||
|
||||
.sign-right {
|
||||
right: 86px;
|
||||
}
|
||||
|
||||
.sign-center {
|
||||
left: 135px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker__container-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.time-hide-second {
|
||||
width: 180px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,421 @@
|
||||
class Calendar {
|
||||
constructor({
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range,
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDateObj(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 起始时间
|
||||
this.startDate = startDate
|
||||
// 终止时间
|
||||
this.endDate = endDate
|
||||
// 是否范围选择
|
||||
this.range = range
|
||||
// 多选状态
|
||||
this.cleanMultipleStatus()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
this.lastHover = false
|
||||
}
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
const selectDate = this.getDateObj(date)
|
||||
this.getWeeks(selectDate.fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理多选状态
|
||||
*/
|
||||
cleanMultipleStatus() {
|
||||
this.multipleStatus = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
setStartDate(startDate) {
|
||||
this.startDate = startDate
|
||||
}
|
||||
|
||||
setEndDate(endDate) {
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
getPreMonthObj(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth - 1)
|
||||
const newMonth = date.getMonth()
|
||||
if (oldMonth !== 0 && newMonth - oldMonth === 0) {
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
getNextMonthObj(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth + 1)
|
||||
const newMonth = date.getMonth()
|
||||
if (newMonth - oldMonth > 1) {
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定格式Date对象
|
||||
*/
|
||||
getDateObj(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
return {
|
||||
fullDate: getDate(date),
|
||||
year: date.getFullYear(),
|
||||
month: addZero(date.getMonth() + 1),
|
||||
date: addZero(date.getDate()),
|
||||
day: date.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上一个月日期集合
|
||||
*/
|
||||
getPreMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
for (let i = amount - 1; i >= 0; i--) {
|
||||
const month = dateObj.month - 1
|
||||
result.push({
|
||||
date: new Date(dateObj.year, month, -i).getDate(),
|
||||
month,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取本月日期集合
|
||||
*/
|
||||
getCurrentMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
|
||||
const isToday = fullDate === currentDate
|
||||
// 获取打点信息
|
||||
const info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(currentDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
disableBefore = dateCompare(this.startDate, currentDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
disableAfter = dateCompare(currentDate, this.endDate)
|
||||
}
|
||||
|
||||
let multiples = this.multipleStatus.data
|
||||
let multiplesStatus = -1
|
||||
if (this.range && multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, currentDate)
|
||||
})
|
||||
}
|
||||
const checked = multiplesStatus !== -1
|
||||
|
||||
result.push({
|
||||
fullDate: currentDate,
|
||||
year: dateObj.year,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
month: dateObj.month,
|
||||
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
|
||||
currentDate, this.endDate)),
|
||||
isToday,
|
||||
userChecked: false,
|
||||
extraInfo: info
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取下一个月日期集合
|
||||
*/
|
||||
_getNextMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const month = dateObj.month + 1
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
result.push({
|
||||
date: i,
|
||||
month,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
|
||||
return res ? res : this.getDateObj(date)
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
before = new Date(fixIosDateFormat(before))
|
||||
after = new Date(fixIosDateFormat(after))
|
||||
return before.valueOf() === after.valueOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较真实起始日期
|
||||
*/
|
||||
|
||||
isLogicBefore(currentDate, before, after) {
|
||||
let logicBefore = before
|
||||
if (before && after) {
|
||||
logicBefore = dateCompare(before, after) ? before : after
|
||||
}
|
||||
return this.dateEqual(logicBefore, currentDate)
|
||||
}
|
||||
|
||||
isLogicAfter(currentDate, before, after) {
|
||||
let logicAfter = after
|
||||
if (before && after) {
|
||||
logicAfter = dateCompare(before, after) ? after : before
|
||||
}
|
||||
return this.dateEqual(logicAfter, currentDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @param {Object} begin
|
||||
* @param {Object} end
|
||||
*/
|
||||
geDateAll(begin, end) {
|
||||
var arr = []
|
||||
var ab = begin.split('-')
|
||||
var ae = end.split('-')
|
||||
var db = new Date()
|
||||
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||||
var de = new Date()
|
||||
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||||
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = unixDb; k <= unixDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
if (!this.range) return
|
||||
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
if (before && after) {
|
||||
if (!this.lastHover) {
|
||||
this.lastHover = true
|
||||
return
|
||||
}
|
||||
this.multipleStatus.before = fullDate
|
||||
this.multipleStatus.after = ''
|
||||
this.multipleStatus.data = []
|
||||
this.multipleStatus.fulldate = ''
|
||||
this.lastHover = false
|
||||
} else {
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
this.multipleStatus.after = undefined;
|
||||
this.lastHover = false
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
|
||||
.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
|
||||
.before);
|
||||
}
|
||||
this.lastHover = true
|
||||
}
|
||||
}
|
||||
this.getWeeks(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标 hover 更新多选状态
|
||||
*/
|
||||
setHoverMultiple(fullDate) {
|
||||
//抖音小程序点击会触发hover事件,需要避免一下
|
||||
// #ifndef MP-TOUTIAO
|
||||
if (!this.range || this.lastHover) return
|
||||
const {
|
||||
before
|
||||
} = this.multipleStatus
|
||||
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||||
}
|
||||
}
|
||||
this.getWeeks(fullDate)
|
||||
// #endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新默认值多选状态
|
||||
*/
|
||||
setDefaultMultiple(before, after) {
|
||||
this.multipleStatus.before = before
|
||||
this.multipleStatus.after = after
|
||||
if (before && after) {
|
||||
if (dateCompare(before, after)) {
|
||||
this.multipleStatus.data = this.geDateAll(before, after);
|
||||
this.getWeeks(after)
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(after, before);
|
||||
this.getWeeks(before)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
getWeeks(dateData) {
|
||||
const {
|
||||
year,
|
||||
month,
|
||||
} = this.getDateObj(dateData)
|
||||
|
||||
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
|
||||
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const currentMonthDayAmount = new Date(year, month, 0).getDate()
|
||||
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
|
||||
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
|
||||
|
||||
const weeks = new Array(6)
|
||||
for (let i = 0; i < calendarDays.length; i++) {
|
||||
const index = Math.floor(i / 7)
|
||||
if (!weeks[index]) {
|
||||
weeks[index] = new Array(7)
|
||||
}
|
||||
weeks[index][i % 7] = calendarDays[i]
|
||||
}
|
||||
|
||||
this.calendar = calendarDays
|
||||
this.weeks = weeks
|
||||
}
|
||||
}
|
||||
|
||||
function getDateTime(date, hideSecond) {
|
||||
return `${getDate(date)} ${getTime(date, hideSecond)}`
|
||||
}
|
||||
|
||||
function getDate(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
return `${year}-${addZero(month)}-${addZero(day)}`
|
||||
}
|
||||
|
||||
function getTime(date, hideSecond) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
|
||||
}
|
||||
|
||||
function addZero(num) {
|
||||
if (num < 10) {
|
||||
num = `0${num}`
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
function getDefaultSecond(hideSecond) {
|
||||
return hideSecond ? '00:00' : '00:00:00'
|
||||
}
|
||||
|
||||
function dateCompare(startDate, endDate) {
|
||||
startDate = new Date(fixIosDateFormat(typeof startDate === 'string' ? startDate.trim() : startDate))
|
||||
endDate = new Date(fixIosDateFormat(typeof endDate === 'string' ? endDate.trim() : endDate))
|
||||
return startDate <= endDate
|
||||
}
|
||||
|
||||
function checkDate(date) {
|
||||
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||||
return date.match(dateReg)
|
||||
}
|
||||
//ios低版本15及以下,无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
|
||||
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
|
||||
|
||||
function fixIosDateFormat(value) {
|
||||
if (typeof value === 'string' && dateTimeReg.test(value)) {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export {
|
||||
Calendar,
|
||||
getDateTime,
|
||||
getDate,
|
||||
getTime,
|
||||
addZero,
|
||||
getDefaultSecond,
|
||||
dateCompare,
|
||||
checkDate,
|
||||
fixIosDateFormat
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"id": "uni-datetime-picker",
|
||||
"displayName": "uni-datetime-picker 日期选择器",
|
||||
"version": "2.2.42",
|
||||
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
|
||||
"keywords": [
|
||||
"uni-datetime-picker",
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"日期时间选择器",
|
||||
"日期时间"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": "",
|
||||
"uni-app": "^4.07",
|
||||
"uni-app-x": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue",
|
||||
"darkmode": "x",
|
||||
"i18n": "x",
|
||||
"widescreen": "x"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"uni-scss",
|
||||
"uni-icons"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "x",
|
||||
"aliyun": "x",
|
||||
"alipay": "x"
|
||||
},
|
||||
"client": {
|
||||
"uni-app": {
|
||||
"vue": {
|
||||
"vue2": "√",
|
||||
"vue3": "√"
|
||||
},
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"vue": "√",
|
||||
"nvue": "√",
|
||||
"android": "√",
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√",
|
||||
"alipay": "√",
|
||||
"toutiao": "√",
|
||||
"baidu": "√",
|
||||
"kuaishou": "-",
|
||||
"jd": "-",
|
||||
"harmony": "-",
|
||||
"qq": "√",
|
||||
"lark": "-"
|
||||
},
|
||||
"quickapp": {
|
||||
"huawei": "√",
|
||||
"union": "√"
|
||||
}
|
||||
},
|
||||
"uni-app-x": {
|
||||
"web": {
|
||||
"safari": "-",
|
||||
"chrome": "-"
|
||||
},
|
||||
"app": {
|
||||
"android": "-",
|
||||
"ios": "-",
|
||||
"harmony": "-"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
|
||||
|
||||
## DatetimePicker 时间选择器
|
||||
|
||||
> **组件名:uni-datetime-picker**
|
||||
> 代码块: `uDatetimePicker`
|
||||
|
||||
|
||||
该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
|
||||
|
||||
若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
|
||||
|
||||
**_点击 picker 默认值规则:_**
|
||||
|
||||
- 若设置初始值 value, 会显示在 picker 显示框中
|
||||
- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
@@ -42,7 +42,7 @@
|
||||
:shape="item.badge && item.badge.shape || propsBadge.shape"
|
||||
:numberType="item.badge && item.badge.numberType || propsBadge.numberType"
|
||||
:inverted="item.badge && item.badge.inverted || propsBadge.inverted"
|
||||
customStyle="margin-left: 4px;"
|
||||
:customStyle="item.badge && item.badge.customStyle || 'margin-left: 4px;'"
|
||||
></u-badge>
|
||||
</view>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
|
||||