当前位置:网站首页>[Shanda conference] use typescript to reconstruct the project
[Shanda conference] use typescript to reconstruct the project
2022-06-22 16:03:00 【What does Xiao Li Mao eat today】
List of articles
TypeScript brief introduction
TypeScript yes JavaScript A superset of , Support ECMAScript 6 standard .TypeScript A free and open source programming language developed by Microsoft . Its design goal is to develop large-scale applications , It can be compiled into pure JavaScript, compiled JavaScript Can run on any browser .
To put it simply , You can think of it as a strongly typed JavaScript dialect , In the face of some large projects , Having type checking can always help developers reduce bug The probability of occurrence of . As the scale of the project continues to expand , I decided to introduce TypeScript , Refactoring for the project .
Dependent installation
First of all, let's install typescript
yarn add -D typescript
In order to make webpack Be able to recognize what we write ts Code , We also need to introduce ts-loader:
yarn add -D ts-loader
because typescript And react Well combined , We don't need to use it anymore babel Transform the code ,typescript I will compile myself . therefore , We can also change the original babel Dependencies are removed from the project :
yarn remove @babel/core @babel/plugin-proposal-class-properties @babel/preset-env @babel/preset-react babel-loader
however , because react And react-dom There is no implementation type definition by itself , So in order to use ts Writing react Code , Additional introduction of react and react-dom Of types rely on :
yarn add -D @types/react @types/react-dom
Now? , The required dependencies are already installed , We can write the code .
tsconfig.json
We open the terminal in the root directory of the project , Enter command :
npx typescript init
We will see an automatically generated... In the project root directory tsconfig.json file , We can configure it according to our actual needs , My configuration is as follows :
{
"compilerOptions": {
"target": "es2016",
"jsx": "react",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"baseUrl": "./",
"resolveJsonModule": true,
"paths": {
"Components/*": ["src/Components/*"],
"Utils/*": ["src/Utils/*"],
"Views/*": ["src/Views/*"]
}
},
"include": ["src/**/*"]
}
modify webpack.config.js
Because we refactor the project to typescript Project , therefore , We are no longer writing .js 、.jsx file , It is .ts and .tsx file , our webpack.config.js Changes need to be made accordingly :
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
devServer: {
static: path.join(__dirname, 'public'),
host: '127.0.0.1',
port: 9000,
},
resolve: {
extensions: ['.js', '.json', '.ts', '.tsx'],
alias: {
Components: path.join(__dirname, 'src/Components'),
Views: path.join(__dirname, 'src/Views'),
Utils: path.join(__dirname, 'src/Utils'),
},
},
entry: {
login: './src/Views/Login/index.tsx',
register: './src/Views/Register/index.tsx',
},
output: {
path: path.resolve(__dirname, './build'),
filename: '[name]/index.[chunkhash:8].js',
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
'css-loader',
'resolve-url-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.tsx?$/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'ts-loader',
},
],
},
{
test: /\.(png|jpg|gif|mp3)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1024, // Limit the size of the file ,1kb
},
},
],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'login/index.html',
chunks: ['login'],
template: './public/index.html',
}),
new HtmlWebpackPlugin({
filename: 'register/index.html',
chunks: ['register'],
template: './public/index.html',
}),
],
};
Modify old code
index.tsx
import React from 'react';
// let rootDiv = document.getElementById('root')
// if (!rootDiv) {
// rootDiv = document.createElement('div')
// rootDiv.setAttribute('id', 'root')
// }
// createRoot(rootDiv).render(<App />)
import {
render } from 'react-dom';
// import { createRoot } from 'react-dom/client';
import App from './App';
render(<App />, document.getElementById('root'));
The login page
import {
LoadingOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import {
Checkbox, Form, Input } from 'antd';
import {
globalMessage } from 'Components/GlobalMessage/GlobalMessage';
import {
LogoIcon, MinimizeIcon, RegisterIcon, ShutdownIcon } from 'Components/MyIcon/MyIcon';
import RippleButton from 'Components/RippleButton/RippleButton';
import {
Victor } from 'Components/Victor/Victor';
import React, {
useEffect, useRef, useState } from 'react';
import {
ajax } from 'Utils/Axios/Axios';
import {
decodeJWT } from 'Utils/Global';
import './App.scss';
export default function App() {
const [form] = Form.useForm();
const lastUserId = localStorage.getItem('userId');
const [userId, setUserId] = useState(lastUserId === 'null' ? '' : lastUserId);
const [userPassword, setUserPassword] = useState('');
const [rememberPassword, setRememberPassword] = useState(
localStorage.getItem('rememberPassword') === 'true'
);
useEffect(() => {
if (rememberPassword) {
(window as any).ipc.invoke('GET_LAST_PASSWORD').then((psw: string) => {
form.setFieldsValue({
password: psw });
});
}
}, []);
const [rotating, setRotating] = useState(false);
useEffect(() => {
if (rotating) {
const mainBody = mainBodyRef.current as HTMLDivElement;
mainBody.style.animationName = 'rotateOut';
let timeout = setTimeout(() => {
mainBody.style.animationName = 'rotateIn';
setShowRegister(!showRegister);
clearTimeout(timeout);
}, 250);
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}
}, [rotating]);
const [showRegister, setShowRegister] = useState(false);
useEffect(() => {
let timeout = setTimeout(() => {
setRotating(false);
clearTimeout(timeout)
}, 250);
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, [showRegister]);
const mainBodyRef = useRef<HTMLDivElement>(null);
// Set dynamic background
useEffect(() => {
const victor = Victor('header', 'canvas');
const theme = ['#ff1324', '#ff3851'];
if (victor)
victor(theme).set();
}, []);
const [isLogining, setIsLogining] = useState(false);
const login = () => {
form.validateFields(['username', 'password'])
.then(async (values) => {
setIsLogining(true);
const text = values.username;
const password = values.password;
const res = await ajax.post('/login_and_register/login', {
text, password });
if (res.code === 200) {
globalMessage.success(' Login successful ');
localStorage.setItem('rememberPassword', `${
rememberPassword}`);
localStorage.setItem('autoLogin', `${
autoLogin}`);
(window as any).ipc.send('SAFE_PASSWORD', rememberPassword, password);
localStorage.setItem('userId', text);
(window as any).ipc.send('USER_LOGIN', res.data.token, decodeJWT(res.data.token).email);
} else {
globalMessage.error(res.message);
setIsLogining(false);
}
})
.catch((err) => {
if (err.ajax) {
globalMessage.error(' Server error , Please try again later ');
} else {
const {
values } = err;
if (values.username === undefined) {
globalMessage.error(' Please enter user name or email !');
} else if (values.password === undefined) {
globalMessage.error(' Please input a password !');
}
}
setIsLogining(false);
});
};
/** * INFO: automatic logon */
const [autoLogin, setAutoLogin] = useState(localStorage.getItem('autoLogin') === 'true');
useEffect(() => {
let timeout = setTimeout(() => {
if (autoLogin) login();
clearTimeout(timeout);
}, 0);
return () => {
if (timeout) {
clearTimeout(timeout);
}
};
}, []);
return (
<>
<div id='dragBar' />
<div id='mainBody' ref={
mainBodyRef}>
<div id='header'>
<div id='titleBar'>
<LogoIcon style={
{
fontSize: '1.5rem' }} />
<span style={
{
fontFamily: 'Microsoft Yahei' }}> Yamada conference </span>
<button
className='titleBtn'
id='shutdown'
title=' sign out '
onClick={
() => {
(window as any).ipc.send('QUIT');
}}>
<ShutdownIcon />
</button>
<button
className='titleBtn'
id='minimize'
title=' To minimize the '
onClick={
() => {
(window as any).ipc.send('MINIMIZE_LOGIN_WINDOW');
}}>
<MinimizeIcon />
</button>
<button
className='titleBtn'
id='switch'
title={
showRegister ? ' Return to login ' : ' Registered account '}
onClick={
() => {
setRotating(true);
}}>
<RegisterIcon />
</button>
</div>
<div id='canvas' />
</div>
<div className='main'>
<div
className='form'
id='loginForm'
style={
{
display: showRegister ? 'none' : 'block' }}>
<Form form={
form}>
<Form.Item
name='username'
rules={
[
{
required: true,
message: ' Please enter user name or email ',
},
]}
initialValue={
userId}>
<Input
placeholder=' Please enter user name or email '
spellCheck={
false}
prefix={
<UserOutlined />}
size={
'large'}
style={
{
width: '65%' }}
onChange={
(event) => {
setUserId(event.target.value);
}}
/>
</Form.Item>
<Form.Item
name='password'
rules={
[
{
required: true,
message: ' Password cannot be empty ',
},
]}
initialValue={
userPassword}>
<Input.Password
placeholder=' Please input a password '
spellCheck={
false}
prefix={
<LockOutlined />}
size={
'large'}
style={
{
width: '65%' }}
onChange={
(event) => {
setUserPassword(event.target.value);
}}
/>
</Form.Item>
<Form.Item>
<Checkbox
style={
{
fontSize: '0.75rem' }}
checked={
rememberPassword}
onChange={
(e) => {
setRememberPassword(e.target.checked);
}}>
Remember the password
</Checkbox>
<Checkbox
style={
{
fontSize: '0.75rem' }}
checked={
autoLogin}
onChange={
(e) => {
setAutoLogin(e.target.checked);
}}>
automatic logon
</Checkbox>
</Form.Item>
<Form.Item>
<RippleButton
className='submit'
onClick={
login}
disabled={
isLogining}>
<>{
isLogining && <LoadingOutlined />} deng record </>
</RippleButton>
</Form.Item>
</Form>
</div>
<div
className='form'
id='registerForm'
style={
{
display: showRegister ? 'flex' : 'none' }}>
<RippleButton
className='submit'
onClick={
() => {
const registerUrl =
process.env.NODE_ENV === 'development'
? './register/'
: '../register/index.html';
window.open(registerUrl);
}}>
notes book
</RippleButton>
</div>
</div>
</div>
</>
);
}
Victor.ts
let CAV: any = {
FRONT: 0,
BACK: 1,
DOUBLE: 2,
SVGNS: 'http://www.w3.org/2000/svg',
Array: typeof Float32Array === 'function' ? Float32Array : Array,
Utils: {
isNumber: function (a: any) {
return !isNaN(parseFloat(a)) && isFinite(a);
},
}
};
(function () {
for (
var a = 0, b = ['ms', 'moz', 'webkit', 'o'], c = 0;
c < b.length && !window.requestAnimationFrame;
++c
)
(window.requestAnimationFrame = (window as any)[b[c] + 'RequestAnimationFrame']),
(window.cancelAnimationFrame =
(window as any)[b[c] + 'CancelAnimationFrame'] ||
(window as any)[b[c] + 'CancelRequestAnimationFrame']);
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function (b) {
var c = new Date().getTime(),
f = Math.max(0, 16 - (c - a)),
g = window.setTimeout(function () {
b(c + f);
}, f);
a = c + f;
return g;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function (a) {
clearTimeout(a);
};
})();
const randomInRange = function (a: number, b: number) {
return a + (b - a) * Math.random();
};
const clamp = function (a: number, b: number, c: number) {
a = Math.max(a, b);
return (a = Math.min(a, c));
};
CAV.Vector3 = {
create: function (a: any, b: any, c: any) {
var d = new CAV.Array(3);
this.set(d, a, b, c);
return d;
},
clone: function (a: any) {
var b = this.create();
this.copy(b, a);
return b;
},
set: function (a: any[], b: number, c: number, d: number) {
a[0] = b || 0;
a[1] = c || 0;
a[2] = d || 0;
return this;
},
setX: function (a: any[], b: number) {
a[0] = b || 0;
return this;
},
setY: function (a: any[], b: number) {
a[1] = b || 0;
return this;
},
setZ: function (a: any[], b: number) {
a[2] = b || 0;
return this;
},
copy: function (a: any[], b: any[]) {
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
return this;
},
add: function (a: any[], b: any[]) {
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
return this;
},
addVectors: function (a: any[], b: any[], c: any[]) {
a[0] = b[0] + c[0];
a[1] = b[1] + c[1];
a[2] = b[2] + c[2];
return this;
},
addScalar: function (a: any[], b: any) {
a[0] += b;
a[1] += b;
a[2] += b;
return this;
},
subtract: function (a: number[], b: number[]) {
a[0] -= b[0];
a[1] -= b[1];
a[2] -= b[2];
return this;
},
subtractVectors: function (a: number[], b: number[], c: number[]) {
a[0] = b[0] - c[0];
a[1] = b[1] - c[1];
a[2] = b[2] - c[2];
return this;
},
subtractScalar: function (a: number[], b: number) {
a[0] -= b;
a[1] -= b;
a[2] -= b;
return this;
},
multiply: function (a: number[], b: number[]) {
a[0] *= b[0];
a[1] *= b[1];
a[2] *= b[2];
return this;
},
multiplyVectors: function (a: number[], b: number[], c: number[]) {
a[0] = b[0] * c[0];
a[1] = b[1] * c[1];
a[2] = b[2] * c[2];
return this;
},
multiplyScalar: function (a: number[], b: number) {
a[0] *= b;
a[1] *= b;
a[2] *= b;
return this;
},
divide: function (a: number[], b: number[]) {
a[0] /= b[0];
a[1] /= b[1];
a[2] /= b[2];
return this;
},
divideVectors: function (a: number[], b: number[], c: number[]) {
a[0] = b[0] / c[0];
a[1] = b[1] / c[1];
a[2] = b[2] / c[2];
return this;
},
divideScalar: function (a: number[], b: number) {
b !== 0 ? ((a[0] /= b), (a[1] /= b), (a[2] /= b)) : ((a[0] = 0), (a[1] = 0), (a[2] = 0));
return this;
},
cross: function (a: number[], b: number[]) {
var c = a[0],
d = a[1],
e = a[2];
a[0] = d * b[2] - e * b[1];
a[1] = e * b[0] - c * b[2];
a[2] = c * b[1] - d * b[0];
return this;
},
crossVectors: function (a: number[], b: number[], c: number[]) {
a[0] = b[1] * c[2] - b[2] * c[1];
a[1] = b[2] * c[0] - b[0] * c[2];
a[2] = b[0] * c[1] - b[1] * c[0];
return this;
},
min: function (a: any[], b: number) {
a[0] < b && (a[0] = b);
a[1] < b && (a[1] = b);
a[2] < b && (a[2] = b);
return this;
},
max: function (a: any[], b: number) {
a[0] > b && (a[0] = b);
a[1] > b && (a[1] = b);
a[2] > b && (a[2] = b);
return this;
},
clamp: function (a: any, b: any, c: any) {
this.min(a, b);
this.max(a, c);
return this;
},
limit: function (a: any, b: number | null, c: number | null) {
var d = this.length(a);
b !== null && d < b ? this.setLength(a, b) : c !== null && d > c && this.setLength(a, c);
return this;
},
dot: function (a: number[], b: number[]) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
},
normalise: function (a: any) {
return this.divideScalar(a, this.length(a));
},
negate: function (a: any) {
return this.multiplyScalar(a, -1);
},
distanceSquared: function (a: number[], b: number[]) {
var c = a[0] - b[0],
d = a[1] - b[1],
e = a[2] - b[2];
return c * c + d * d + e * e;
},
distance: function (a: any, b: any) {
return Math.sqrt(this.distanceSquared(a, b));
},
lengthSquared: function (a: number[]) {
return a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
},
length: function (a: any) {
return Math.sqrt(this.lengthSquared(a));
},
setLength: function (a: any, b: number) {
var c = this.length(a);
c !== 0 && b !== c && this.multiplyScalar(a, b / c);
return this;
},
};
CAV.Vector4 = {
create: function (a: any, b: any, c: any) {
var d = new CAV.Array(4);
this.set(d, a, b, c);
return d;
},
set: function (a: any[], b: number, c: number, d: number, e: number) {
a[0] = b || 0;
a[1] = c || 0;
a[2] = d || 0;
a[3] = e || 0;
return this;
},
setX: function (a: any[], b: number) {
a[0] = b || 0;
return this;
},
setY: function (a: any[], b: number) {
a[1] = b || 0;
return this;
},
setZ: function (a: any[], b: number) {
a[2] = b || 0;
return this;
},
setW: function (a: any[], b: number) {
a[3] = b || 0;
return this;
},
add: function (a: any[], b: any[]) {
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
a[3] += b[3];
return this;
},
multiplyVectors: function (a: number[], b: number[], c: number[]) {
a[0] = b[0] * c[0];
a[1] = b[1] * c[1];
a[2] = b[2] * c[2];
a[3] = b[3] * c[3];
return this;
},
multiplyScalar: function (a: number[], b: number) {
a[0] *= b;
a[1] *= b;
a[2] *= b;
a[3] *= b;
return this;
},
min: function (a: any[], b: number) {
a[0] < b && (a[0] = b);
a[1] < b && (a[1] = b);
a[2] < b && (a[2] = b);
a[3] < b && (a[3] = b);
return this;
},
max: function (a: any[], b: number) {
a[0] > b && (a[0] = b);
a[1] > b && (a[1] = b);
a[2] > b && (a[2] = b);
a[3] > b && (a[3] = b);
return this;
},
clamp: function (a: any, b: any, c: any) {
this.min(a, b);
this.max(a, c);
return this;
},
};
CAV.Color = function (a: string, b: any) {
this.rgba = CAV.Vector4.create();
this.hex = a || '#000000';
this.opacity = CAV.Utils.isNumber(b) ? b : 1;
this.set(this.hex, this.opacity);
};
CAV.Color.prototype = {
set: function (a: string, b: any) {
var a = a.replace('#', ''),
c = a.length / 3;
this.rgba[0] = parseInt(a.substring(c * 0, c * 1), 16) / 255;
this.rgba[1] = parseInt(a.substring(c * 1, c * 2), 16) / 255;
this.rgba[2] = parseInt(a.substring(c * 2, c * 3), 16) / 255;
this.rgba[3] = CAV.Utils.isNumber(b) ? b : this.rgba[3];
return this;
},
hexify: function (a: string | number) {
a = Math.ceil(Number(a) * 255).toString(16);
a.length === 1 && (a = '0' + a);
return a;
},
format: function () {
var a = this.hexify(this.rgba[0]),
b = this.hexify(this.rgba[1]),
c = this.hexify(this.rgba[2]);
return (this.hex = '#' + a + b + c);
},
};
CAV.Object = function () {
this.position = CAV.Vector3.create();
};
CAV.Object.prototype = {
setPosition: function (a: any, b: any, c: any) {
CAV.Vector3.set(this.position, a, b, c);
return this;
},
};
CAV.Light = function (a: any, b: any) {
CAV.Object.call(this);
this.ambient = new CAV.Color(a || '#FFFFFF');
this.diffuse = new CAV.Color(b || '#FFFFFF');
this.ray = CAV.Vector3.create();
};
CAV.Light.prototype = Object.create(CAV.Object.prototype);
CAV.Vertex = function (a: any, b: any, c: any) {
this.position = CAV.Vector3.create(a, b, c);
};
CAV.Vertex.prototype = {
setPosition: function (a: any, b: any, c: any) {
CAV.Vector3.set(this.position, a, b, c);
return this;
},
};
CAV.Triangle = function (a: any, b: any, c: any) {
this.a = a || new CAV.Vertex();
this.b = b || new CAV.Vertex();
this.c = c || new CAV.Vertex();
this.vertices = [this.a, this.b, this.c];
this.u = CAV.Vector3.create();
this.v = CAV.Vector3.create();
this.centroid = CAV.Vector3.create();
this.normal = CAV.Vector3.create();
this.color = new CAV.Color();
this.polygon = document.createElementNS(CAV.SVGNS, 'polygon');
this.polygon.setAttributeNS(null, 'stroke-linejoin', 'round');
this.polygon.setAttributeNS(null, 'stroke-miterlimit', '1');
this.polygon.setAttributeNS(null, 'stroke-width', '1');
this.computeCentroid();
this.computeNormal();
};
CAV.Triangle.prototype = {
computeCentroid: function () {
this.centroid[0] = this.a.position[0] + this.b.position[0] + this.c.position[0];
this.centroid[1] = this.a.position[1] + this.b.position[1] + this.c.position[1];
this.centroid[2] = this.a.position[2] + this.b.position[2] + this.c.position[2];
CAV.Vector3.divideScalar(this.centroid, 3);
return this;
},
computeNormal: function () {
CAV.Vector3.subtractVectors(this.u, this.b.position, this.a.position);
CAV.Vector3.subtractVectors(this.v, this.c.position, this.a.position);
CAV.Vector3.crossVectors(this.normal, this.u, this.v);
CAV.Vector3.normalise(this.normal);
return this;
},
};
CAV.Geometry = function () {
this.vertices = [];
this.triangles = [];
this.dirty = false;
};
CAV.Geometry.prototype = {
update: function () {
if (this.dirty) {
var a, b;
for (a = this.triangles.length - 1; a >= 0; a--)
(b = this.triangles[a]), b.computeCentroid(), b.computeNormal();
this.dirty = false;
}
return this;
},
};
CAV.Plane = function (a: number, b: number, _c: number, d: number) {
let t0, t1;
CAV.Geometry.call(this);
this.width = a || 100;
this.height = b || 100;
this.segments = _c || 4;
this.slices = d || 4;
this.segmentWidth = this.width / this.segments;
this.sliceHeight = this.height / this.slices;
var e,
f,
g,
c = [];
e = this.width * -0.5;
f = this.height * 0.5;
for (a = 0; a <= this.segments; a++) {
c.push([]);
for (b = 0; b <= this.slices; b++)
(d = new CAV.Vertex(e + a * this.segmentWidth, f - b * this.sliceHeight)),
(c[a] as Array<any>).push(d),
this.vertices.push(d);
}
for (a = 0; a < this.segments; a++)
for (b = 0; b < this.slices; b++)
(d = c[a + 0][b + 0]),
(e = c[a + 0][b + 1]),
(f = c[a + 1][b + 0]),
(g = c[a + 1][b + 1]),
(t0 = new CAV.Triangle(d, e, f)),
(t1 = new CAV.Triangle(f, e, g)),
this.triangles.push(t0, t1);
};
CAV.Plane.prototype = Object.create(CAV.Geometry.prototype);
CAV.Material = function (a: any, b: any) {
this.ambient = new CAV.Color(a || '#444444');
this.diffuse = new CAV.Color(b || '#FFFFFF');
this.slave = new CAV.Color();
};
CAV.Mesh = function (a: any, b: any) {
CAV.Object.call(this);
this.geometry = a || new CAV.Geometry();
this.material = b || new CAV.Material();
this.side = CAV.FRONT;
this.visible = true;
};
CAV.Mesh.prototype = Object.create(CAV.Object.prototype);
CAV.Mesh.prototype.update = function (a: string | any[], b: any) {
var c, d, e, f, g;
this.geometry.update();
if (b)
for (c = this.geometry.triangles.length - 1; c >= 0; c--) {
d = this.geometry.triangles[c];
CAV.Vector4.set(d.color.rgba);
for (e = a.length - 1; e >= 0; e--)
(f = a[e]),
CAV.Vector3.subtractVectors(f.ray, f.position, d.centroid),
CAV.Vector3.normalise(f.ray),
(g = CAV.Vector3.dot(d.normal, f.ray)),
this.side === CAV.FRONT
? (g = Math.max(g, 0))
: this.side === CAV.BACK
? (g = Math.abs(Math.min(g, 0)))
: this.side === CAV.DOUBLE && (g = Math.max(Math.abs(g), 0)),
CAV.Vector4.multiplyVectors(
this.material.slave.rgba,
this.material.ambient.rgba,
f.ambient.rgba
),
CAV.Vector4.add(d.color.rgba, this.material.slave.rgba),
CAV.Vector4.multiplyVectors(
this.material.slave.rgba,
this.material.diffuse.rgba,
f.diffuse.rgba
),
CAV.Vector4.multiplyScalar(this.material.slave.rgba, g),
CAV.Vector4.add(d.color.rgba, this.material.slave.rgba);
CAV.Vector4.clamp(d.color.rgba, 0, 1);
}
return this;
};
CAV.Scene = function () {
this.meshes = [];
this.lights = [];
};
CAV.Scene.prototype = {
add: function (a: any) {
a instanceof CAV.Mesh && !~this.meshes.indexOf(a)
? this.meshes.push(a)
: a instanceof CAV.Light && !~this.lights.indexOf(a) && this.lights.push(a);
return this;
},
remove: function (a: any) {
a instanceof CAV.Mesh && ~this.meshes.indexOf(a)
? this.meshes.splice(this.meshes.indexOf(a), 1)
: a instanceof CAV.Light &&
~this.lights.indexOf(a) &&
this.lights.splice(this.lights.indexOf(a), 1);
return this;
},
};
CAV.Renderer = function () {
this.halfHeight = this.halfWidth = this.height = this.width = 0;
};
CAV.Renderer.prototype = {
setSize: function (a: any, b: any) {
if (!(this.width === a && this.height === b))
return (
(this.width = a),
(this.height = b),
(this.halfWidth = this.width * 0.5),
(this.halfHeight = this.height * 0.5),
this
);
},
clear: function () {
return this;
},
render: function () {
return this;
},
};
CAV.CanvasRenderer = function () {
CAV.Renderer.call(this);
this.element = document.createElement('canvas');
this.element.style.display = 'block';
this.context = this.element.getContext('2d');
this.setSize(this.element.width, this.element.height);
};
CAV.CanvasRenderer.prototype = Object.create(CAV.Renderer.prototype);
CAV.CanvasRenderer.prototype.setSize = function (a: any, b: any) {
CAV.Renderer.prototype.setSize.call(this, a, b);
this.element.width = a;
this.element.height = b;
this.context.setTransform(1, 0, 0, -1, this.halfWidth, this.halfHeight);
return this;
};
CAV.CanvasRenderer.prototype.clear = function () {
CAV.Renderer.prototype.clear.call(this);
this.context.clearRect(-this.halfWidth, -this.halfHeight, this.width, this.height);
return this;
};
CAV.CanvasRenderer.prototype.render = function (a: {
meshes: string | any[]; lights: any; }) {
CAV.Renderer.prototype.render.call(this, a);
var b, c, d, e, f;
this.clear();
this.context.lineJoin = 'round';
this.context.lineWidth = 1;
for (b = a.meshes.length - 1; b >= 0; b--)
if (((c = a.meshes[b]), c.visible)) {
c.update(a.lights, true);
for (d = c.geometry.triangles.length - 1; d >= 0; d--)
(e = c.geometry.triangles[d]),
(f = e.color.format()),
this.context.beginPath(),
this.context.moveTo(e.a.position[0], e.a.position[1]),
this.context.lineTo(e.b.position[0], e.b.position[1]),
this.context.lineTo(e.c.position[0], e.c.position[1]),
this.context.closePath(),
(this.context.strokeStyle = f),
(this.context.fillStyle = f),
this.context.stroke(),
this.context.fill();
}
return this;
};
export function Victor(container: string, anitOut: string) {
let J, l;
if (!!document.createElement('canvas').getContext) {
var t = {
width: 1.5,
height: 1.5,
depth: 10,
segments: 12,
slices: 6,
xRange: 0.8,
yRange: 0.1,
zRange: 1,
ambient: '#525252',
diffuse: '#FFFFFF',
speed: 0.0002,
};
var G = {
count: 2,
xyScalar: 1,
zOffset: 100,
ambient: '#002c4a',
diffuse: '#005584',
speed: 0.001,
gravity: 1200,
dampening: 0.95,
minLimit: 10,
maxLimit: null,
minDistance: 20,
maxDistance: 400,
autopilot: false,
draw: false,
bounds: CAV.Vector3.create(),
step: CAV.Vector3.create(
randomInRange(0.2, 1),
randomInRange(0.2, 1),
randomInRange(0.2, 1)
),
};
var m = 'canvas';
var E = 'svg';
var x = {
renderer: m,
};
var i: number,
n = Date.now();
var L = CAV.Vector3.create();
var k = CAV.Vector3.create();
var z = document.getElementById(container || 'container');
var w = document.getElementById(anitOut || 'anitOut');
var D: {
element: any; setSize: (arg0: number, arg1: number) => void; clear: () => void; width: number; height: number; halfWidth: any; halfHeight: any; render: (arg0: any) => void; }, I: {
remove: (arg0: any) => void; add: (arg0: any) => void; lights: string | any[]; }, h: any, q: {
vertices: string | any[]; segmentWidth: number; sliceHeight: number; dirty: boolean; }, y;
var g: any;
var r;
function C() {
F();
p();
s();
B();
v();
K((z as HTMLElement).offsetWidth, (z as HTMLElement).offsetHeight);
o();
}
function F() {
g = new CAV.CanvasRenderer();
H(x.renderer);
}
function H(N: string) {
if (D) {
(w as HTMLElement).removeChild(D.element);
}
switch (N) {
case m:
D = g;
break;
}
D.setSize((z as HTMLElement).offsetWidth, (z as HTMLElement).offsetHeight);
(w as HTMLElement).appendChild(D.element);
}
function p() {
I = new CAV.Scene();
}
function s() {
I.remove(h);
D.clear();
q = new CAV.Plane(t.width * D.width, t.height * D.height, t.segments, t.slices);
y = new CAV.Material(t.ambient, t.diffuse);
h = new CAV.Mesh(q, y);
I.add(h);
var N, O;
for (N = q.vertices.length - 1; N >= 0; N--) {
O = q.vertices[N];
O.anchor = CAV.Vector3.clone(O.position);
O.step = CAV.Vector3.create(
randomInRange(0.2, 1),
randomInRange(0.2, 1),
randomInRange(0.2, 1)
);
O.time = randomInRange(0, Math.PI * 2);
}
}
function B() {
var O, N;
for (O = I.lights.length - 1; O >= 0; O--) {
N = I.lights[O];
I.remove(N);
}
D.clear();
for (O = 0; O < G.count; O++) {
N = new CAV.Light(G.ambient, G.diffuse);
N.ambientHex = N.ambient.format();
N.diffuseHex = N.diffuse.format();
I.add(N);
N.mass = randomInRange(0.5, 1);
N.velocity = CAV.Vector3.create();
N.acceleration = CAV.Vector3.create();
N.force = CAV.Vector3.create();
}
}
function K(O: number, N: number) {
D.setSize(O, N);
CAV.Vector3.set(L, D.halfWidth, D.halfHeight);
s();
}
function o() {
i = Date.now() - n;
u();
M();
requestAnimationFrame(o);
}
function u() {
var Q,
P,
O,
R,
T,
V,
U,
S = t.depth / 2;
CAV.Vector3.copy(G.bounds, L);
CAV.Vector3.multiplyScalar(G.bounds, G.xyScalar);
CAV.Vector3.setZ(k, G.zOffset);
for (R = I.lights.length - 1; R >= 0; R--) {
T = I.lights[R];
CAV.Vector3.setZ(T.position, G.zOffset);
var N = clamp(
CAV.Vector3.distanceSquared(T.position, k),
G.minDistance,
G.maxDistance
);
var W = (G.gravity * T.mass) / N;
CAV.Vector3.subtractVectors(T.force, k, T.position);
CAV.Vector3.normalise(T.force);
CAV.Vector3.multiplyScalar(T.force, W);
CAV.Vector3.set(T.acceleration);
CAV.Vector3.add(T.acceleration, T.force);
CAV.Vector3.add(T.velocity, T.acceleration);
CAV.Vector3.multiplyScalar(T.velocity, G.dampening);
CAV.Vector3.limit(T.velocity, G.minLimit, G.maxLimit);
CAV.Vector3.add(T.position, T.velocity);
}
for (V = q.vertices.length - 1; V >= 0; V--) {
U = q.vertices[V];
Q = Math.sin(U.time + U.step[0] * i * t.speed);
P = Math.cos(U.time + U.step[1] * i * t.speed);
O = Math.sin(U.time + U.step[2] * i * t.speed);
CAV.Vector3.set(
U.position,
t.xRange * q.segmentWidth * Q,
t.yRange * q.sliceHeight * P,
t.zRange * S * O - S
);
CAV.Vector3.add(U.position, U.anchor);
}
q.dirty = true;
}
function M() {
D.render(I);
}
J = (O: any) => {
var Q,
N,
S = O;
var P = function (T: any) {
for (Q = 0, l = I.lights.length; Q < l; Q++) {
N = I.lights[Q];
N.ambient.set(T);
N.ambientHex = N.ambient.format();
}
};
var R = function (T: any) {
for (Q = 0, l = I.lights.length; Q < l; Q++) {
N = I.lights[Q];
N.diffuse.set(T);
N.diffuseHex = N.diffuse.format();
}
};
return {
set: function () {
P(S[0]);
R(S[1]);
},
};
};
function v() {
window.addEventListener('resize', j);
}
function A(N: {
x: any; y: number; }) {
CAV.Vector3.set(k, N.x, D.height - N.y);
CAV.Vector3.subtract(k, L);
}
function j(N: any) {
K((z as HTMLElement).offsetWidth, (z as HTMLElement).offsetHeight);
M();
}
C();
}
return J;
}
Registration page
import {
KeyOutlined,
LockFilled,
LockOutlined,
MailOutlined,
UserOutlined
} from '@ant-design/icons';
import {
Button, Form, Input, notification, Select } from 'antd';
import React, {
useEffect, useState } from 'react';
import {
ajax } from 'Utils/Axios/Axios';
import './App.scss';
export default function App() {
const [sendCaptchaTick, setSendCaptchaTick] = useState(0);
const [sendCaptchaInterval, setSendCaptchaInterval] = useState<NodeJS.Timeout | null>(null);
useEffect(() => {
return () => {
if (sendCaptchaInterval) {
clearInterval(sendCaptchaInterval);
setSendCaptchaInterval(null);
}
};
}, []);
const [chosenEmail, setChosenEmail] = useState('@mail.sdu.edu.cn');
const [form] = Form.useForm();
const [isRegistering, setIsRegistering] = useState(false);
const {
Option } = Select;
return (
<div className='register' style={
{
backgroundImage: `url(${
require('./bg.jpg').default})` }}>
<div className='container'>
<div className='title'> Yamada conference Registered account </div>
<div className='inputs'>
<Form
onFinish={
(values) => {
submitForm(values, chosenEmail, setIsRegistering);
}}
autoComplete='off'
form={
form}>
<Form.Item
rules={
[
{
required: true,
message: ' Please enter a nickname for registration ',
},
{
pattern: /^[^@]+$/,
message: ' No... Is allowed in nicknames "@"',
},
]}
name={
'username'}>
<Input placeholder=' Please enter your nickname ' prefix={
<UserOutlined />} />
</Form.Item>
<Form.Item
rules={
[
{
required: true, message: ' Please input a password ' },
{
min: 6,
message: ' Please enter a length greater than 6 Bit code ',
},
]}
name={
'password'}>
<Input.Password placeholder=' Please input a password ' prefix={
<LockOutlined />} />
</Form.Item>
<Form.Item
validateTrigger='onBlur'
rules={
[
{
required: true,
message: ' Please input the password again ',
},
({
getFieldValue }) => ({
validator(rule, value) {
if (getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(' The two passwords are not the same ');
},
}),
]}
name={
'passwordCheck'}>
<Input.Password placeholder=' Please input the password again ' prefix={
<LockFilled />} />
</Form.Item>
<Form.Item
rules={
[
{
required: true,
message: ' Please enter email address ',
},
{
pattern: /^[^@]+$/,
message: ' Please do not enter again "@"',
},
]}
name={
'email'}>
<Input
placeholder=' Please enter email address '
addonAfter={
<Select defaultValue={
chosenEmail} onSelect={
setChosenEmail}>
<Option value='@mail.sdu.edu.cn'>@mail.sdu.edu.cn</Option>
<Option value='@sdu.edu.cn'>@sdu.edu.cn</Option>
</Select>
}
prefix={
<MailOutlined />}
/>
</Form.Item>
<Form.Item
rules={
[
{
required: true,
message: ' Please enter the verification code ',
},
]}
name={
'captcha'}>
<Input placeholder=' Please enter email verification code ' prefix={
<KeyOutlined />} />
</Form.Item>
<Form.Item>
<div style={
{
display: 'flex', justifyContent: 'space-around' }}>
<Button
disabled={
sendCaptchaTick > 0}
loading={
sendCaptchaTick === -1}
onClick={
() => {
form.validateFields(['username', 'email'])
.then((values) => {
setSendCaptchaTick(-1);
const {
username, email } = values;
ajax.post('/login_and_register/code', {
username,
email: `${
email}${
chosenEmail}`,
}).then((response) => {
if (response.code === 200) {
notification.success({
message: ' Verification code sent successfully ',
description:
' Verification code has been sent , Please go to the mailbox to check the verification code ',
});
sendCaptcha(
setSendCaptchaTick,
setSendCaptchaInterval
);
} else {
notification.error({
message: ' Verification code sending failed ',
description: response.message,
});
}
});
})
.catch(() => {
});
}}>
{
sendCaptchaTick > 0
? `${
sendCaptchaTick} It can be sent again in seconds `
: ' Send verification code '}
</Button>
<Button loading={
isRegistering} type='primary' htmlType='submit'>
register
</Button>
</div>
</Form.Item>
</Form>
</div>
</div>
</div>
);
}
async function submitForm(values: {
username: any; password: any; captcha: any; email: any; }, chosenEmail: string, setIsRegistering: {
(value: React.SetStateAction<boolean>): void; (arg0: boolean): void; }) {
setIsRegistering(true);
const {
username, password, captcha, email } = values;
const res = await ajax.post('/login_and_register/register', {
username,
password,
email: `${
email}${
chosenEmail}`,
code: captcha,
});
if (res.code === 200) {
notification.success({
message: ' Registered successfully ', description: ' Registered successfully , Please go to login ' });
} else {
notification.error({
message: ' Registration failed ', description: res.message });
}
setIsRegistering(false);
}
function sendCaptcha(setSendCaptchaTick: {
(value: React.SetStateAction<number>): void; (arg0: number): void; }, setSendCaptchaInterval: {
(value: React.SetStateAction<NodeJS.Timeout | null>): void; (arg0: NodeJS.Timer | null): void; }) {
let sendCaptchaTick = 60;
setSendCaptchaTick(sendCaptchaTick);
const interval = setInterval(() => {
setSendCaptchaTick(--sendCaptchaTick);
if (sendCaptchaTick === 0) {
clearInterval(interval);
setSendCaptchaInterval(null);
}
}, 1000);
setSendCaptchaInterval(interval);
}
Redux
actions.ts
/** * action type */
import {
ChatWebSocketType, DEVICE_TYPE } from "Utils/Constraints";
import {
DeviceInfo } from "Utils/Types";
const UNDEFINED_ACTION = 'UNDEFINED_ACTION'
// Select the current chat object ID
export const SET_NOW_CHATTING_ID = 'SET_NOW_CHATTING_ID';
export function setNowChattingId(nowChattingId: number | null) {
return {
type: SET_NOW_CHATTING_ID, nowChattingId };
}
export const SET_NOW_WEBRTC_FRIEND_ID = 'SET_NOW_WEBRTC_FRIEND_ID';
export function setNowWebrtcFriendId(nowWebrtcFriendId: number | null) {
return {
type: SET_NOW_WEBRTC_FRIEND_ID, nowWebrtcFriendId };
}
// Update available audio and video devices
export const UPDATE_AVAILABLE_VIDEO_DEVICES = 'UPDATE_AVAILABLE_VIDEO_DEVICES';
export const UPDATE_AVAILABLE_AUDIO_DEVICES = 'UPDATE_AVAILABLE_AUDIO_DEVICES';
export function updateAvailableDevices(deviceType: string, devices: DeviceInfo[]) {
switch (deviceType) {
case DEVICE_TYPE.VIDEO_DEVICE:
return {
type: UPDATE_AVAILABLE_VIDEO_DEVICES, devices };
case DEVICE_TYPE.AUDIO_DEVICE:
return {
type: UPDATE_AVAILABLE_AUDIO_DEVICES, devices };
default:
return {
type: UNDEFINED_ACTION };
}
}
// Replace the selected audio and video equipment
export const EXCHANGE_VIDEO_DEVICE = 'EXCHANGE_VIDEO_DEVICE';
export const EXCHANGE_AUDIO_DEVICE = 'EXCHANGE_AUDIO_DEVICE';
export function exchangeMediaDevice(deviceType: string, deviceInfo: DeviceInfo) {
switch (deviceType) {
case DEVICE_TYPE.VIDEO_DEVICE:
return {
type: EXCHANGE_VIDEO_DEVICE, deviceInfo };
case DEVICE_TYPE.AUDIO_DEVICE:
return {
type: EXCHANGE_AUDIO_DEVICE, deviceInfo };
default:
return {
type: UNDEFINED_ACTION };
}
}
// Set user Token
export const SET_AUTH_TOKEN = 'SET_AUTH_TOKEN';
export function setAuthToken(token: string) {
return {
type: SET_AUTH_TOKEN, token };
}
// Manage unread messages
export const ADD_UNREAD_MESSAGE = 'ADD_UNREAD_MESSAGE';
export const REMOVE_UNREAD_MESSAGES = 'REMOVE_UNREAD_MESSAGES';
export function setUnreadMessages(operation: string, payload: any) {
return {
type: operation, payload };
}
// Manage message logging
export const INIT_MESSAGE_HISTORY = 'INIT_MESSAGE_HISTORY';
export const SYNC_CLOUD_MESSAGE_HISTORY = 'SYNC_CLOUD_MESSAGE_HISTORY';
export const GET_MORE_MESSAGE_HISTORY = 'GET_MORE_MESSAGE_HISTORY';
export const ADD_MESSAGE_HISTORY = 'ADD_MESSAGE_HISTORY';
export const REMOVE_MESSAGE_HISTORY = 'REMOVE_MESSAGE_HISTORY';
export function setMessageHistory(operation: string, payload: any) {
return {
type: operation, payload };
}
// Apply call status
export const SET_CALL_STATUS = 'SET_CALL_STATUS';
export function setCallStatus(status: ChatWebSocketType) {
return {
type: SET_CALL_STATUS, status };
}
reducers.ts
import {
combineReducers } from '@reduxjs/toolkit';
import {
CALL_STATUS_FREE, ChatWebSocketType } from 'Utils/Constraints';
import {
ChatMessage, DeviceInfo } from 'Utils/Types';
import {
ADD_MESSAGE_HISTORY,
ADD_UNREAD_MESSAGE,
EXCHANGE_AUDIO_DEVICE,
EXCHANGE_VIDEO_DEVICE,
GET_MORE_MESSAGE_HISTORY,
INIT_MESSAGE_HISTORY,
REMOVE_MESSAGE_HISTORY,
REMOVE_UNREAD_MESSAGES,
SET_AUTH_TOKEN,
SET_CALL_STATUS,
SET_NOW_CHATTING_ID,
SET_NOW_WEBRTC_FRIEND_ID,
SYNC_CLOUD_MESSAGE_HISTORY,
UPDATE_AVAILABLE_AUDIO_DEVICES,
UPDATE_AVAILABLE_VIDEO_DEVICES
} from './actions';
function setNowChattingId(state = null, action: {
type: string, nowChattingId: number | null }) {
if (action.type === SET_NOW_CHATTING_ID) {
return action.nowChattingId;
}
return state;
}
function setNowWebrtcFriendId(state = null, action: {
type: string, nowWebrtcFriendId: number | null }) {
if (action.type === SET_NOW_WEBRTC_FRIEND_ID) {
return action.nowWebrtcFriendId;
}
return state;
}
function updateAvailableVideoDevices(state = new Array(), action: {
type: string, devices: DeviceInfo[] }): Array<DeviceInfo> {
switch (action.type) {
case UPDATE_AVAILABLE_VIDEO_DEVICES:
return action.devices;
default:
return state;
}
}
function updateAvailableAudioDevices(state = new Array(), action: {
type: string, devices: DeviceInfo[] }): Array<DeviceInfo> {
switch (action.type) {
case UPDATE_AVAILABLE_AUDIO_DEVICES:
return action.devices;
default:
return state;
}
}
function exchangeVideoDevice(state = null, action: {
type: string, deviceInfo: DeviceInfo }) {
switch (action.type) {
case EXCHANGE_VIDEO_DEVICE:
localStorage.setItem('usingVideoDevice', action.deviceInfo.deviceId);
return action.deviceInfo;
default:
return state;
}
}
function exchangeAudioDevice(state = null, action: {
type: string, deviceInfo: DeviceInfo }) {
switch (action.type) {
case EXCHANGE_AUDIO_DEVICE:
localStorage.setItem('usingAudioDevice', action.deviceInfo.deviceId);
return action.deviceInfo;
default:
return state;
}
}
function setAuthToken(state = null, action: {
type: string, token: string }) {
if (action.type === SET_AUTH_TOKEN) return action.token;
return state;
}
function setUnreadMessages(state = {
}, action: {
type: string, payload: any })
: {
[user: string]: ChatMessage[]
} {
switch (action.type) {
case ADD_UNREAD_MESSAGE:
const {
fromId, toId, myId } = action.payload;
const messageOwnerId = fromId === myId ? toId : fromId;
const newArr = state[`${
messageOwnerId}` as keyof typeof state]
? [...state[`${
messageOwnerId}` as keyof typeof state]]
: new Array();
newArr.push(action.payload);
return Object.assign({
}, state, {
[`${
messageOwnerId}`]: newArr,
});
case REMOVE_UNREAD_MESSAGES:
const {
userId } = action.payload;
const newState = Object.assign({
}, state);
delete newState[`${
userId}` as keyof typeof newState];
return newState;
default:
return state;
}
}
function setMessageHistory(state = {
}, action: {
type: string, payload: any }) {
switch (action.type) {
case INIT_MESSAGE_HISTORY:
return action.payload;
case SYNC_CLOUD_MESSAGE_HISTORY:
return Object.assign({
}, state, action.payload);
case GET_MORE_MESSAGE_HISTORY:
const chatId = action.payload.chatId as keyof typeof state
const newArr1 = state[`${
chatId}`] ? [...state[`${
chatId}`]] : new Array();
newArr1.unshift(action.payload);
return Object.assign({
}, state, {
[`${
chatId}`]: newArr1,
});
case ADD_MESSAGE_HISTORY:
const {
fromId, toId, myId } = action.payload;
const messageOwnerId = (fromId === myId ? toId : fromId) as keyof typeof state;
const newArr2 = state[`${
messageOwnerId}`]
? [...state[`${
messageOwnerId}`]]
: new Array();
newArr2.push(action.payload);
const newMessages = Object.assign({
}, state, {
[`${
messageOwnerId}`]: newArr2,
});
return newMessages;
case REMOVE_MESSAGE_HISTORY:
const newState = Object.assign({
}, state);
const userId = action.payload.userId as keyof typeof newState;
delete newState[`${
userId}`];
return newState;
default:
return state;
}
}
function setCallStatus(state = CALL_STATUS_FREE, action: {
type: string, status: ChatWebSocketType }) {
if (action.type === SET_CALL_STATUS) {
return action.status;
}
return state;
}
const reducers = combineReducers({
nowChattingId: setNowChattingId,
nowWebrtcFriendId: setNowWebrtcFriendId,
availableVideoDevices: updateAvailableVideoDevices,
availableAudioDevices: updateAvailableAudioDevices,
usingVideoDevice: exchangeVideoDevice,
usingAudioDevice: exchangeAudioDevice,
authToken: setAuthToken,
unreadMessages: setUnreadMessages,
messageHistory: setMessageHistory,
callStatus: setCallStatus,
});
export default reducers;
store.ts
import {
configureStore } from '@reduxjs/toolkit';
import reducers from './reducers';
const store = configureStore({
reducer: reducers,
});
export default store;
Add new code
In order to improve development efficiency and code reuse ability , I am here src/Utils Three new files are defined under the folder :
- Constraints.ts: Some global constants are defined
- Global.ts: Defines some scattered 、 But global functions that are often referenced by various components
- Types.ts: Some types defined for development convenience
Constraints.ts
/** * This file is used to store some constants */
// Audio and video equipment
export const DEVICE_TYPE = {
VIDEO_DEVICE: 'video',
AUDIO_DEVICE: 'audio',
};
/** * Call status */
export const CALL_STATUS_FREE = 0;
export const CALL_STATUS_OFFERING = 1;
export const CALL_STATUS_OFFERED = 2;
export const CALL_STATUS_ANSWERING = 3;
export const CALL_STATUS_CALLING = 4;
/** * Reply to friend application */
export const ACCEPT_FRIEND_REQUEST = 2;
export const REJECT_FRIEND_REQUEST = 1;
export const NO_OPERATION_FRIEND_REQUEST = -1;
/** * Chat system WebSocket type Parameters */
export enum ChatWebSocketType {
UNDEFINED_0, // Undefined 0 placeholder
CHAT_SEND_PRIVATE_MESSAGE, // Send private chat messages
CHAT_READ_MESSAGE, // Sign for private chat messages
CHAT_SEND_FRIEND_REQUEST, // Send friend request
CHAT_ANSWER_FRIEND_REQUEST, // Respond to friend requests
CHAT_PRIVATE_WEBRTC_OFFER, // Send a video chat request OFFER
CHAT_PRIVATE_WEBRTC_ANSWER, // Respond to video chat requests ANSWER
CHAT_PRIVATE_WEBRTC_CANDIDATE, // Video chat ICE candidates
CHAT_PRIVATE_WEBRTC_DISCONNECT, // Disconnect video chat
}
Global.ts
/** * This file is used to store some global functions that are not easy to classify */
import jwtDecode from 'jwt-decode';
import {
DEVICE_TYPE } from './Constraints';
import store from './Store/store';
import {
DeviceInfo } from './Types';
/** * Used to return mainContent Modal screen mask layer mount DOM * @returns Id The value is 'mainContent' Of DOM */
function getMainContent() {
const content = document.getElementById('mainContent');
if (content) {
return content
} else {
return document.body
}
}
/** * Because of direct use jwtDecode Illegal parsing token Will report a mistake , So package it * @param {string} token * @returns The resolved token */
function decodeJWT(token: string): any {
try {
return jwtDecode(token);
} catch (error: any) {
if (error.message === 'Invalid token specified') return undefined;
console.log(error);
}
}
/** * Get device stream function after encapsulation * @param {string} device Device type DEVICE_TYPE * @returns */
function getDeviceStream(device: string) {
switch (device) {
case DEVICE_TYPE.AUDIO_DEVICE:
const audioDevice = store.getState().usingAudioDevice as DeviceInfo;
const audioConstraints = {
deviceId: {
exact: audioDevice.deviceId,
},
noiseSuppression: localStorage.getItem('noiseSuppression') !== 'false',
echoCancellation: localStorage.getItem('echoCancellation') !== 'false',
};
return navigator.mediaDevices.getUserMedia({
audio: audioConstraints });
case DEVICE_TYPE.VIDEO_DEVICE:
const videoDevice = store.getState().usingVideoDevice as DeviceInfo;
const videoConstraints = {
deviceId: {
exact: videoDevice.deviceId,
},
width: 1920,
height: 1080,
frameRate: {
max: 30,
},
};
return navigator.mediaDevices.getUserMedia({
video: videoConstraints,
});
default:
return Promise.resolve(new MediaStream());
}
}
export const A_SECOND_TIME = 1000;
export const A_MINUTE_TIME = 60 * A_SECOND_TIME;
export const AN_HOUR_TIME = 60 * A_MINUTE_TIME;
export const A_DAY_TIME = 24 * AN_HOUR_TIME;
export const isSameDay = (timeStampA: string | number | Date, timeStampB: string | number | Date) => {
const dateA = new Date(timeStampA);
const dateB = new Date(timeStampB);
return dateA.setHours(0, 0, 0, 0) === dateB.setHours(0, 0, 0, 0);
};
export const isSameWeek = (timeStampA: string | number | Date, timeStampB: string | number | Date) => {
let A = new Date(timeStampA).setHours(0, 0, 0, 0);
let B = new Date(timeStampB).setHours(0, 0, 0, 0);
const timeDistance = Math.abs(A - B);
return timeDistance / A_DAY_TIME;
};
export const isSameYear = (timeStampA: string | number | Date, timeStampB: string | number | Date) => {
const dateA = new Date(timeStampA);
const dateB = new Date(timeStampB);
dateA.setHours(0, 0, 0, 0);
dateB.setHours(0, 0, 0, 0);
dateA.setMonth(0, 1);
dateB.setMonth(0, 1);
return dateA.getFullYear() === dateB.getFullYear();
};
export const translateDayNumberToDayChara = (day: any) => {
if (typeof day === 'number') {
day = day % 7;
}
switch (day) {
case 0:
return ' Sunday ';
case 1:
return ' Monday ';
case 2:
return ' Tuesday ';
case 3:
return ' Wednesday ';
case 4:
return ' Thursday ';
case 5:
return ' Friday ';
case 6:
return ' Saturday ';
default:
return String(day);
}
};
export {
decodeJWT, getMainContent, getDeviceStream };
Types.ts
import {
ReactNode } from "react"
export interface ChatMessage {
date: number,
fromId: number,
id: number,
message: string,
toId: number,
myId?: number,
userId: number
}
export interface DeviceInfo {
webLabel?: ReactNode
deviceId: string,
label: string,
}
export interface UserInfo {
email: string,
exp: number,
iat: number,
id: number,
iss: string,
profile: string,
role: [
{
authority: string,
id: number
}
],
sub: string,
username: string
}
边栏推荐
猜你喜欢
随机推荐
How safe is the new bond
快速排序quick_sort
C语言学习-17-函数作为参数传入函数
B树和B+树
Navicat Premium 连接Oracle 数据库(图文教程)
Applet development - Custom expiration cache
[VTK] model rotation and Translation
普通人怎么在一年内赚到100万?
Discourse 新用户可插入媒体的数量
着力打造网红产品,新捷途X70S焕新上市,8.79万起售
Turn to: jackwelch: strategy is to think less and be quick to act
Batch export excel zip using zipfile, openpyxl and flask
MongoDB在腾讯零售优码中的应用
DevSecOps: CI/CD 流水线安全的最佳实践
【山大会议】私人聊天频道 WebRTC 工具类
ORB_VI思想框架
Pymssql Module User Guide
phantomJs使用总结
pymssql模块使用指南
华为云HCDEZ专场暨分布式技术峰会:华为云分布式云原生技术与实践之路









