更新界面 可以部署一版了

This commit is contained in:
LittleBoy 2023-08-22 23:03:23 +08:00
parent 07347cba09
commit 488001574a
29 changed files with 765 additions and 102 deletions

View File

@ -1,9 +1,14 @@
import React from 'react'
import React, {useEffect} from 'react'
import './assets/global.scss'
import {AppRouter} from "./pages/Router.tsx";
import {useUserinfoStore} from "./store/userinfoStore.ts";
export function App() {
const {init} = useUserinfoStore();
useEffect(()=>{
init(); // 初始化用户信息
}, [])
return (<div>
<AppRouter/>
</div>)

View File

@ -0,0 +1,24 @@
import {List, Space} from "@douyinfe/semi-ui"
import {Link} from "react-router-dom";
import {formatDate} from "../../../utils/date.ts";
import {AppModel} from "../../../model";
export const AppList = (props: {
list: AppModel[];
onItemClick?: (app: AppModel) => void;
}) => {
return (<div className="app-list-wrapper">
{props.list.map(it => (
<div key={it.id} className="list-link-item flex space-between" onClick={() =>{
props.onItemClick?.(it)
}}>
<Space className="space">
<span>{it.id}</span>
<span>{it.title}</span>
<span>{formatDate(it.create_time)}</span>
</Space>
<span></span>
</div>
))}
</div>)
}

View File

@ -1,13 +0,0 @@
import React from "react";
export type ResultProps = {
extra: React.ReactNode;
title: React.ReactNode;
status: number | string;
};
export const Result: React.FC<ResultProps> = (props) => {
return <div>
<div className="title">{props.title}</div>
<div className="extra">{props.extra}</div>
</div>
}

View File

@ -0,0 +1,38 @@
import React from "react";
import './result.scss'
import {CheckCircleFilled} from "../icons/CheckCircleFilled.tsx";
import {NotFound} from "../icons/NotFound.tsx";
type Status = 'success' | 'error' | 'info' | 'warning' | '404' | '403' | '500';
export type ResultProps = {
extra?: React.ReactNode;
title?: React.ReactNode;
subTitle?: React.ReactNode;
icon?: React.ReactNode;
status?: Status //number | string;
};
export const IconMap: {
[key in Status]: React.ReactNode
} = {
success: <CheckCircleFilled/>,
error: <CheckCircleFilled/>,
info: <CheckCircleFilled/>,
warning: <CheckCircleFilled/>,
// error: CloseCircleFilled,
// info: ExclamationCircleFilled,
// warning: WarningFilled,
'404': <NotFound/>,
'500': <NotFound/>,
'403': <NotFound/>,
// '500': serverError,
// '403': unauthorized,
};
export const Index: React.FC<ResultProps> = (props) => {
const icon = props.icon || (props.status ? IconMap[props.status] : <></>)
return <div className="result-wrapper">
<div className="icon">{icon}</div>
<div className="title">{props.title}</div>
{props.subTitle && <div className="sub-title">{props.subTitle}</div>}
<div className="extra">{props.extra}</div>
</div>
}

View File

@ -0,0 +1,26 @@
.result-wrapper {
text-align: center;
padding: 48px 32px;
.icon {
margin-bottom: 24px;
color:#52c41a;
font-size: 72px;
}
.title {
color: rgba(0, 0, 0, 0.88);
font-size: 24px;
line-height: 1.3333333333333333;
margin-block: 8px;
}
.sub-title{
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
line-height: 1.5714285714285714;
}
.extra {
margin: 24px 0 0 0;
}
}

View File

@ -0,0 +1,16 @@
import React from "react";
export type SvgProps = {} & React.SVGProps<SVGElement>;
export const CheckCircleFilled: React.FC<SvgProps> = (props) => {
return (<svg
viewBox="64 64 896 896"
focusable="false"
data-icon="check-circle"
width="1em" height="1em"
fill="currentColor"
aria-hidden="true"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"></path>
</svg>)
}

View File

@ -0,0 +1,157 @@
import React from "react";
export const NotFound: React.FC = () => {
return (<svg width="252" height="294">
<defs>
<path d="M0 .387h251.772v251.772H0z"></path>
</defs>
<g fill="none" fill-rule="evenodd">
<g transform="translate(0 .012)">
<mask fill="#fff"></mask>
<path
d="M0 127.32v-2.095C0 56.279 55.892.387 124.838.387h2.096c68.946 0 124.838 55.892 124.838 124.838v2.096c0 68.946-55.892 124.838-124.838 124.838h-2.096C55.892 252.16 0 196.267 0 127.321"
fill="#E4EBF7" mask="url(#b)"></path>
</g>
<path d="M39.755 130.84a8.276 8.276 0 1 1-16.468-1.66 8.276 8.276 0 0 1 16.468 1.66" fill="#FFF"></path>
<path d="M36.975 134.297l10.482 5.943M48.373 146.508l-12.648 10.788" stroke="#FFF" stroke-width="2"></path>
<path
d="M39.875 159.352a5.667 5.667 0 1 1-11.277-1.136 5.667 5.667 0 0 1 11.277 1.136M57.588 143.247a5.708 5.708 0 1 1-11.358-1.145 5.708 5.708 0 0 1 11.358 1.145M99.018 26.875l29.82-.014a4.587 4.587 0 1 0-.003-9.175l-29.82.013a4.587 4.587 0 1 0 .003 9.176M110.424 45.211l29.82-.013a4.588 4.588 0 0 0-.004-9.175l-29.82.013a4.587 4.587 0 1 0 .004 9.175"
fill="#FFF"></path>
<path
d="M112.798 26.861v-.002l15.784-.006a4.588 4.588 0 1 0 .003 9.175l-15.783.007v-.002a4.586 4.586 0 0 0-.004-9.172M184.523 135.668c-.553 5.485-5.447 9.483-10.931 8.93-5.485-.553-9.483-5.448-8.93-10.932.552-5.485 5.447-9.483 10.932-8.93 5.485.553 9.483 5.447 8.93 10.932"
fill="#FFF"></path>
<path d="M179.26 141.75l12.64 7.167M193.006 156.477l-15.255 13.011" stroke="#FFF" stroke-width="2"></path>
<path
d="M184.668 170.057a6.835 6.835 0 1 1-13.6-1.372 6.835 6.835 0 0 1 13.6 1.372M203.34 153.325a6.885 6.885 0 1 1-13.7-1.382 6.885 6.885 0 0 1 13.7 1.382"
fill="#FFF"></path>
<path
d="M151.931 192.324a2.222 2.222 0 1 1-4.444 0 2.222 2.222 0 0 1 4.444 0zM225.27 116.056a2.222 2.222 0 1 1-4.445 0 2.222 2.222 0 0 1 4.444 0zM216.38 151.08a2.223 2.223 0 1 1-4.446-.001 2.223 2.223 0 0 1 4.446 0zM176.917 107.636a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM195.291 92.165a2.223 2.223 0 1 1-4.445 0 2.223 2.223 0 0 1 4.445 0zM202.058 180.711a2.223 2.223 0 1 1-4.446 0 2.223 2.223 0 0 1 4.446 0z"
stroke="#FFF" stroke-width="2"></path>
<path stroke="#FFF" stroke-width="2"
d="M214.404 153.302l-1.912 20.184-10.928 5.99M173.661 174.792l-6.356 9.814h-11.36l-4.508 6.484M174.941 125.168v-15.804M220.824 117.25l-12.84 7.901-15.31-7.902V94.39"></path>
<path
d="M166.588 65.936h-3.951a4.756 4.756 0 0 1-4.743-4.742 4.756 4.756 0 0 1 4.743-4.743h3.951a4.756 4.756 0 0 1 4.743 4.743 4.756 4.756 0 0 1-4.743 4.742"
fill="#FFF"></path>
<path
d="M174.823 30.03c0-16.281 13.198-29.48 29.48-29.48 16.28 0 29.48 13.199 29.48 29.48 0 16.28-13.2 29.48-29.48 29.48-16.282 0-29.48-13.2-29.48-29.48"
fill="#1677ff"></path>
<path
d="M205.952 38.387c.5.5.785 1.142.785 1.928s-.286 1.465-.785 1.964c-.572.5-1.214.75-2 .75-.785 0-1.429-.285-1.929-.785-.572-.5-.82-1.143-.82-1.929s.248-1.428.82-1.928c.5-.5 1.144-.75 1.93-.75.785 0 1.462.25 1.999.75m4.285-19.463c1.428 1.249 2.143 2.963 2.143 5.142 0 1.712-.427 3.13-1.219 4.25-.067.096-.137.18-.218.265-.416.429-1.41 1.346-2.956 2.699a5.07 5.07 0 0 0-1.428 1.75 5.207 5.207 0 0 0-.536 2.357v.5h-4.107v-.5c0-1.357.215-2.536.714-3.5.464-.964 1.857-2.464 4.178-4.536l.43-.5c.643-.785.964-1.643.964-2.535 0-1.18-.358-2.108-1-2.785-.678-.68-1.643-1.001-2.858-1.001-1.536 0-2.642.464-3.357 1.43-.37.5-.621 1.135-.76 1.904a1.999 1.999 0 0 1-1.971 1.63h-.004c-1.277 0-2.257-1.183-1.98-2.43.337-1.518 1.02-2.78 2.073-3.784 1.536-1.5 3.607-2.25 6.25-2.25 2.32 0 4.214.607 5.642 1.894"
fill="#FFF"></path>
<path
d="M52.04 76.131s21.81 5.36 27.307 15.945c5.575 10.74-6.352 9.26-15.73 4.935-10.86-5.008-24.7-11.822-11.577-20.88"
fill="#FFB594"></path>
<path
d="M90.483 67.504l-.449 2.893c-.753.49-4.748-2.663-4.748-2.663l-1.645.748-1.346-5.684s6.815-4.589 8.917-5.018c2.452-.501 9.884.94 10.7 2.278 0 0 1.32.486-2.227.69-3.548.203-5.043.447-6.79 3.132-1.747 2.686-2.412 3.624-2.412 3.624"
fill="#FFC6A0"></path>
<path
d="M128.055 111.367c-2.627-7.724-6.15-13.18-8.917-15.478-3.5-2.906-9.34-2.225-11.366-4.187-1.27-1.231-3.215-1.197-3.215-1.197s-14.98-3.158-16.828-3.479c-2.37-.41-2.124-.714-6.054-1.405-1.57-1.907-2.917-1.122-2.917-1.122l-7.11-1.383c-.853-1.472-2.423-1.023-2.423-1.023l-2.468-.897c-1.645 9.976-7.74 13.796-7.74 13.796 1.795 1.122 15.703 8.3 15.703 8.3l5.107 37.11s-3.321 5.694 1.346 9.109c0 0 19.883-3.743 34.921-.329 0 0 3.047-2.546.972-8.806.523-3.01 1.394-8.263 1.736-11.622.385.772 2.019 1.918 3.14 3.477 0 0 9.407-7.365 11.052-14.012-.832-.723-1.598-1.585-2.267-2.453-.567-.736-.358-2.056-.765-2.717-.669-1.084-1.804-1.378-1.907-1.682"
fill="#FFF"></path>
<path
d="M101.09 289.998s4.295 2.041 7.354 1.021c2.821-.94 4.53.668 7.08 1.178 2.55.51 6.874 1.1 11.686-1.26-.103-5.51-6.889-3.98-11.96-6.713-2.563-1.38-3.784-4.722-3.598-8.799h-9.402s-1.392 10.52-1.16 14.573"
fill="#CBD1D1"></path>
<path
d="M101.067 289.826s2.428 1.271 6.759.653c3.058-.437 3.712.481 7.423 1.031 3.712.55 10.724-.069 11.823-.894.413 1.1-.343 2.063-.343 2.063s-1.512.603-4.812.824c-2.03.136-5.8.291-7.607-.503-1.787-1.375-5.247-1.903-5.728-.241-3.918.95-7.355-.286-7.355-.286l-.16-2.647z"
fill="#2B0849"></path>
<path d="M108.341 276.044h3.094s-.103 6.702 4.536 8.558c-4.64.618-8.558-2.303-7.63-8.558"
fill="#A4AABA"></path>
<path
d="M57.542 272.401s-2.107 7.416-4.485 12.306c-1.798 3.695-4.225 7.492 5.465 7.492 6.648 0 8.953-.48 7.423-6.599-1.53-6.12.266-13.199.266-13.199h-8.669z"
fill="#CBD1D1"></path>
<path
d="M51.476 289.793s2.097 1.169 6.633 1.169c6.083 0 8.249-1.65 8.249-1.65s.602 1.114-.619 2.165c-.993.855-3.597 1.591-7.39 1.546-4.145-.048-5.832-.566-6.736-1.168-.825-.55-.687-1.58-.137-2.062"
fill="#2B0849"></path>
<path
d="M58.419 274.304s.033 1.519-.314 2.93c-.349 1.42-1.078 3.104-1.13 4.139-.058 1.151 4.537 1.58 5.155.034.62-1.547 1.294-6.427 1.913-7.252.619-.825-4.903-2.119-5.624.15"
fill="#A4AABA"></path>
<path
d="M99.66 278.514l13.378.092s1.298-54.52 1.853-64.403c.554-9.882 3.776-43.364 1.002-63.128l-12.547-.644-22.849.78s-.434 3.966-1.195 9.976c-.063.496-.682.843-.749 1.365-.075.585.423 1.354.32 1.966-2.364 14.08-6.377 33.104-8.744 46.677-.116.666-1.234 1.009-1.458 2.691-.04.302.211 1.525.112 1.795-6.873 18.744-10.949 47.842-14.277 61.885l14.607-.014s2.197-8.57 4.03-16.97c2.811-12.886 23.111-85.01 23.111-85.01l3.016-.521 1.043 46.35s-.224 1.234.337 2.02c.56.785-.56 1.123-.392 2.244l.392 1.794s-.449 7.178-.898 11.89c-.448 4.71-.092 39.165-.092 39.165"
fill="#7BB2F9"></path>
<path d="M76.085 221.626c1.153.094 4.038-2.019 6.955-4.935M106.36 225.142s2.774-1.11 6.103-3.883"
stroke="#648BD8" stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M107.275 222.1s2.773-1.11 6.102-3.884" stroke="#648BD8" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M74.74 224.767s2.622-.591 6.505-3.365M86.03 151.634c-.27 3.106.3 8.525-4.336 9.123M103.625 149.88s.11 14.012-1.293 15.065c-2.219 1.664-2.99 1.944-2.99 1.944M99.79 150.438s.035 12.88-1.196 24.377M93.673 175.911s7.212-1.664 9.431-1.664M74.31 205.861a212.013 212.013 0 0 1-.979 4.56s-1.458 1.832-1.009 3.776c.449 1.944-.947 2.045-4.985 15.355-1.696 5.59-4.49 18.591-6.348 27.597l-.231 1.12M75.689 197.807a320.934 320.934 0 0 1-.882 4.754M82.591 152.233L81.395 162.7s-1.097.15-.5 2.244c.113 1.346-2.674 15.775-5.18 30.43M56.12 274.418h13.31"
stroke="#648BD8" stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path
d="M116.241 148.22s-17.047-3.104-35.893.2c.158 2.514-.003 4.15-.003 4.15s14.687-2.818 35.67-.312c.252-2.355.226-4.038.226-4.038"
fill="#192064"></path>
<path
d="M106.322 151.165l.003-4.911a.81.81 0 0 0-.778-.815c-2.44-.091-5.066-.108-7.836-.014a.818.818 0 0 0-.789.815l-.003 4.906a.81.81 0 0 0 .831.813c2.385-.06 4.973-.064 7.73.017a.815.815 0 0 0 .842-.81"
fill="#FFF"></path>
<path
d="M105.207 150.233l.002-3.076a.642.642 0 0 0-.619-.646 94.321 94.321 0 0 0-5.866-.01.65.65 0 0 0-.63.647v3.072a.64.64 0 0 0 .654.644 121.12 121.12 0 0 1 5.794.011c.362.01.665-.28.665-.642"
fill="#192064"></path>
<path
d="M100.263 275.415h12.338M101.436 270.53c.006 3.387.042 5.79.111 6.506M101.451 264.548a915.75 915.75 0 0 0-.015 4.337M100.986 174.965l.898 44.642s.673 1.57-.225 2.692c-.897 1.122 2.468.673.898 2.243-1.57 1.57.897 1.122 0 3.365-.596 1.489-.994 21.1-1.096 35.146"
stroke="#648BD8" stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path
d="M46.876 83.427s-.516 6.045 7.223 5.552c11.2-.712 9.218-9.345 31.54-21.655-.786-2.708-2.447-4.744-2.447-4.744s-11.068 3.11-22.584 8.046c-6.766 2.9-13.395 6.352-13.732 12.801M104.46 91.057l.941-5.372-8.884-11.43-5.037 5.372-1.74 7.834a.321.321 0 0 0 .108.32c.965.8 6.5 5.013 14.347 3.544a.332.332 0 0 0 .264-.268"
fill="#FFC6A0"></path>
<path
d="M93.942 79.387s-4.533-2.853-2.432-6.855c1.623-3.09 4.513 1.133 4.513 1.133s.52-3.642 3.121-3.642c.52-1.04 1.561-4.162 1.561-4.162s11.445 2.601 13.526 3.121c0 5.203-2.304 19.424-7.84 19.861-8.892.703-12.449-9.456-12.449-9.456"
fill="#FFC6A0"></path>
<path
d="M113.874 73.446c2.601-2.081 3.47-9.722 3.47-9.722s-2.479-.49-6.64-2.05c-4.683-2.081-12.798-4.747-17.48.976-9.668 3.223-2.05 19.823-2.05 19.823l2.713-3.021s-3.935-3.287-2.08-6.243c2.17-3.462 3.92 1.073 3.92 1.073s.637-2.387 3.581-3.342c.355-.71 1.036-2.674 1.432-3.85a1.073 1.073 0 0 1 1.263-.704c2.4.558 8.677 2.019 11.356 2.662.522.125.871.615.82 1.15l-.305 3.248z"
fill="#520038"></path>
<path
d="M104.977 76.064c-.103.61-.582 1.038-1.07.956-.489-.083-.801-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.644.698 1.254M112.132 77.694c-.103.61-.582 1.038-1.07.956-.488-.083-.8-.644-.698-1.254.103-.61.582-1.038 1.07-.956.488.082.8.643.698 1.254"
fill="#552950"></path>
<path stroke="#DB836E" stroke-width="1.118" stroke-linecap="round" stroke-linejoin="round"
d="M110.13 74.84l-.896 1.61-.298 4.357h-2.228"></path>
<path d="M110.846 74.481s1.79-.716 2.506.537" stroke="#5C2552" stroke-width="1.118" stroke-linecap="round"
stroke-linejoin="round"></path>
<path d="M92.386 74.282s.477-1.114 1.113-.716c.637.398 1.274 1.433.558 1.99-.717.556.159 1.67.159 1.67"
stroke="#DB836E" stroke-width="1.118" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M103.287 72.93s1.83 1.113 4.137.954" stroke="#5C2552" stroke-width="1.118" stroke-linecap="round"
stroke-linejoin="round"></path>
<path
d="M103.685 81.762s2.227 1.193 4.376 1.193M104.64 84.308s.954.398 1.511.318M94.693 81.205s2.308 7.4 10.424 7.639"
stroke="#DB836E" stroke-width="1.118" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M81.45 89.384s.45 5.647-4.935 12.787M69 82.654s-.726 9.282-8.204 14.206" stroke="#E4EBF7"
stroke-width="1.101" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M129.405 122.865s-5.272 7.403-9.422 10.768" stroke="#E4EBF7" stroke-width="1.051"
stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M119.306 107.329s.452 4.366-2.127 32.062" stroke="#E4EBF7" stroke-width="1.101"
stroke-linecap="round" stroke-linejoin="round"></path>
<path
d="M150.028 151.232h-49.837a1.01 1.01 0 0 1-1.01-1.01v-31.688c0-.557.452-1.01 1.01-1.01h49.837c.558 0 1.01.453 1.01 1.01v31.688a1.01 1.01 0 0 1-1.01 1.01"
fill="#F2D7AD"></path>
<path d="M150.29 151.232h-19.863v-33.707h20.784v32.786a.92.92 0 0 1-.92.92" fill="#F4D19D"></path>
<path
d="M123.554 127.896H92.917a.518.518 0 0 1-.425-.816l6.38-9.113c.193-.277.51-.442.85-.442h31.092l-7.26 10.371z"
fill="#F2D7AD"></path>
<path fill="#CC9B6E" d="M123.689 128.447H99.25v-.519h24.169l7.183-10.26.424.298z"></path>
<path
d="M158.298 127.896h-18.669a2.073 2.073 0 0 1-1.659-.83l-7.156-9.541h19.965c.49 0 .95.23 1.244.622l6.69 8.92a.519.519 0 0 1-.415.83"
fill="#F4D19D"></path>
<path fill="#CC9B6E"
d="M157.847 128.479h-19.384l-7.857-10.475.415-.31 7.7 10.266h19.126zM130.554 150.685l-.032-8.177.519-.002.032 8.177z"></path>
<path fill="#CC9B6E"
d="M130.511 139.783l-.08-21.414.519-.002.08 21.414zM111.876 140.932l-.498-.143 1.479-5.167.498.143zM108.437 141.06l-2.679-2.935 2.665-3.434.41.318-2.397 3.089 2.384 2.612zM116.607 141.06l-.383-.35 2.383-2.612-2.397-3.089.41-.318 2.665 3.434z"></path>
<path
d="M154.316 131.892l-3.114-1.96.038 3.514-1.043.092c-1.682.115-3.634.23-4.789.23-1.902 0-2.693 2.258 2.23 2.648l-2.645-.596s-2.168 1.317.504 2.3c0 0-1.58 1.217.561 2.58-.584 3.504 5.247 4.058 7.122 3.59 1.876-.47 4.233-2.359 4.487-5.16.28-3.085-.89-5.432-3.35-7.238"
fill="#FFC6A0"></path>
<path
d="M153.686 133.577s-6.522.47-8.36.372c-1.836-.098-1.904 2.19 2.359 2.264 3.739.15 5.451-.044 5.451-.044"
stroke="#DB836E" stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M145.16 135.877c-1.85 1.346.561 2.355.561 2.355s3.478.898 6.73.617" stroke="#DB836E"
stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path
d="M151.89 141.71s-6.28.111-6.73-2.132c-.223-1.346.45-1.402.45-1.402M146.114 140.868s-1.103 3.16 5.44 3.533M151.202 129.932v3.477M52.838 89.286c3.533-.337 8.423-1.248 13.582-7.754"
stroke="#DB836E" stroke-width="1.051" stroke-linecap="round" stroke-linejoin="round"></path>
<path
d="M168.567 248.318a6.647 6.647 0 0 1-6.647-6.647v-66.466a6.647 6.647 0 1 1 13.294 0v66.466a6.647 6.647 0 0 1-6.647 6.647"
fill="#5BA02E"></path>
<path
d="M176.543 247.653a6.647 6.647 0 0 1-6.646-6.647v-33.232a6.647 6.647 0 1 1 13.293 0v33.232a6.647 6.647 0 0 1-6.647 6.647"
fill="#92C110"></path>
<path
d="M186.443 293.613H158.92a3.187 3.187 0 0 1-3.187-3.187v-46.134a3.187 3.187 0 0 1 3.187-3.187h27.524a3.187 3.187 0 0 1 3.187 3.187v46.134a3.187 3.187 0 0 1-3.187 3.187"
fill="#F2D7AD"></path>
<path d="M88.979 89.48s7.776 5.384 16.6 2.842" stroke="#E4EBF7" stroke-width="1.101" stroke-linecap="round"
stroke-linejoin="round"></path>
</g>
</svg>)
}

View File

@ -9,6 +9,7 @@
}
.panelTitle{
font-size: 14px;
font-weight: bold;
}
.panelExtra{

View File

@ -4,7 +4,7 @@ import ReactDOM from 'react-dom/client';
import {App} from './App'
ReactDOM.createRoot(document.querySelector('#root')!).render(
<React.StrictMode>
// <React.StrictMode>
<App/>
</React.StrictMode>
// </React.StrictMode>
)

View File

@ -3,7 +3,8 @@ import {BrowserRouter, HashRouter, Navigate, Route, Routes, useNavigate} from "r
import {APP_CONFIG} from "../config.ts";
import {Button} from "@douyinfe/semi-ui";
import DefaultPage from "./index";
import {Result} from "../components/Result.tsx";
import {Index} from "../components/Result";
import {DashboardIndex} from "./dashboard";
const routerMode: 'browser' | 'hash' | string = APP_CONFIG.ROUTER_MODE;
@ -15,7 +16,7 @@ const WebRouter: React.FC<{
const NotFound: React.FC = () => {
const navigate = useNavigate();
return <Result
return <Index
status="404"
title="页面不存在或无法找到所请求的资源"
// subTitle="Sorry, the page you visited does not exist."
@ -25,6 +26,7 @@ export const AppRouter = () => (<WebRouter>
<div className="page-body-content">
<Routes>
<Route path="/" element={<DefaultPage/>}/>
<Route path="/dashboard" element={<DashboardIndex/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</div>

View File

@ -0,0 +1,130 @@
import React from "react";
import {Panel} from "../../components/panel";
import {AppList} from "../../components/AppList";
import {AppModel, EventDataModel, EventModel} from "../../../model";
import {appList, appEventList, appEventDataList} from "../../service/api.app.ts";
import './style.scss'
import {Space, Table} from "@douyinfe/semi-ui";
import {formatDate} from "../../../utils/date.ts";
import {useInterval} from "ahooks";
export const DashboardIndex: React.FC = () => {
// 数据
const [apps, setApps] = React.useState<AppModel[]>([]);
const [currentAppID, setCurrentAppID] = React.useState<number>(0);
const [events, setEvents] = React.useState<EventModel[]>([]);
const [eventDataList, setEventDataList] = React.useState<EventDataModel[]>([]);
const [page, setPage] = React.useState<number>(1);
const [dataTotal, setDataTotal] = React.useState<number>(0);
const eventDataColumns = [
{
title: '编号',
dataIndex: 'id',
width: 60
},
{
title: '事件',
dataIndex: 'title',
width: 80
},
{
title: '路径',
dataIndex: 'path',
width: 120
},
{
title: '访问者浏览器',
ellipsis: true,
dataIndex: 'browser'
},
{
title: '来源',
dataIndex: 'ip',
width: 80
},
{
title: '分辨率',
dataIndex: 'resolution',
width: 120
},
{
title: '日期',
dataIndex: 'create_time',
render: (text: string) => formatDate(text),
width: 180
},
]
// 加载应用所有的事件
const getAppEvents = () => {
appEventList(currentAppID).then(list => setEvents(list))
}
// 加载引用所有事件上报的数据
const loadAppEventsAndDataList = (page = 1) => {
appEventDataList({
appId: currentAppID,
pageSize: 10,
page
}).then(list => {
setEventDataList(list)
setPage(page)
})
}
const getAppEventAndData = ()=>{
if (currentAppID > 0) {
getAppEvents()
loadAppEventsAndDataList()
}
}
// 10s 自动刷新
useInterval(loadAppEventsAndDataList, 10000)
React.useEffect(() => {
appList().then(list => setApps(list))
}, [])
React.useEffect(getAppEventAndData, [currentAppID])
return (
<div className="dashboard container">
<div>
<h1>Dashboard</h1>
</div>
<Panel title="我的应用" noPadding>
<AppList
list={apps}
onItemClick={(it) => setCurrentAppID(it.id)}
/>
</Panel>
{currentAppID > 0 && <>
<Panel title="事件列表" noPadding>
<div className="app-list-wrapper">
{events.map(it => (
<div key={it.id} className="list-link-item flex space-between">
<Space className="space">
<span>{it.id}</span>
<span>{it.title}</span>
</Space>
<span></span>
</div>
))}
</div>
</Panel>
<Panel title="事件数据">
<div>
<Table columns={eventDataColumns} dataSource={eventDataList} pagination={{
currentPage: page,
pageSize: 10,
total: dataTotal,
onPageChange: loadAppEventsAndDataList,
hideOnSinglePage: true
}}/>
</div>
</Panel>
</>}
</div>
);
};

View File

@ -0,0 +1,9 @@
.app-list-wrapper{
.list-link-item{
padding:10px;
border-bottom: solid 1px #eee;
&:last-child{
border-bottom: none;
}
}
}

View File

@ -1,4 +1,4 @@
import React, {useRef, useState} from "react";
import React, {useEffect, useRef, useState} from "react";
import {IconGithubLogo, IconWeibo} from "@douyinfe/semi-icons";
import css from './index.module.scss'
import {LoginComponent} from "../../components/LoginComponent.tsx";
@ -11,13 +11,12 @@ const DefaultPage: React.FC = () => {
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const {login} = useUserinfoStore()
const {login, userinfo} = useUserinfoStore()
const onFinish = async (values: any) => {
setLoading(true);
try {
const user = await login(values)
setVisible(true);
navigate('/dashboard')
} catch (err) {
// 登录失败
@ -30,8 +29,12 @@ const DefaultPage: React.FC = () => {
setLoading(false);
};
const [visible, setVisible] = useState(false);
const hideModal = () => setVisible(false)
useEffect(() => {
if (userinfo && userinfo.id > 0) {
navigate('/dashboard')
}
}, [userinfo])
return (<div className={css.index}>
{/*<LoginComponent/>*/}

22
front/service/api.app.ts Normal file
View File

@ -0,0 +1,22 @@
import {get, post} from "./request.ts";
import {AppModel, EventDataModel, EventModel, UserModel} from "../../model";
// 获取用户归属应用列表
export function appList() {
return get<AppModel[]>('/api/app/list')
}
// 根据应用id获取应用所有的事件列表
export function appEventList(appId: number) {
return get<EventModel[]>('/api/app/event', {appId})
}
// 根据应用id获取应用所有的事件数据列表
export function appEventDataList(params: {
appId: number;
eventId?: number;
page?: number;
pageSize?: number;
}) {
return get<EventDataModel[]>('/api/app/event-data', params)
}

View File

@ -59,8 +59,22 @@ Axios.interceptors.response.use(res => {
return Promise.reject(err)
})
// 将data对象转化为url参数
function dataToQueryString(data: any) {
if (!data) return '';
return Object.keys(data).map(key => {
return encodeURIComponent(key) + '=' + encodeURIComponent(data[key])
}).join('&')
}
export function request<T>(url: string, method: RequestMethod, data: any = null, getOriginResult = false) {
return new Promise<T>((resolve, reject) => {
if (method == 'get' && data) {
url += `?${dataToQueryString(data)}`
data = null
}
Axios.request<APIResponse<T>>({
url,
method,
@ -103,10 +117,10 @@ export function uploadFile<T>(url: string, file: File, data: any = {}, returnOri
return request<T>(url, 'post', formData, returnOrigin)
}
export function post<T>(url: string, data: any = {}) {
export function post<T>(url: string, data: any = null) {
return request<T>(url, 'post', data)
}
export function get<T>(url: string, data: any = {}) {
export function get<T>(url: string, data: any = null) {
return request<T>(url, 'get', data)
}

View File

@ -33,7 +33,7 @@ export const useUserinfoStore = create<{
/**
*
*/
init: () => Promise<void>;
init: () => void;
}>((set, _, _state) => {
return {
userinfo: {
@ -43,10 +43,9 @@ export const useUserinfoStore = create<{
init: () => {
const state = _state.getState()
if (state.token) {
return Promise.resolve()
return;
}
const token = Storage.get<string>(LOGIN_TOKEN_KEY);
return new Promise<void>((resolve) => {
if (token) {
getInfo().then((info) => {
set({
@ -55,8 +54,17 @@ export const useUserinfoStore = create<{
})
})
}
resolve();
});
// return new Promise<void>((resolve) => {
// if (token) {
// getInfo().then((info) => {
// set({
// userinfo: info,
// token
// })
// })
// }
// resolve();
// });
},
logout: () => {
return new Promise<void>((resolve) => {

View File

@ -17,6 +17,8 @@ export type EventDataModel = {
uid: number;
uuid: number;
type: 'pv' | 'uv' | string;
title:string;
description:string;
location: string;
resolution: string;
browser: string;

View File

@ -17,6 +17,7 @@
"@douyinfe/semi-ui": "^2.41.3",
"@emotion/css": "^11.11.2",
"@types/express": "^4.17.17",
"@types/md5": "^2.3.2",
"@types/mocha": "^10.0.1",
"@types/mysql": "^2.15.21",
"@types/node": "^20.4.9",
@ -24,6 +25,7 @@
"@types/react-dom": "^18.2.7",
"@types/supertest": "^2.0.12",
"@vitejs/plugin-react": "^4.0.4",
"ahooks": "^3.7.8",
"axios": "^1.4.0",
"dayjs": "^1.11.9",
"mocha": "^10.2.0",
@ -39,7 +41,9 @@
},
"dependencies": {
"express": "^4.18.2",
"md5": "^2.3.0",
"mysql": "^2.18.1",
"redis": "^4.6.7",
"ts-node": "^10.9.1"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,4 +1,4 @@
import { InitServerOption } from "./types";
import {InitServerOption} from "./types";
// import { createServer as createServerOrigin } from "http";
// import express = require("express");
import * as express from "express";
@ -8,9 +8,23 @@ export function createServer(options: Partial<InitServerOption>, callback?: () =
const app = express();
// 将请求体转换为JSON格式
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(express.urlencoded({extended: true}))
// 监听端口
app.listen(options.port, callback);
// 添加允许跨域中间件
app.use(function (req, res, next) {
const method = req.method.toLowerCase();
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
// res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
if (method === 'options') {
res.status(200).end('OK');
return;
}
next();
});
app.get('/ping', (_req, res) => {
res.appendHeader('app-ping', 'pong')
res.send('pong')

View File

@ -1,4 +1,7 @@
import { Response, Request } from 'express'
import {Response, Request} from 'express'
import {IncomingHttpHeaders} from "http";
import {UserModel} from "../../model";
export type InitServerOption = {
port: number;
host: string;
@ -11,7 +14,8 @@ export type RouteHandleFunctionParam = {
query: Record<string, any>;
body: Record<string, any>;
method: HttpMethod;
headers: Record<string, string>;
user?: UserModel | null;
headers: IncomingHttpHeaders;
res: Response<any, Record<string, any>>
req: Request
}

View File

@ -2,21 +2,42 @@ import {Application, Request, Response} from "express";
import {RouteHandleFunction, RouteHandleFunctionParam} from "../core/types";
import {home} from "./home";
import {appList, reportToServer, appEvent, eventData} from "./reportor";
import {getUserInfo, loginHandler} from "./user.ts";
import {decodeUserToken, getUserInfo, loginHandler} from "./user.ts";
const excludes = [
'/home',
'/api/report',
]
//
function createRoute(handler: RouteHandleFunction) {
return (req: Request, res: Response<any, Record<string, any>>) => {
// console.log('params', req.params, req.query, req.body)
handler({
// console.log('params', req.headers)
const params = {
path: req.path,
param: req.params,
query: req.query,
body: req.body,
method: req.method,
headers: {},
headers: req.headers,
res,
req
};
const path = req.path;
console.log('request path:', path)
if (excludes.includes(path)) {
return handler(params);
}
const token = req.headers.authorization
if (!token) {
res.send({code: 403, message: '请先登录'})
return;
}
decodeUserToken(token).then(user => {
handler({
...params,
user: typeof (user) == "string" ? JSON.parse(user) : user
})
})
}
}

View File

@ -1,37 +1,46 @@
import { RouteHandleFunction } from "../core/types";
import { listAppByUID } from "../service/app";
import { reportEvent } from "../service/report-service";
import {RouteHandleFunction} from "../core/types";
import {listAppByUID, listAppEvent, listAppEventData} from "../service/app";
import {reportEvent} from "../service/report-service";
export const reportToServer: RouteHandleFunction = ({
param, res
}) => {
reportEvent(param).then(() => {
export const reportToServer: RouteHandleFunction =
({
body, res
}) => {
reportEvent(body).then(() => {
res.send('got and saved!')
}).catch((e: Error) => {
console.log(e)
res.send('got but not saved!')
});
}
}
export const appList: RouteHandleFunction = async ({
export const appList: RouteHandleFunction =
async ({
param, res
}) => {
}) => {
const apps = await listAppByUID(1);
res.send({ code: 0, data: apps })
}
res.send({code: 0, data: apps})
}
export const appEvent: RouteHandleFunction = async ({
export const appEvent: RouteHandleFunction =
async ({
query, res, param, body
}) => {
}) => {
const events = await listAppEvent(query.appId)
res.send({
query, param, body
code: 0,
data: events
})
}
}
export const eventData: RouteHandleFunction = ({
param, res
}) => {
res.send(JSON.stringify(param))
}
export const eventData: RouteHandleFunction =
async ({
query, res
}) => {
const data = await listAppEventData(Number(query.appId), Number(query.page), Number(query.pageSize))
res.send({
code: 0,
data
})
}

View File

@ -1,17 +1,22 @@
import {RouteHandleFunction} from "../core/types.ts";
import {login} from "../service/app.ts";
import {UserModel} from "../../model";
import {getFromRedis, setToRedis} from "../service/redis.ts";
export function encodeUserToken(user: UserModel) {
if (user == null) throw new Error('user is null')
const token = JSON.stringify(user)
return btoa(encodeURIComponent(token));
// const token = JSON.stringify(user)
const token = btoa(user.id + ':' + Date.now())
setToRedis('app-report:user:' + token, JSON.stringify(user)).then(() => console.log('setToRedis success'));
return token;
}
export function decodeUserToken(token: string) {
// 将token转回UserModel对象数据
const user = decodeURIComponent(atob(token));
return JSON.parse(user) as UserModel
// const user = decodeURIComponent(atob(token));
console.log('decodeUserToken token==>app-report:user:', token)
return getFromRedis<UserModel>('app-report:user:' + token)
// return JSON.parse(user) as UserModel
}
@ -38,8 +43,14 @@ export const loginHandler: RouteHandleFunction
}
export const getUserInfo: RouteHandleFunction =
({headers, res}) => {
const token = headers.Authorization
const user = decodeUserToken(token)
res.send({code: 0, message: '登录成功', data: user})
async ({headers,user, res}) => {
const token = headers.authorization
if (!token) {
res.send({code: 403, message: '请先登录'})
return;
}
if (!user) {
res.send({code: 403, message: '请先登录'})
}
res.send({code: 0, message: 'success', data: user})
}

View File

@ -17,7 +17,7 @@ export function listAppEvent(id: number) {
// 查询应用所有的事件数据
export function listAppEventData(id: number, page = 1, pageSize = 10) {
return selectArray<EventModel>('select * from events_data where app_id=? limit ?,?',
return selectArray<EventModel>('select d.*,e.title,e.type,e.description from events_data d,events e where d.event_id = e.id and d.app_id=? limit ?,?',
[id, (page - 1) * pageSize, pageSize])
}

View File

@ -42,7 +42,7 @@ export async function selectOne<T>(sql: string, params: any = null) {
// 统计数据
export async function queryCount(sql: string, params: any = null) {
const obj = await selectOne<{ [key: string]: number }>(sql, params);
if(!obj) return 0;
if (!obj) return 0;
const keys = Object.keys(obj);
return obj[keys[0]];
}
@ -68,13 +68,14 @@ export async function isExist(sql: string, params: any) {
function executeSQL<T>(sql: string, params: any) {
return new Promise<T>((resolve, reject) => {
pool.query(sql, params, (err, ret) => {
const q = pool.query(sql, params, (err, ret) => {
if (err) {
reject(err)
} else {
resolve(ret)
}
})
console.log('[SQL]: ' + q.sql,params)
})
}

32
service/service/redis.ts Normal file
View File

@ -0,0 +1,32 @@
import {createClient} from 'redis';
const client = createClient();
client.on('error', err => console.log('Redis Client', err));
client.connect().then(() => {
console.log('connected to redis success')
})
export async function setToRedis(key: string, value: any, expire?: number) {
if (!value) throw new Error('value is required');
await client.set(key, JSON.stringify(value))
if (expire) await client.expire(key, expire);
return;
}
// export async function getString(key: string) {
// const data = await client.get(key);
// if (!data) return null;
// return data;
// }
export async function getFromRedis<T>(key: string) {
const data = await client.get(key);
if (!data) return null;
console.log('getFromRedis=>',typeof(data),data)
return JSON.parse(data) as T;
}
// 导出客户端)
export default client;

View File

@ -1,19 +1,16 @@
import { PvUvModel } from "../../model";
import { isExist, insertAndGetInsertId } from './mysql'
const table = {
pv_uv: 'pv_uv'
}
export async function reportEvent(data: Partial<PvUvModel>) {
//pv:用户每次打开一个页面便记录1次PV多次打开同一页面则浏览量累计。
//uv:1天内同一访客的多次访问只记录为一个访客。通过IP和cookie是判断UV值的两种方式。
const { type } = data;
if (type == 'uv') {
// 判断今日的数据是否已经存在
const existsToday = await isExist('select count(*) _ from pv_uv where DATE(created_at) = CURDATE() and uuid=?', [data.uuid])
const existsToday = await isExist('select count(*) _ from events_data where DATE(created_at) = CURDATE() and uuid=?', [data.uuid])
if (existsToday) {
return;
}
}
await insertAndGetInsertId('pv_uv', data)
await insertAndGetInsertId('events_data', data)
}

140
yarn.lock
View File

@ -564,6 +564,40 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@redis/bloom@1.2.0":
version "1.2.0"
resolved "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71"
integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==
"@redis/client@1.5.8":
version "1.5.8"
resolved "https://registry.npmmirror.com/@redis/client/-/client-1.5.8.tgz#a375ba7861825bd0d2dc512282b8bff7b98dbcb1"
integrity sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==
dependencies:
cluster-key-slot "1.1.2"
generic-pool "3.9.0"
yallist "4.0.0"
"@redis/graph@1.1.0":
version "1.1.0"
resolved "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz#cc2b82e5141a29ada2cce7d267a6b74baa6dd519"
integrity sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==
"@redis/json@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1"
integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==
"@redis/search@1.1.3":
version "1.1.3"
resolved "https://registry.npmmirror.com/@redis/search/-/search-1.1.3.tgz#b5a6837522ce9028267fe6f50762a8bcfd2e998b"
integrity sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==
"@redis/time-series@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz#af85eb080f6934580e4d3b58046026b6c2b18717"
integrity sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==
"@remix-run/router@1.8.0":
version "1.8.0"
resolved "https://registry.npmmirror.com/@remix-run/router/-/router-1.8.0.tgz#e848d2f669f601544df15ce2a313955e4bf0bafc"
@ -634,6 +668,16 @@
resolved "https://registry.npmmirror.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65"
integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==
"@types/js-cookie@^2.x.x":
version "2.2.7"
resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
"@types/md5@^2.3.2":
version "2.3.2"
resolved "https://registry.npmmirror.com/@types/md5/-/md5-2.3.2.tgz#529bb3f8a7e9e9f621094eb76a443f585d882528"
integrity sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==
"@types/mime@*":
version "3.0.1"
resolved "https://registry.npmmirror.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
@ -767,6 +811,27 @@ acorn@^8.4.1:
resolved "https://registry.npmmirror.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
ahooks-v3-count@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz#ddeb392e009ad6e748905b3cbf63a9fd8262ca80"
integrity sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==
ahooks@^3.7.8:
version "3.7.8"
resolved "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.8.tgz#3fa3c491cd153e884a32b0c4192fc72cf84c4332"
integrity sha512-e/NMlQWoCjaUtncNFIZk3FG1ImSkV/JhScQSkTqnftakRwdfZWSw6zzoWSG9OMYqPNs2MguDYBUFFC6THelWXA==
dependencies:
"@babel/runtime" "^7.21.0"
"@types/js-cookie" "^2.x.x"
ahooks-v3-count "^1.0.0"
dayjs "^1.9.1"
intersection-observer "^0.12.0"
js-cookie "^2.x.x"
lodash "^4.17.21"
resize-observer-polyfill "^1.5.1"
screenfull "^5.0.0"
tslib "^2.4.1"
ansi-colors@4.1.1:
version "4.1.1"
resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
@ -967,6 +1032,11 @@ chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
charenc@0.0.2:
version "0.0.2"
resolved "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==
chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.2:
version "3.5.3"
resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
@ -1001,6 +1071,11 @@ clsx@^1.1.1:
resolved "https://registry.npmmirror.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
cluster-key-slot@1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -1105,6 +1180,11 @@ create-require@^1.1.0:
resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
crypt@0.0.2:
version "0.0.2"
resolved "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==
csstype@^3.0.2:
version "3.1.2"
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
@ -1122,7 +1202,7 @@ date-fns@^2.29.3:
dependencies:
"@babel/runtime" "^7.21.0"
dayjs@^1.11.9:
dayjs@^1.11.9, dayjs@^1.9.1:
version "1.11.9"
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
@ -1395,6 +1475,11 @@ function-bind@^1.1.1:
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
generic-pool@3.9.0:
version "3.9.0"
resolved "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4"
integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@ -1537,6 +1622,11 @@ inherits@2, inherits@2.0.4, inherits@~2.0.3:
resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
intersection-observer@^0.12.0:
version "0.12.2"
resolved "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375"
integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@ -1554,6 +1644,11 @@ is-binary-path@~2.1.0:
dependencies:
binary-extensions "^2.0.0"
is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-core-module@^2.13.0:
version "2.13.0"
resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
@ -1598,6 +1693,11 @@ isarray@~1.0.0:
resolved "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
js-cookie@^2.x.x:
version "2.2.1"
resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -1676,6 +1776,15 @@ make-error@^1.1.1:
resolved "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
md5@^2.3.0:
version "2.3.0"
resolved "https://registry.npmmirror.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
charenc "0.0.2"
crypt "0.0.2"
is-buffer "~1.1.6"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -2088,6 +2197,18 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
redis@^4.6.7:
version "4.6.7"
resolved "https://registry.npmmirror.com/redis/-/redis-4.6.7.tgz#c73123ad0b572776223f172ec78185adb72a6b57"
integrity sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==
dependencies:
"@redis/bloom" "1.2.0"
"@redis/client" "1.5.8"
"@redis/graph" "1.1.0"
"@redis/json" "1.0.4"
"@redis/search" "1.1.3"
"@redis/time-series" "1.0.4"
regenerator-runtime@^0.14.0:
version "0.14.0"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
@ -2155,6 +2276,11 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"
screenfull@^5.0.0:
version "5.2.0"
resolved "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
scroll-into-view-if-needed@^2.2.24:
version "2.2.31"
resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
@ -2377,7 +2503,7 @@ ts-node@^10.9.1:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tslib@^2.0.0:
tslib@^2.0.0, tslib@^2.4.1:
version "2.6.2"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
@ -2478,16 +2604,16 @@ y18n@^5.0.5:
resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yallist@4.0.0, yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.0:
version "1.10.2"
resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"