652 lines
17 KiB
TypeScript
Raw Normal View History

2023-11-23 16:33:21 +08:00
import { ResourceItemType } from "@/Common/ResourceItem/ResourceItemType";
import { BaseEnumerator } from "@/Engine/CatanEngine/CoroutineV2/Core/BaseEnumerator";
import { TableManager } from "@/Engine/CatanEngine/TableV3/TableManager";
import CSSettingsV3 from "@/FormTable/CSSettingsV3";
import { ShopMycardTableRow, ShopShow2TableRow } from "@/FormTable/Tables/ShopTable";
import { Cocos } from "@/assets/VueScript/Cocos";
import { CocosVueScript } from "@/assets/VueScript/CocosVueScript";
import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos";
import { FriendRequest } from "@/define/Request/FriendRequest";
import { TxnRequest } from "@/define/Request/TxnRequest";
import { VIPLevelMapForChat } from "@/map";
import Player from "@/modules/player";
import { UserBindFlag } from "@/modules/player/define/userbind_flag";
import { ChatRoomRole, Games, ItemCodeList, ItemPropsType, ItemSize, PriceList, SelectorItemProps, StringContentType, TagTypes, TxnCenterData } from "@/types";
import liff from "@line/liff";
import axios, { AxiosResponse } from "axios";
import { isMobile } from "react-device-detect";
import * as Scroll from "react-scroll";
import stringWidth from "string-width";
import BusinessTypeSetting, { FolderName } from "../_BusinessTypeSetting/BusinessTypeSetting";
export const transArray = <T>(array: T[], split: number): T[][] => {
const newArr = [];
const copiedArr = array ? array?.slice() : [];
const length = copiedArr?.length;
for (let i = 0, j = 0; i < length; i += split, j++) {
newArr[j] = copiedArr.splice(0, split);
}
return newArr;
};
/** 去掉英文+百分比% */
export function onlyNumber(stringText: string): number {
const str = +stringText.replace(/[A-Za-z%]/g, "");
return str;
}
export function wordsLimit(limit: number, string: string) {
const length = string?.length;
const isOverLimit = length > limit;
const result = isOverLimit ? "..." : "";
return string?.substring(0, limit) + result;
}
export const capitalize = (str: string) =>
`${str.charAt(0).toUpperCase()}${str.slice(1)}`;
export function checkForUnique(str: string): boolean {
const chineseCharacterMatch =
/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu;
const arr = str.match(chineseCharacterMatch);
if (arr === null) return true;
return !hasDuplicates(arr);
}
export function onlyChinese(str: string) {
const chineseCharacterMatch =
/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu;
const arr = str.match(chineseCharacterMatch);
return arr.join("");
}
export function hasDuplicates(array: string[]): boolean {
return new Set(array).size !== array.length;
}
export function generatePriceList(
arr: [ID: number, ProductId: number, ShowMoney: number][],
items: { [id: string]: [ID: number, price: number] },
priceRef: ShopMycardTableRow[],
itemCodeList?: Map<number, ItemCodeList>,
): PriceList[] {
if (itemCodeList) {
arr = arr.filter((item) => itemCodeList.has(item[0]));
}
const MyCardPriceRefMap = new Map<number, number>(
priceRef.map((item) => [item.Id, item.Price]),
);
const newArr: [ID: number, ProductId: number, ShowMoney: number][] = [];
for (const item of Object.values(items)) {
arr.forEach((v: [ID: number, ProductId: number, ShowMoney: number]) => {
if (v[1] === item[0]) {
newArr.push(v);
}
});
}
return newArr
.map((item) => ({
ID: item[0],
points: item[2],
price: MyCardPriceRefMap.get(item[1]),
}))
.sort((a, b) => b.price - a.price);
}
/** 支付列表 */
export function generatePaymentList(
arr: string[],
priceRef: ShopShow2TableRow[],
): ShopShow2TableRow[] {
const newArr: ShopShow2TableRow[] = [];
for (const item of Object.values(priceRef)) {
arr.forEach((x) => {
if (item.Show && x === item.Key) newArr.push(item);
});
}
// priceRef.forEach((value: ShopShow2TableRow) => {
// arr.includes(value.Key);
// })
return newArr;
}
/** getQueryParameters */
export function getQueryParameters(v: string): string {
const queryParameters = new URLSearchParams(location.search);
return queryParameters.get(v);
}
export function createMap(obj: unknown) {
return new Map(Object.entries(obj));
}
export function isArray(itemCode: string | string[]): boolean {
return Array.isArray(itemCode);
}
export function formatTime(date: Date): string {
const hours = date.getHours();
const minutes = date.getMinutes();
const amPm = hours >= 12 ? "pm" : "am";
const formattedHours = hours % 12 === 0 ? 12 : hours % 12;
const formattedMinutes = minutes < 10 ? "0" + minutes : minutes;
return `${formattedHours}:${formattedMinutes} ${amPm}`;
}
export function getCurrentLocalTime() {
const date = new Date();
const utcTime = date.getTime();
return new Date(utcTime).toLocaleTimeString();
}
export function transferColorText(str: string): string {
const regex = /color=/g;
const replacement = "span style=color:";
const result = str.replace(regex, replacement);
const regex2 = /color>/g;
const replacement2 = "span>";
return result.replace(regex2, replacement2);
}
export function generateItemsData(
games: Map<string, number[]>,
favoriteGames: number[],
): ItemPropsType[] {
let itemsData: boolean | ItemPropsType[] = [];
const s = new Set(favoriteGames);
if (games.size) {
// @ts-ignore
for (const [gameID, [vendorID, id, VIPLimit, status, tag]] of games) {
const dataObj: ItemPropsType = {
id: gameID,
vendorID: vendorID.toString(),
img: {
url: `${BusinessTypeSetting.UseDownloadUrl}${FolderName.Game}${id}/b`,
},
size: ItemSize.small,
tag: tag as unknown as TagTypes,
lockBtn: VIPLimit,
like: s.has(id),
status,
};
itemsData.push(dataObj);
}
} else {
itemsData = [];
}
return itemsData;
}
export function generateItemsDataMap(games: Games): Map<string, number[]> {
const map = new Map();
for (const [gameID, value] of Object.entries(games)) {
map.set(gameID, value);
}
return map;
}
export function sortedGames(sorts: number[], map: Map<string, number[]>) {
const obj = new Map();
sorts?.forEach((gameID) => {
obj.set("" + gameID, map?.get("" + gameID));
});
return obj;
}
export function addPropertiesToDefaultItem(
games: any[],
selectedID: number,
): SelectorItemProps[] {
const index = games.findIndex((item) => parseInt(item.id) === selectedID);
const newGames = games.slice();
return newGames.map((g, i) =>
i === index
? { ...g, selected: true, defaultItem: true }
: {
...g,
selected: false,
defaultItem: false,
},
);
}
export function switchObjToMap(games: Games) {
// for (const [gameID, value] of Object.entries(games)) {
// map.set(gameID, value)
// }
return new Map(Object.entries(games));
}
export function hexToRgb(
hex: string,
// eslint-disable-next-line @typescript-eslint/typedef
result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex),
) {
const x = result ? result.map((i) => parseInt(i, 16)).slice(1) : null;
return {
r: x[0],
g: x[1],
b: x[2],
};
}
export function replaceBorderColor(string: string, color: string) {
const hasComma = string.includes(",");
if (hasComma) {
const result = string.split(",").map((s, i) => {
const index = s.indexOf("#");
const replaceStr = s.substring(index);
return s.replace(replaceStr, i === 0 ? "black" : color);
});
return result.join(",");
} else {
const index = string.indexOf("#");
const replaceStr = string.substring(index);
return string.replace(replaceStr, color);
}
}
export function generateMessage(message: string) {
return {
AID: "10000000063",
nickName: "masterkai",
profileIMG: "./img/png/avatar.png",
role: ChatRoomRole.player,
message: message,
created: getCurrentLocalTime(),
vip: VIPLevelMapForChat.get(4),
};
}
export function getVIPLevelFromStr(vipStr: string) {
const arr = vipStr.split(".");
const str = arr[0];
return str.at(-1);
}
interface Accumulator {
[AID: number]: {
AID: number;
nickName: string;
avatar: number;
role: number;
vip: number;
messages: {
message: string;
created: number;
}[];
};
}
export function sleep(ms: any): Promise<any> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export async function downloadJSON(formname: string) {
const patchUrl: string =
BusinessTypeSetting.UsePatch + BusinessTypeSetting.FolderUrlJson;
let fileUrl: string = `${patchUrl}${formname}.json`;
fileUrl = fileUrl + "?v=" + Date.now();
let resp: AxiosResponse<any, any> = null;
axios.get(fileUrl).then((res: AxiosResponse<any, any>) => {
loadJsonProcess(null, res, formname);
resp = res;
});
while (!resp) {
await sleep(0.1);
}
}
function loadJsonProcess(
err: any,
res: AxiosResponse<any, any>,
formname: string,
) {
res["name"] = formname;
TableManager.AddJsonAsset(res.data);
}
export function getProfileImgUrl(avatar: number, aId: number) {
return avatar === 1
? `${BusinessTypeSetting.UseDownloadUrl}avatar/${aId}`
: "./img/common/DefaultAvatar.png";
}
export const CssStringContent = (
StringKey: number,
StringID: number | string,
): string => {
switch (StringKey) {
case StringContentType.String:
return StringID?.toString();
case StringContentType.CSSString:
return CSSettingsV3.prototype.CommonString(+StringID);
case StringContentType.CSSMailString:
return CSSettingsV3.prototype.CSSMailString(+StringID);
case StringContentType.CSSNetworkString:
return ""; // CSSettingsV3.Network.Priority[StringID][LanguageManager.GetMsgId()];
case StringContentType.HallString:
/* 廳管1~4 但表格是從2號位開始 */
return CSSettingsV3.prototype.LobbyString(1 + +StringID);
default:
break;
}
return;
};
export function txnDataTransformer(
arr: TxnRequest.TxnInfo[],
playerAid: number,
): TxnCenterData[] {
return arr.map(
([
sn,
time,
giver,
receiver,
status,
fee,
[[category, categoryId, quantity]],
]) => ({
serialNum: sn,
createdAt: time,
giverAid: giver[0],
giverName: giver[1],
isGiver: giver[0] === playerAid,
receiverAid: receiver[0],
receiverName: receiver[1],
status: +status,
quantity,
fee,
}),
);
}
export function calculatedReward(rewards: [number, number][]) {
const maximum = 6;
const result = [];
const couponType = ResourceItemType.Card_Coupon;
rewards.forEach(([type, quantity]) => {
if (type === couponType && quantity > maximum) {
const packNum = Math.floor(quantity / maximum);
const returnPack = Array.from({ length: packNum }, () => [
couponType,
maximum,
]);
const remainder = quantity % maximum;
const returnRemainder = remainder ? [couponType, remainder] : null;
if (returnRemainder) {
returnPack.push(returnRemainder);
}
returnPack.forEach((item) => result.push(item));
} else {
result.push([type, quantity]);
}
});
return result;
}
export const random = (min: number, max: number) =>
Math.floor(Math.random() * (max - min)) + min;
// Default color is a bright yellow
const DEFAULT_COLOR = "hsl(50deg, 100%, 50%)";
export const generateSparkle = (color = DEFAULT_COLOR) => {
return {
id: "" + random(10000, 99999),
createdAt: Date.now(),
// Bright yellow color:
color,
size: random(20, 60),
style: {
// Pick a random spot in the available space
top: random(0, 100) + "%",
left: random(0, 100) + "%",
// Float sparkles above sibling content
zIndex: 2,
},
};
};
export const range = (start, end, step = 1) => {
const output = [];
if (typeof end === "undefined") {
end = start;
start = 0;
}
for (let i = start; i < end; i += step) {
output.push(i);
}
return output;
};
export async function waitSetBusinessType() {
while (!BusinessTypeSetting.UseHost) {
await sleep(100);
}
}
/**
*
* @param {number} aId AID
*/
export function isMyFriend(aId: number): boolean {
let isTrue: boolean = false;
const playerData = Player.data.getState();
const lists: FriendRequest.ListFriendData = playerData.account.allowList;
for (let i = 0; i < lists.length; i++) {
const list: FriendRequest.SingleFriendData = lists[i];
if (list[0] === aId) {
isTrue = true;
break;
}
}
return isTrue;
}
/**
*
* @param {number} aId AID
*/
export function isMyDeny(aId: number): boolean {
let isTrue: boolean = false;
const playerData = Player.data.getState();
const lists: FriendRequest.ListFriendData = playerData.account.denyList;
for (let i = 0; i < lists.length; i++) {
const list: FriendRequest.SingleFriendData = lists[i];
if (list[0] === aId) {
isTrue = true;
break;
}
}
return isTrue;
}
export const sheetNameResourceTypeSwitcher = (
resourceType: ResourceItemType,
) => {
switch (resourceType) {
case ResourceItemType.Card_Coupon:
return "CouponSetting";
case ResourceItemType.Card:
return "Card1Setting";
default:
return "Card1Setting";
}
};
export function escapeCodesNToBr(v: string): string {
return v.replace(/\n/g, "<br>");
}
/**
*
* @param str
* @param showBytes (12BYTES)
* @returns
*/
export function trimString(
str: string,
showBytes: number = 12,
ellipses: boolean = true,
): string {
if (!str) {
return str;
}
let bytes: number = stringWidth(str);
if (bytes <= showBytes) {
return str;
}
let byteAmount: number = 0;
let strLength: number = str.length;
for (let i: number = 0; i < strLength; i++) {
let word: string = str[i];
bytes = stringWidth(word);
byteAmount += bytes;
if (byteAmount > showBytes) {
let checkStr: string = str.substring(0, i + 1);
let checkByte: number = stringWidth(checkStr);
if (checkByte < showBytes) {
byteAmount = checkByte;
continue;
}
let result: string = str.substring(0, i);
if (ellipses) {
return result + "...";
} else {
return result;
}
}
}
console.error("Trim Nickname Error.");
return str;
}
/** CommonEventType */
export enum CommonEventType {
/** Maintenance */
Maintenance,
/**ActivityReRender */
ActivityReRender,
}
export function responsiveText(characters: number): number {
if (characters <= 10) return 1.125;
if (characters > 10 && characters <= 20) return 0.9;
if (characters > 20) return 0.8;
}
export function discount(numberOff: number): number {
return (100 - numberOff) / 100;
}
/** 預載字體 */
export function PreloadFont(fonts: string[]): void {
// Check if API exists
if (document && document.fonts) {
// Do not block page loading
setTimeout(function (): void {
let successCount: number = 0;
for (let i: number = 0; i < fonts.length; i++) {
const font: string = fonts[i];
// eslint-disable-next-line no-loop-func
document.fonts.load(`16px ${font}`).then(() => {
// Make font using elements visible
successCount++;
if (successCount === fonts.length) {
document.documentElement.classList.add("font-loaded");
}
});
}
}, 0);
} else {
// Fallback if API does not exist
document.documentElement.classList.add("font-loaded");
}
}
// PWA
/** BeforeInstallPromptEvent */
export let deferredPrompt: any;
window.addEventListener("beforeinstallprompt", (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI to notify the user they can add to home screen
Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, e);
});
export function addToHomeScreen(): void {
if (isMobile) {
let url: string =
BusinessTypeSetting.UsePatch +
"addtohomescreen/index.html" +
"?v=" +
Date.now();
liff.openWindow({
url: url,
external: true,
});
} else {
if (deferredPrompt) {
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === "accepted") {
// console.log("User accepted the A2HS prompt");
Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, false);
} else {
// console.log("User dismissed the A2HS prompt");
}
deferredPrompt = null;
});
}
}
}
export function getArray(count: number): number[] {
const array: number[] = [];
for (let i: number = 0; i < count; i++) {
array.push(i);
}
return array;
}
/** 判斷登入並且Line綁定完 */
export function checkWait(): boolean {
const playerData = Player.data.getState();
const isLineBind: boolean = Player.hasUserBindFlag(UserBindFlag.LineBind);
if (!BaseEnumerator.isInit) {
return true;
} else if (!CocosVueScript.Instance || !CocosVueScript.Instance?.GetLoginData()) {
return true;
} else if (!playerData.account.role && !isLineBind) {
return true;
}
return false;
}
export function scrollToBottom(dynamicListHeight: number, duration: number = 200) {
Scroll.animateScroll.scrollTo(dynamicListHeight, {
duration: duration,
smooth: "easeInQuad",
containerId: "scrollableDiv",
offset: 50
});
}
export function Copy(serialNum: string) {
try {
navigator.clipboard.writeText(serialNum);
}
catch (error) {
console.error(error);
}
}