feat: add some utils

mack-mac
mackt 8 months ago
parent 3377801fcd
commit 081be29323

@ -1,32 +1,39 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm i
npm run dev
```
Open [http://localhost:3001](http://localhost:3001) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm i
npm run dev
```
Open [http://localhost:3001](http://localhost:3001) with your browser to see the result.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
如果遇到代码飘红报错 [试一下这个方法](https://juejin.cn/post/6844904069304156168#heading-6)
## Learn More
需要了解 Next.js 的相关信息,可以查看以下资源
- [Next.js Documentation](https://nextjs.org/docs) - 了解Next.js功能和API
- [Learn Next.js](https://nextjs.org/learn) - 交互式Next.js教程
- [Learn Next.js APP router](https://nextjs.org/learn/dashboard-app) - 交互式的 Next.js APP router教程。
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
## todo
- [ ] 首页
- [ ] 底部播放器
- [ ] loading skeleton
- [ ] api 封装
- [ ] MP4 资源加密
- [ ] SEO [meta](https://nextjs.org/learn/dashboard-app/adding-metadata)

17744
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,49 +1,50 @@
{
"name": "queyue-h5",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start -p 3001",
"lint": "eslint src --fix --ext .ts,.tsx,.js,.jsx,.mdx,.md,.json,.mjs --max-warnings 0"
},
"dependencies": {
"next": "14.1.3",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@commitlint/cli": "^19.1.0",
"@commitlint/config-conventional": "^19.1.0",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@unocss/postcss": "^0.58.6",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.1.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"postcss": "^8",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^9.5.1",
"prettier": "^3.2.5",
"typescript": "^5.2.2",
"unocss": "^0.58.6"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json}": [
"npm run lint",
"prettier --write"
]
},
"browserslist": [
"iOS >= 7",
"Android >= 4"
]
}
{
"name": "queyue-h5",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start -p 3001",
"lint": "eslint src --fix --ext .ts,.tsx,.js,.jsx,.mdx,.md,.json,.mjs --max-warnings 0"
},
"dependencies": {
"next": "14.1.3",
"react": "^18",
"react-dom": "^18",
"react-redux": "^9.1.0"
},
"devDependencies": {
"@commitlint/cli": "^19.1.0",
"@commitlint/config-conventional": "^19.1.0",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@unocss/postcss": "^0.58.6",
"autoprefixer": "^10.0.1",
"eslint": "^8",
"eslint-config-next": "14.1.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-prettier": "^5.1.3",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"postcss": "^8",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^9.5.1",
"prettier": "^3.2.5",
"typescript": "^5.2.2",
"unocss": "^0.58.6"
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json}": [
"npm run lint",
"prettier --write"
]
},
"browserslist": [
"iOS >= 7",
"Android >= 4"
]
}

