// ==UserScript== // @name 别样红辅助(大道店) // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.4.2 // @description 别样红辅助 // @author EmpyrealTear // @icon https://c1.beyondh.com/maxpms/5.2.1.2/favicon.ico // @match .*://mn.beyondh.com:8101/* // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js // @require https://scriptcat.org/lib/513/2.0.0/ElementGetter.js // @grant unsafeWindow // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // ==/UserScript== (function () { 'use strict'; unsafeWindow.jQuery = $ const options = { menus: { isShowCleaner: { toStr: (x) => '显示保洁:' + (x ? '✓' : '✕') }, isShowDetailContractName: { toStr: (x) => '显示中介明细:' + (x ? '✓' : '✕') }, isShowGuestRecords: { toStr: (x) => '显示客历入住:' + (x ? '✓' : '✕') }, isHighlightBalanceltPrice: { toStr: (x) => '高亮余额<房价:' + (x ? '✓' : '✕') }, isHighlightBalancegtPrice: { toStr: (x) => '高亮余额>房价:' + (x ? '✓' : '✕') }, }, register: (name) => { let val = GM_getValue(name) options.menus[name][!val ? '_new' : '_old'] = GM_registerMenuCommand(options.menus[name].toStr(val), () => { GM_setValue(name, !val) options.register(name) }) GM_unregisterMenuCommand(options.menus[name][val ? '_new' : '_old']) }, loads: () => { Object.keys(options.menus).forEach(v => options.register(v)) } } options.loads() const sum = (arr) => { if (arr == undefined) return undefined let res = 0 for (let i of arr) res += i return res } const getCleaner = (id) => { if ((id >= 301 && id <= 311) || (id >= 601 && id <= 611)) return '谢' else if ((id >= 401 && id <= 411) || id == 706 || (id >= 708 && id <= 711) || (id >= 807 && id <= 812)) return '易' else return '段' } const apis = { GetMixAllRoomDetails: () => { // 获取房态信息 let res = null $.ajax({ url: 'https://mn.beyondh.com:8111/api/Room/GetMixAllRoomDetails', type: 'GET', xhrFields: { withCredentials: true }, dataType: 'json', async: false, success: (data) => { res = data } }) if (res == null) return res for (let i = 0; i < res.Content.length; i++) { let id = parseInt(res.Content[i].RoomNumber) res.Content[i].Cleaner = getCleaner(id) } return res }, GetMixSingleRoomOccupationInfo: (id) => { // 获取房间摘要信息 let res = null $.ajax({ url: `https://mn.beyondh.com:8111/api/Room/GetMixSingleRoomOccupationInfo?roomNumber=${id}`, type: 'GET', xhrFields: { withCredentials: true }, dataType: 'json', async: false, success: (data) => { res = data } }) return res }, SearchGuestFolioCheckIn: () => { // 获取住客在住单 let res = null $.ajax({ url: `https://mn.beyondh.com:8111/API/GuestFolio/SearchGuestFolio?PageSize=100&PageIndex=1&IsDesc=false&Status%5B%5D=I&IsMeiTuanOrder=false&DateRangeType=RecentWithOneYear`, type: 'GET', xhrFields: { withCredentials: true }, dataType: 'json', async: false, success: (data) => { res = data } }) return res }, SearchGuestFolioCheckOut: (keywords, pageIndex = 1, pageSize = 10) => { // 获取住客退房单(不含挂账单) let res = null $.ajax({ url: `https://mn.beyondh.com:8111/API/GuestFolio/SearchGuestFolio?PageSize=${pageSize}&PageIndex=${pageIndex}&IsDesc=false&Status%5B%5D=O&Keywords=${keywords}&IsMeiTuanOrder=false&DateRangeType=RecentWithOneYear`, type: 'GET', xhrFields: { withCredentials: true }, dataType: 'json', async: false, success: (data) => { res = data } }) return res }, GetCustomerForEdit: (id) => { // 获取住客信息 let res = null $.ajax({ url: `https://mn.beyondh.com:8111/API/Customer/GetCustomerForEdit?CustomerId=${id}`, type: 'GET', xhrFields: { withCredentials: true }, dataType: 'json', async: false, success: (data) => { res = data } }) return res }, GetBillStatistics: (billIds) => { // 获取订单收付总额 let res = null $.ajax({ url: `https://mn.beyondh.com:8111/API/Bill/GetBillStatistics`, type: 'POST', xhrFields: { withCredentials: true }, data: JSON.stringify([...billIds]), contentType: 'application/json', dataType: 'json', async: false, success: (data) => { res = data } }) return res }, } unsafeWindow.apis = apis elmGetter.selector('jquery') const xhrSend = XMLHttpRequest.prototype.send; const CheckinType = { Normal: '正常', Hour2: '2H', Hour4: '4H', Hour8: '8H', Internal: '自用', LongTerm: '长包', Free: '免费' } XMLHttpRequest.prototype.send = function (data) { const xhr = this // 修复客历无法显示历史入住记录问题 if (GM_getValue('isShowGuestRecords') && /API\/Customer\/SearchCustomerCheckinsByPost/.test(xhr.url)) { let xhrSendBody = JSON.parse(data) let idCardNumber = apis.GetCustomerForEdit(xhrSendBody.CustomerId).Content.IdCardNumber let checkouts = apis.SearchGuestFolioCheckOut(idCardNumber, xhrSendBody.PageIndex, xhrSendBody.PageSize) const getter = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, "responseText").get Object.defineProperty(xhr, "responseText", { get: () => { let result = JSON.parse(getter.call(xhr)) let rows = [] for (let i of checkouts.Content.Content) { let detail = i.GuestFolioDetailModels[0] let bill = undefined // apis.GetBillStatistics([i.BillId]) rows.push({ RoomNumber: detail.RoomNumber[0], // 房号 ArriveTime: i.ArriveTime, // 抵店时间 DepatureTime: i.DepatureTime, // 离店时间 Days: i.CheckinTypeId.startsWith('Hour') ? CheckinType[i.CheckinTypeId] : detail.DailyPrices.length, // 天数 PriceRoomTypeName: `${detail.ControlRoomTypeName}`, // 房型 FirstDayPrice: detail.FirstDayPrice, // 房价 RoomChargeAmount: bill == undefined ? (i.Contract.Name ?? '散客') : bill.Content?.CreditAmount, // 总房费 OtherChargeAmount: i.CheckinMemo, // 其他消费 }) } result.Content = { ...checkouts.Content, Content: rows } return JSON.stringify(result) }, }) } return xhrSend.apply(xhr, arguments) } const xhrOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function () { const xhr = this if (/api\/Room\/GetMixAllRoomDetails/.test(arguments[1])) { const getter = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, "responseText").get Object.defineProperty(xhr, "responseText", { get: () => { let result = getter.call(xhr) let roomInfo = JSON.parse(result) let roomSet = {} let roomDetails = apis.SearchGuestFolioCheckIn().Content.Content for (let i = 0; i < roomInfo.Content.length; i++) { let id = parseInt(roomInfo.Content[i].RoomNumber) roomInfo.Content[i].Cleaner = getCleaner(id) let guests = roomDetails .filter(v => v.GuestFolioDetailModels[0].RoomNumber.some(num => num == roomInfo.Content[i].RoomNumber)) roomInfo.Content[i].Remark = guests.map(v => v.CheckinMemo).join(';') if (guests.length > 0) { roomInfo.Content[i].Balance = sum(guests.map(v => v.Balance)) roomInfo.Content[i].TodayPrice = guests[0].GuestFolioDetailModels[0].FirstDayPrice.ActualPrice roomInfo.Content[i].DailyPrices = guests[0].GuestFolioDetailModels[0].DailyPrices } roomSet[roomInfo.Content[i].RoomNumber] = roomInfo.Content[i] } // console.log(roomSet) let cleans = {} let rooms = roomInfo.Content for (let i = 0; i < rooms.length; i++) { let k = rooms[i].Cleaner if (!(k in cleans)) cleans[k] = 0 // VD=空脏; VC=空净; V_C=空夜; OOO=维修; OK=已检; OD=住脏; OC=住净; ED=预退; if (rooms[i].CustomerStatus == 'IsEstArrival' || /VD|OD|OC/.test(rooms[i].RoomStatus)) // if (rooms[i].CustomerStatus == 'IsEstArrival' || /OD|OC/.test(rooms[i].RoomStatus)) cleans[k] += 1 } // 统计需保洁数量 jQuery('#cleaner').remove() jQuery('div>div.small:contains("出租率")').parent().prepend(`
(${Object.keys(cleans).map((v) => `${v}:${cleans[v]}`).join(';')})
`) elmGetter.each('.room_number_default', (e) => { let roomId = e.text() let id = roomId.replace(/\s\(.+\)/, '') // 添加保洁显示 if (GM_getValue('isShowCleaner')) { if (!/[\(\)]/.test(roomId)) e.text(`${roomId} (${roomSet[roomId].Cleaner})`) } else { if (/[\(\)]/.test(roomId)) e.text(roomId.replace(/\s\(.+\)/, '')) } // 修改中介小图标 e.nextAll('.icon_group').each((i, v) => { elmGetter.get('.iconfont', v).then(elm => { let name = roomSet[id]?.ContractName if (name != undefined && /小程序|直客通|赫程预付/.test(name)) { if (GM_getValue('isShowDetailContractName')) { if (/[小直赫介]/.test(elm.text())) { let txt = name[0], icon = 'icon_circle' if (/小程序|直客通/.test(name)) { let remark = roomSet[id]?.Remark if (/[银金钻][卡石]/.test(remark)) { txt = remark.replace(/\n/g, '').replace(/.*([银金钻])[卡石].*/, '$1') icon = 'icon_circle icon_circle_' + (/直客通/.test(name) ? 'lv' : 'vacant_status') } } else if (/赫程预付/.test(name)) { icon = 'icon_circle icon_circle_xie' } elm.parent().attr('class', icon) elm.text(txt) } } else { if (elm.text() != '介' && !elm.text().includes('抵')) { elm.parent().attr('class', 'icon_circle') elm.text('介') } } } }) }) let roomInfo = roomSet[id] // 高亮余额≠房价 if (GM_getValue('isHighlightBalanceltPrice') && roomInfo.Balance != undefined) { // 每日5:50后完成夜审 let nowPrice = roomInfo.DailyPrices?.filter(v => new Date(v.Date).AddDays(1).AddMinutes(60 * 6 - 10) > Date.now())[0]?.ActualPrice if (roomInfo.Balance < (nowPrice == undefined ? 0 : nowPrice) && !/免费/.test(roomInfo.Remark)) { e.parent().css('border', '2px dashed #f24e4c') } else if (GM_getValue('isHighlightBalancegtPrice') && roomInfo.Balance > (nowPrice == undefined ? 0 : nowPrice)) { e.parent().css('border', '2px dashed #fed100') } else e.parent().css('border', '') } else e.parent().css('border', '') }) return result }, }) } return xhrOpen.apply(xhr, arguments) } })();