@ -0,0 +1,39 @@
/**
* get client cookie
* @param {String} name cookie name
*/
export const getCookie = (name: string): string | undefined => {
const value = `; ${typeof window === 'undefined' ? '' : document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
const ppop = parts.pop();
if (ppop) {
return ppop.split(';').shift();
}
}
return '';
};
/**
* delete client cookie
* @param {String} name cookie name
*/
export const deleteCookie = (name: string) => {
const date = new Date();
date.setTime(date.getTime() - 10000);
document.cookie = name + '=; expire=' + date.toString();
};
/**
* set client cookie
* @param {String} name cookie name
* @param {String} value cookie value
*/
export const setCookie = (name: string, value: string) => {
const Days = 30;
const exp = new Date();
exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
document.cookie = name + '=' + value + ';expires=' + exp.toString();
};

@ -1,31 +0,0 @@
import localFont from 'next/font/local';
export const RegularFont = localFont({
src: '../../public/fonts/ping-fang-hei-ti-zhun-jian.ttf',
display: 'swap',
});
export const MediumFont = localFont({
src: '../../public/fonts/pingfang-sc-medium.otf',
display: 'swap',
});
export const SemiboldFont = localFont({
src: '../../public/fonts/pingfangsc-semibold.otf',
display: 'swap',
});
export const AbhayaFont = localFont({
src: '../../public/fonts/AlibabaPuHuiTi-3-65-Medium.woff2',
display: 'swap',
});
export const AbhayaSemiboldFont = localFont({
src: '../../public/fonts/abhayalibre-semibold.ttf',
display: 'swap',
});
export const XinYiJiXiangSongFont = localFont({
src: '../../public/fonts/Fontquan-XinYiJiXiangSong.ttf',
display: 'swap',
});

@ -0,0 +1,176 @@
/**
* @description API URL
*/
export const getApiUrl = (originUrl: string): string => {
// const baseUrl = import.meta.env.VITE_BASE_API_URL;
// if (process.env.NODE_ENV === 'prod' || process.env.NODE_ENV === 'grey') {
const baseurl = 'http://39.103.180.196:9012';
return `${baseurl}${originUrl}`;
// }
// return originUrl;
};
/**
* @description queryString
*/
export const getQueryString = (name: string): string | null => {
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
const r = window.location.search.substr(1).match(reg);
if (r != null) return decodeURIComponent(r[2]);
return null;
};
/**
* @description token
*/
export const getToken = (): string | null => {
return getQueryString('token');
};
/**
* @description isIos
*/
export const isIos = (): boolean => {
const u = navigator.userAgent;
return !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
};
/**
* @description
*/
export const getPlatform = (): string => {
const ua = navigator.userAgent;
if (ua.match(/MicroMessenger/i)) {
return 'MicroMessenger';
}
if (ua.match(/WeiBo/i)) {
return 'WeiBo';
}
if (ua.match(/QQ/i)) {
return 'QQ';
}
return '';
};
/**
* @description ios
*/
export const getDate = (date: string): Date => {
return new Date(date.replace(/-/g, '/'));
};
/**
* @description
*/
export const toPercent = (val: number) => {
return `${(Math.abs(val) * 100).toFixed(2)}%`;
};
/**
* @description
*/
export const copyMsg = (msg: string) => {
navigator.clipboard.writeText(msg);
};
/**
* ISO-
* @param {Number} date 13
* @return {String} 2021-03-12 20:21:02
*/
export const formatDate = (date: any) => {
const da = new Date(date).toISOString();
const ymd = da.split('T')[0];
const hms = da.split('T')[1];
return `${ymd} ${hms.split('.')[0]}`;
};
/**
* -
* @param {Number} date 13
* @return {String} 2021-03-12 20:21:02
*/
export const formatTime = (date: any) => {
const da = new Date(date);
const year = da.getFullYear();
const month = da.getMonth() + 1 > 9 ? da.getMonth() + 1 : `0${da.getMonth() + 1}`;
const day = da.getDate() > 9 ? da.getDate() : `0${da.getDate()}`;
const hours = da.getHours() > 9 ? da.getHours() : `0${da.getHours()}`;
const mins = da.getMinutes() > 9 ? da.getMinutes() : `0${da.getMinutes()}`;
const secs = da.getSeconds() > 9 ? da.getSeconds() : `0${da.getSeconds()}`;
return `${year}-${month}-${day} ${hours}:${mins}:${secs}`;
};
/**
*
* @param {String} val name
*/
export const getStringWidth = (val: string): number => {
let len = 0;
for (let i = 0; i < val.length; i++) {
const length = val.charCodeAt(i);
if (length >= 0 && length <= 128) {
len += 1;
} else {
len += 2;
}
}
return len;
};
/**
* base64 to blob
* @param {String} dataurl base64
*/
export const dataURLtoBlob = (dataurl: string) => {
const arr: any = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
};
/**
* blobfile
* @param {String} val name
*/
export const blobToFile = (theBlob: any, fileName: string) => {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
};
/**
*
* @param {String} url url
*/
export const openBlankLink = (url: string) => {
if (url.includes('https://') || url.includes('http://')) return window.open(url);
return window.open('https://' + url);
};
/**
*
* @param {String} url url
*/
export const scrollToBottom = () => {
const currentScroll = document.documentElement.scrollTop || document.body.scrollTop; // 已经被卷掉的高度
const clientHeight = document.documentElement.clientHeight; // 浏览器高度
const scrollHeight = document.documentElement.scrollHeight; // 总高度
if (scrollHeight - 10 > currentScroll + clientHeight) {
window.requestAnimationFrame(scrollToBottom);
window.scrollTo(0, currentScroll + (scrollHeight - currentScroll - clientHeight) / 2);
}
};
/**
*
*/
export const uniqueArray = (arr: any[], uniId: string) => {
const res = new Map();
return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
};

@ -0,0 +1,2 @@
export { default as request } from './request';
export { default as verifyResponse } from './verifyResponse';

@ -0,0 +1,17 @@
// server端
import { cookies } from 'next/headers';
export const nextFetchGet = async (api: string) => {
const nextCookies = cookies();
const token = nextCookies.get('token') || '';
const role = nextCookies.get('role');
const roleId = nextCookies.get('roleId');
const url = `${process.env.BASE_FETCH_URL}/api/be${api}`;
const res = await fetch(url, {
headers: token ? { Authorization: 'Bearer ' + token } : {},
});
if (!res.ok) {
throw new Error('Failed to fetch data');
}
return res.json();
};

@ -0,0 +1,112 @@
// client端请求
import { getCookie } from './cookie';
import { getApiUrl } from './helpers';
interface RequestOptions extends RequestInit {
responseType?: 'TEXT' | 'JSON' | 'BLOB' | 'ARRAYBUFFER' | 'text' | 'json' | 'blob' | 'arraybuffer';
body?: any;
}
// 发送数据请求
const request = async (url: string, config?: RequestOptions) => {
const finalUrl: string = getApiUrl(url);
const inital: RequestOptions = {
method: 'GET',
body: null,
headers: {
'Content-Type': 'application/json',
Authorization: getCookie('token') ? 'Bearer ' + getCookie('token') : '',
},
credentials: 'include',
cache: 'no-cache',
mode: 'cors',
responseType: 'JSON',
};
const configs: RequestOptions = {
...inital,
...config,
};
if (config && config.headers)
configs.headers = {
...inital.headers,
Authorization: getCookie('token') ? 'Bearer ' + getCookie('token') : '',
...config.headers,
};
// 基于fetch请求数据
const finalConfig: RequestInit = {
method: configs.method?.toUpperCase(),
credentials: configs.credentials,
mode: configs.mode,
cache: configs.cache,
headers: configs.headers,
body: configs.body,
};
return fetch(`${finalUrl}`, finalConfig)
.then((response: Response) => {
// 走到这边不一定是成功的:
// Fetch的特点的是只要服务器有返回结果不论状态码是多少它都认为是成功
const { status } = response;
if (status >= 200 && status < 400) {
// 真正成功获取数据
let result: any;
switch (configs.responseType && configs.responseType.toUpperCase()) {
case 'TEXT':
result = response.text();
break;
case 'JSON':
result = response.json();
break;
case 'BLOB':
result = response.blob();
break;
case 'ARRAYBUFFER':
result = response.arrayBuffer();
break;
default:
result = response.json();
}
return result;
}
// 失败的处理
return Promise.reject(response);
})
.catch((reason: any) => {
// @2:断网
if (typeof window !== 'undefined' && navigator && !navigator.onLine) {
console.log('Your network is break!');
}
// @1:状态码失败
if (reason && reason.status) {
switch (reason.status) {
case 400:
console.log('Please verify your info!');
break;
case 401:
console.log('Please Login!');
break;
case 403:
console.log('You have no access to this');
break;
case 500:
console.log("Oops, there's something wrong!");
break;
case 504:
console.log("Oops, there's something wrong!");
break;
default:
}
} else {
// @3:处理返回数据格式失败
console.log("Oops, there's something wrong!");
}
return Promise.reject(reason);
});
};
export default request;

@ -0,0 +1,9 @@
const verify = ({ code, message, data }: { code: number; message: string; data: any }) => {
if (code === 200) {
return data;
} else {
console.log(`错误code${code},${message}`);
}
};
export default verify;
Loading…
Cancel
Save