├── public
├── reset.css
├── favicon.ico
├── manifest.json
└── index.html
├── src
├── Page
│ ├── Login
│ │ ├── Login.scss
│ │ └── Login.tsx
│ ├── Reservation
│ │ └── Reservation.tsx
│ ├── PageType.tsx
│ ├── User
│ │ ├── User.scss
│ │ └── User.tsx
│ ├── Home
│ │ ├── Home.scss
│ │ └── Home.tsx
│ ├── Shop
│ │ ├── Shop.scss
│ │ └── Shop.tsx
│ └── Page.tsx
├── Components
│ ├── UniversalComponents
│ │ ├── FormValidate
│ │ │ ├── FormValidate.scss
│ │ │ ├── FromValidateType.ts
│ │ │ └── FormValidate.tsx
│ │ ├── Map
│ │ │ └── Map.tsx
│ │ ├── Notify
│ │ │ ├── Notify.tsx
│ │ │ └── Notify.scss
│ │ ├── Calendar
│ │ │ ├── Calendar.scss
│ │ │ └── Calendar.tsx
│ │ ├── ListView
│ │ │ ├── ListViewType.tsx
│ │ │ ├── ListView.scss
│ │ │ └── ListView.tsx
│ │ └── SharePoster
│ │ │ └── CreateQrcode.tsx
│ └── AppointmentDate
│ │ ├── AppointmentDate.scss
│ │ ├── AppointmentDateBody
│ │ ├── AppointmentDateBodyType.tsx
│ │ ├── AppointmentDateBody.scss
│ │ └── AppointmentDateBody.tsx
│ │ ├── AppointmentDate.tsx
│ │ └── AppointmentDateHeader
│ │ ├── AppointmentDateHeader.scss
│ │ └── AppointmentDateHeader.tsx
├── Static
│ ├── Images
│ │ ├── christmas.jpg
│ │ ├── AppBar
│ │ │ ├── heiyuyue_9_12.9@2x.png
│ │ │ ├── heigshouye_9_12.9@2x.png
│ │ │ ├── heihuiyuan_9_12.9@2x.png
│ │ │ ├── heishangpin_9_12.9@2x.png
│ │ │ ├── honghuiyuan_9_12.9@2x.png
│ │ │ ├── hongshouye_9_12.9@2x.png
│ │ │ ├── hongyuyue_9_12.9@2x.png
│ │ │ └── hongishangpin_9_12.9@2x.png
│ │ └── Home
│ │ │ ├── shouyejinsedingwe_9_12.9@2x.png
│ │ │ └── shouyejinsedianhuahao_9_12.9@2x.png
│ └── Css
│ │ ├── Base.scss
│ │ └── Reset.css
├── index.scss
├── Utils
│ ├── Base
│ │ ├── TimesType.ts
│ │ ├── BaseTypes.ts
│ │ ├── IosQuestion.ts
│ │ ├── Times.ts
│ │ └── Base.ts
│ ├── HttpList
│ │ ├── HomeHttp
│ │ │ ├── HomeHttpType.ts
│ │ │ └── HomeHttp.ts
│ │ └── PublicHttp
│ │ │ └── PublicHttp.ts
│ ├── Axios
│ │ ├── AxiosConfig.ts
│ │ └── Axios.ts
│ ├── Wx
│ │ ├── WxPay.ts
│ │ └── WxShare.ts
│ ├── UserAgent
│ │ └── UserAgent.ts
│ └── MapCallback
│ │ └── MapCallback.ts
├── Redux
│ ├── Types
│ │ └── Types.ts
│ ├── Reducer
│ │ └── Reducer.ts
│ ├── State
│ │ ├── StateType.ts
│ │ └── State.ts
│ ├── Store
│ │ └── Store.ts
│ └── Actions
│ │ ├── Actions.ts
│ │ └── HandleAction.ts
├── App.test.tsx
├── Hooks
│ └── IsIphoneX.ts
├── App.scss
├── proxy.js
├── index.tsx
├── Router
│ ├── Router.scss
│ └── Router.tsx
├── logo.svg
├── App.tsx
└── registerServiceWorker.ts
├── .gitattributes
├── tsconfig.prod.json
├── tsconfig.test.json
├── images.d.ts
├── config
├── jest
│ ├── typescriptTransform.js
│ ├── fileTransform.js
│ └── cssTransform.js
├── polyfills.js
├── paths.js
├── env.js
├── webpackDevServer.config.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── declaration.d.ts
├── .gitignore
├── scripts
├── test.js
├── start.js
└── build.js
├── tslint.json
├── tsconfig.json
├── README.md
└── package.json
/public/reset.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Page/Login/Login.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.tsx linguist-language=TypeScript
--------------------------------------------------------------------------------
/tsconfig.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json"
3 | }
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/FormValidate/FormValidate.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/Static/Images/christmas.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/christmas.jpg
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs"
5 | }
6 | }
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | padding-bottom: env(safe-area-inset-bottom);
6 | }
7 |
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/heiyuyue_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/heiyuyue_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/heigshouye_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/heigshouye_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/heihuiyuan_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/heihuiyuan_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/heishangpin_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/heishangpin_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/honghuiyuan_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/honghuiyuan_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/hongshouye_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/hongshouye_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/hongyuyue_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/hongyuyue_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/AppBar/hongishangpin_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/AppBar/hongishangpin_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/Home/shouyejinsedingwe_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/Home/shouyejinsedingwe_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Static/Images/Home/shouyejinsedianhuahao_9_12.9@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhanglijie5997/react-mobile/HEAD/src/Static/Images/Home/shouyejinsedianhuahao_9_12.9@2x.png
--------------------------------------------------------------------------------
/src/Components/AppointmentDate/AppointmentDate.scss:
--------------------------------------------------------------------------------
1 | .appointmentDate {
2 | width: 690px;
3 | margin: 20px auto 0;
4 | border-radius: 20px;
5 | background: #ffffff;
6 | }
--------------------------------------------------------------------------------
/src/Utils/Base/TimesType.ts:
--------------------------------------------------------------------------------
1 | export interface DateFormatType {
2 | year: number,
3 | month: number,
4 | day: number,
5 | hour: number,
6 | milliseconds: number,
7 | }
--------------------------------------------------------------------------------
/images.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg'
2 | declare module '*.png'
3 | declare module '*.jpg'
4 | declare module '*.jpeg'
5 | declare module '*.gif'
6 | declare module '*.bmp'
7 | declare module '*.tiff'
8 |
--------------------------------------------------------------------------------
/src/Redux/Types/Types.ts:
--------------------------------------------------------------------------------
1 | // 枚举所有redux 方法名
2 | export enum ActionsEnum {
3 | UserStatusAction = 'UserStatusAction',
4 | userLocalAction = 'userLocalAction',
5 | iphoneXAction = 'iphoneXAction'
6 | }
--------------------------------------------------------------------------------
/config/jest/typescriptTransform.js:
--------------------------------------------------------------------------------
1 | // Copyright 2004-present Facebook. All Rights Reserved.
2 |
3 | 'use strict';
4 |
5 | const tsJestPreprocessor = require('ts-jest/preprocessor');
6 |
7 | module.exports = tsJestPreprocessor;
8 |
--------------------------------------------------------------------------------
/src/Components/AppointmentDate/AppointmentDateBody/AppointmentDateBodyType.tsx:
--------------------------------------------------------------------------------
1 | // 月份数组格式
2 | export interface MonthHaveDay{
3 | year: number,
4 | month: number,
5 | day: number,
6 | select?: boolean
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/src/Utils/HttpList/HomeHttp/HomeHttpType.ts:
--------------------------------------------------------------------------------
1 | interface GetMusicUrltypeDatatype {
2 | id: number
3 | }
4 |
5 | // 数据类型接口
6 | export interface GetMusicUrltype {
7 | code: number,
8 | data: GetMusicUrltypeDatatype[]
9 | };
10 |
--------------------------------------------------------------------------------
/src/Utils/Base/BaseTypes.ts:
--------------------------------------------------------------------------------
1 | // 时间格式化格式
2 | export interface DateFormatType {
3 | year: number,
4 | month: number,
5 | nowDay: number,
6 | hours: number,
7 | minutes: number,
8 | seconds: number,
9 | milliseconds: number
10 | }
--------------------------------------------------------------------------------
/src/Utils/Base/IosQuestion.ts:
--------------------------------------------------------------------------------
1 |
2 | /** 解决 Ios 光标错位问题 */
3 | export const onFocusFn = () => {
4 | document.body.style.position = "fixed";
5 | }
6 | /** 解决 Ios 光标错位问题 */
7 | export const onBlurFn = () => {
8 | document.body.style.position = "static";
9 | }
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/Map/Map.tsx:
--------------------------------------------------------------------------------
1 | import React , { useEffect }from 'react';
2 |
3 | /** 地图组件 */
4 | const Map = () => {
5 |
6 | return (
7 |
8 | {/* */}
9 |
10 | )
11 | }
12 |
13 | export default Map;
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/Static/Css/Base.scss:
--------------------------------------------------------------------------------
1 | /* 两端对齐 */
2 | :global(.spaceBetween) {
3 | display: flex;
4 | justify-content: space-between;
5 | }
6 | /* 文字显示2行 */
7 | :global(.column2Text){
8 | display: -webkit-box;
9 | overflow: hidden;
10 | line-clamp: 2;
11 | text-overflow: ellipsis;
12 | -webkit-box-orient: vertical;
13 | }
14 |
--------------------------------------------------------------------------------
/declaration.d.ts:
--------------------------------------------------------------------------------
1 | // scss 模块化
2 | declare module "*.scss"{
3 | const res: any;
4 | export default res;
5 | }
6 |
7 | // 全局使用微信
8 | declare const wx: any;
9 |
10 | // 微信支付
11 | declare const WeixinJSBridge: any;
12 |
13 | // 全局组件使用
14 | declare const AMap: any;
15 |
16 | declare interface Window {
17 | onLoad: () => void
18 | }
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Utils/HttpList/HomeHttp/HomeHttp.ts:
--------------------------------------------------------------------------------
1 | import axiosInit from "../../Axios/Axios";
2 | import { GetMusicUrltype } from "./HomeHttpType";
3 |
4 |
5 | /** 请求示例
6 | * @param id
7 | */
8 | export async function getMusicUrl(id: string): Promise {
9 | const data: T = await axiosInit( "/posts", { a: 1});
10 | return data;
11 | }
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/Utils/Axios/AxiosConfig.ts:
--------------------------------------------------------------------------------
1 |
2 | // 当前环境判断
3 | const nowEnv = process.env.NODE_ENV as string;
4 |
5 | const envMap: Map = new Map([
6 | ["development", "http://localhost:8091"],
7 | ["production", "http://localhost:5000"],
8 | ["testProduction", "testProduction" ]
9 | ])
10 |
11 | // axios 请求url
12 | export const baseUrl = envMap.get(nowEnv);
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/en/webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/src/Redux/Reducer/Reducer.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 | import { userStatusReducer, userLocaltionReducer, isIphoneXReducer } from "../Actions/HandleAction";
3 |
4 | export default {
5 | // 所有新增加的reducer都需要在这里注入
6 | combineReducers: combineReducers({
7 | userStatusReducer,
8 | userLocaltionReducer,
9 | isIphoneXReducer
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/Notify/Notify.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styles from "./Notify.scss";
3 | const Notify = (props: {top: number}) => {
4 | return (
5 |
9 | )
10 | }
11 |
12 | export default Notify
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /node
6 | /build
7 | # testing
8 | /coverage
9 |
10 | # production
11 | /build
12 |
13 | # misc
14 | .idea
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/FormValidate/FromValidateType.ts:
--------------------------------------------------------------------------------
1 | export interface DataType {
2 | name: string,
3 | value: string ,
4 | type: string,
5 | placeholder: string
6 | }
7 |
8 | export interface PropsType {
9 | validateMap: Map boolean>,
10 | toastMap: Map void>,
11 | data: DataType[],
12 | changeFn: (index: number, value: string) => void
13 | }
--------------------------------------------------------------------------------
/src/Hooks/IsIphoneX.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 | import { isIphoneX } from '@/Utils/Base/Base';
3 |
4 | /** 是否iphonex hooks
5 | * @returns true 是 false 否
6 | */
7 | export const IsIphoneXHook = () => {
8 | const [getIsIphoneX, setIsIphoneX] = useState(false);
9 | useEffect(() => {
10 | const iphoneX = isIphoneX();
11 | setIsIphoneX(iphoneX);
12 | }, []);
13 |
14 | return getIsIphoneX;
15 | }
--------------------------------------------------------------------------------
/src/Page/Login/Login.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useCallback, Fragment } from 'react'
2 | import { RouteComponentProps } from 'react-router'
3 | import { onFocusFn, onBlurFn } from 'src/Utils/Base/IosQuestion';
4 |
5 | const Login = (props: RouteComponentProps) => {
6 |
7 | return (
8 | <>
9 | 登录
10 |
11 | >
12 | )
13 | }
14 | export default Login;
15 |
--------------------------------------------------------------------------------
/src/App.scss:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .appBar {
6 |
7 | }
8 |
9 | body {
10 | min-height: 100vh;
11 | }
12 | .header {
13 | background-color: #222;
14 | height: 150px;
15 | padding: 100px;
16 | color: white;
17 | }
18 |
19 | .App-title {
20 | font-size: 1.5em;
21 | }
22 |
23 | .App-intro {
24 | font-size: large;
25 | }
26 |
27 | @keyframes App-logo-spin {
28 | from { transform: rotate(0deg); }
29 | to { transform: rotate(360deg); }
30 | }
31 |
--------------------------------------------------------------------------------
/src/proxy.js:
--------------------------------------------------------------------------------
1 | const proxy = require("http-proxy-middleware");
2 | // console.log(1);
3 | module.exports = function (app) {
4 | app.use(
5 | proxy("/api", {
6 | changeOrigin: true,
7 | target: "http://192.168.1.106:3000/",
8 |
9 | })
10 | );
11 | // app.use(
12 | // proxy("/fans/**", {
13 | // target: "https://easy-mock.com/mock/5c0f31837214cf627b8d43f0/",
14 | // changeOrigin: true
15 | // })
16 | // );
17 | };
18 |
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/Calendar/Calendar.scss:
--------------------------------------------------------------------------------
1 | .calenderUl {
2 | display: flex;
3 | flex-wrap: wrap;
4 | justify-content: flex-start;
5 | width: 350px;
6 | li {
7 | width: 50px;
8 | height: 50px;
9 | border-radius: 50%;
10 | background: #e7e7e7;
11 | color: black;
12 | font-size: 24px;
13 | text-align: center;
14 | line-height: 50px;
15 | }
16 | .select {
17 | color: red;
18 | background: pink;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/ListView/ListViewType.tsx:
--------------------------------------------------------------------------------
1 | import { RefObject } from 'react';
2 |
3 | export interface ListViewType {
4 | offset: number, // 距离底部多少开始加载
5 | loadingText: string , // 加载提示文字
6 | finishText: string | JSX.Element, // 完成提示文字
7 | loading: boolean, // 加载状态
8 | finish: boolean, // 加载完成状态
9 | children: JSX.Element, // 组件,可以是任意组件
10 | onload: () => Promise
11 | }
12 |
13 |
14 | export interface ListViewStateType {
15 | getAnimation: number, // requestAnimationFrame实例
16 | }
--------------------------------------------------------------------------------
/src/Redux/State/StateType.ts:
--------------------------------------------------------------------------------
1 | /** 地图类型 */
2 | export interface LocationType {
3 | addressComponent: {
4 | adcode: string, // 城市编码
5 | city: string, // 城市
6 | district: string,// 区
7 | neighborhood: string, // 区的具体位置
8 | province: string,// 省份
9 | street: string, // 街道
10 | township: string, // 街道名称
11 | streetNumber: string, // 门牌号
12 | },
13 | position: {
14 | lat: number, // 纬度
15 | lng: number, // 经度
16 | }
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Page/Reservation/Reservation.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { RouteComponentProps } from 'react-router';
3 | import Calendar from "@Components/UniversalComponents/Calendar/Calendar";
4 | import Notify from "@Components/UniversalComponents/Notify/Notify";
5 | const Reservation = (props: RouteComponentProps) => {
6 | return (
7 |
8 |
9 |
10 |
11 | )
12 | }
13 | export default Reservation;
14 |
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/Notify/Notify.scss:
--------------------------------------------------------------------------------
1 | .notify {
2 | position: fixed;
3 | width: 50vw;
4 | left: 25vw;
5 | top: -108px;
6 | height: 104px;
7 | border-radius: 20px;
8 | border: 1px solid red;
9 | animation: topTo 2s linear;
10 | .inform {
11 | font-size: 20px;
12 | text-indent: 20px;
13 | }
14 | .msg {
15 | text-indent: 20px;
16 | padding: 20px 0 0 0;
17 | }
18 | }
19 | @keyframes topTo {
20 | 0% {
21 | top: -108px;
22 | }
23 | 100%{
24 | top: 108px;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/Page/PageType.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { LoadableComponent } from '@loadable/component';
3 | import { RouteComponentProps, StaticContext } from 'react-router';
4 |
5 |
6 | // 路由类型
7 | export interface RouteConfigType {
8 | path: string, // 路径
9 | excat: boolean,// 严格匹配还是非严格匹配
10 | component: LoadableComponent>, // 组件名称
11 | name?: string,// 底部appBar参数
12 | defaultImg?: string,// 默认图片
13 | selectImg?: string, // 选中图片
14 | meta: {
15 | title: string, // document.title 字段
16 | requiresAuth: boolean,// 是否需要登录
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Redux/Store/Store.ts:
--------------------------------------------------------------------------------
1 | import { Store, applyMiddleware , createStore} from "redux";
2 | import thunkMiddleware from "redux-thunk";
3 | import { routerMiddleware } from "react-router-redux";
4 | import { History } from "history";
5 | import Reducers from "../Reducer/Reducer";
6 |
7 | // 创建集中管理stroe
8 | const configureStore = (history: History, initState?: string):Store => {
9 | const middleware = applyMiddleware(thunkMiddleware, routerMiddleware(history));
10 | return createStore(
11 | Reducers.combineReducers,
12 | middleware
13 | ) as Store;
14 | }
15 |
16 | export default configureStore;
--------------------------------------------------------------------------------
/src/Redux/Actions/Actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from "redux-actions";
2 | import { ActionsEnum } from '../Types/Types';
3 | import { LocationType } from '../State/StateType';
4 |
5 | // 设置用户状态异步方法
6 | const userStatusAction = createAction(ActionsEnum.UserStatusAction, (status: boolean) => status);
7 |
8 | // 设置用户地理位置
9 | const userLocalAction = createAction(ActionsEnum.userLocalAction, (state: LocationType) => state);
10 |
11 | // 是否iphoneX
12 | const iphoneXAction = createAction(ActionsEnum.iphoneXAction, (state: boolean) => state)
13 |
14 | export {
15 | userStatusAction,
16 | userLocalAction,
17 | iphoneXAction
18 | }
--------------------------------------------------------------------------------
/src/Page/User/User.scss:
--------------------------------------------------------------------------------
1 | .user {
2 | .container {
3 |
4 | .top {
5 | height: 30px;
6 | background-image: linear-gradient(blue, blue,blue);
7 | -webkit-background-clip:text;
8 | background-clip: text;
9 | // background-position: 0 20px, 0 100px ;
10 | color: transparent;
11 | background-repeat: no-repeat;
12 | }
13 | .bottom {
14 | height: 50px;
15 | }
16 | // .text {
17 | // // position: absolute;
18 | // top: 0;
19 | // z-index: 10;
20 | // }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/ListView/ListView.scss:
--------------------------------------------------------------------------------
1 | .listView{
2 | position: relative;
3 | background: #ffffff;
4 | border-bottom-left-radius: 20px;
5 | border-bottom-right-radius: 20px;
6 | overflow: hidden;
7 | }
8 | .footText {
9 | text-align: center;
10 | padding: 10px 0;
11 | color: #999999;
12 | font-size: 24px;
13 | height: 30px;
14 | line-height: 30px;
15 | // position: absolute;
16 | // width: 690px;
17 | background: #ffffff;
18 | z-index: 999;
19 | }
20 | .loading {
21 | position: absolute;
22 | display: flex;
23 | justify-content: center;
24 | left: 45%;
25 | // top: -20px;
26 | span {
27 | margin-left: 10px;
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Components/AppointmentDate/AppointmentDate.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { RouteComponentProps } from 'react-router'
3 | import styles from "./AppointmentDate.scss";
4 | import loadable from '@loadable/component';
5 | const Header = loadable(() => import(/* webpackChunkName: "AppointmentDate" */"./AppointmentDateHeader/AppointmentDateHeader"));
6 | const Body = loadable(() => import(/* webpackChunkName: "AppointmentDate" */"./AppointmentDateBody/AppointmentDateBody"))
7 |
8 | // 日历组件
9 | const AppointmentDate = (props: RouteComponentProps) => {
10 | return (
11 |
12 |
13 |
14 |
15 | )
16 | }
17 |
18 |
19 | export default AppointmentDate;
20 |
--------------------------------------------------------------------------------
/src/Page/Home/Home.scss:
--------------------------------------------------------------------------------
1 | .size {
2 | font-size: 16px;
3 | width: 100vw;
4 | height: 100vh;
5 | div {
6 | &:last-child {
7 | padding-bottom: 105px;
8 | }
9 | }
10 | .mask {
11 | font-size: 50px;
12 | position: fixed;
13 | width: 100vw;
14 | height: 100vh;
15 | }
16 | .getData {
17 | width: 100vw;
18 | text-align: center;
19 | font-size: 36px;
20 | color: red;
21 | }
22 | }
23 |
24 | .img {
25 | width: 240px;
26 | height: 240px;
27 | }
28 |
29 | .show {
30 | overflow: inherit;
31 | }
32 | .hide {
33 | overflow: hidden;
34 | height: 100vh;
35 | }
36 | .bgImg {
37 | width: 100px;
38 | display: block;
39 | }
40 | .positon {
41 | position: fixed;
42 | top: 0;
43 | }
44 |
--------------------------------------------------------------------------------
/src/Components/AppointmentDate/AppointmentDateHeader/AppointmentDateHeader.scss:
--------------------------------------------------------------------------------
1 | .appointmentDateHeader {
2 | width: 100%;
3 | ul {
4 | padding: 30px 0px;
5 | width: 630px;
6 | margin: 0 auto;
7 | display: flex;
8 | border-bottom: 2px solid #f3f3f3;
9 | li {
10 | font-size: 22px;
11 | margin-right: 50px;
12 | white-space: nowrap;
13 | &:last-child {
14 | margin-right: 0;
15 | }
16 | }
17 | .active {
18 | color: #e81844;
19 | }
20 | }
21 | }
22 |
23 | @media only screen and (max-width:320px) {
24 | .appointmentDateHeader {
25 | ul {
26 | li {
27 | margin-right: 5.36vw!important;
28 | }
29 | }
30 |
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Utils/Wx/WxPay.ts:
--------------------------------------------------------------------------------
1 | // 支付参数类型
2 | interface DataType {
3 | appId: string, // 公众号名称,由商户传入
4 | timeStamp: string, // 时间戳,自1970年以来的秒数 字符串类型
5 | nonceStr: string, // 随机串
6 | package: string, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
7 | signType: string, // 微信签名方式:
8 | paySign: string, // 微信签名
9 | }
10 | /** 微信内置浏览器支付
11 | * @param data 参数, 后台返回
12 | * @param success 成功回调
13 | * @param cancel 失败回调
14 | */
15 | const wxPay = (data: DataType, success: () => void, cancel: () => void) => {
16 | WeixinJSBridge.invoke('getBrandWCPayRequest',
17 | {...data},
18 | (res: any) => {
19 | if (res.err_msg === "get_brand_wcpay_request:ok") {
20 | success();
21 | }else {
22 | cancel();
23 | }
24 | })
25 | };
26 | export default wxPay;
--------------------------------------------------------------------------------
/src/Utils/UserAgent/UserAgent.ts:
--------------------------------------------------------------------------------
1 | /** 是否是微信浏览器
2 | * @param type 'isWx' | 'isAndrois' | 'isIos' 平台类型
3 | * @example
4 | * 微信浏览器
5 | * const phoneType: string = userAgent("isWx"); ||
6 | * const phoneType: string = userAgent("isAndroid");||
7 | * const phoneType: string = userAgent("isAndroid");
8 | * @returns
9 | * boolean 结果返回布尔值
10 | */
11 | type UserAgentType = "isWx" | "isAndroid" | "isIos";
12 | const userAgent: (type: UserAgentType) => boolean = (type: UserAgentType) => {
13 | const navigatorUserAgent: string = window.navigator.userAgent.toUpperCase();
14 | const map:Map boolean> = new Map([
15 | ["isWx", () => navigatorUserAgent.includes("MICROMESSENGER")],
16 | ["isAndroid", () => navigatorUserAgent.includes("ANDROID")],
17 | ["isIos", () => navigatorUserAgent.includes("IOS")],
18 | ]);
19 | return map.get(type)!();
20 | }
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter } from "react-router-dom";
4 | import registerServiceWorker from './registerServiceWorker';
5 | import { Provider } from "react-redux";
6 | import { createBrowserHistory } from "history";
7 | import configureStore from ".//Redux/Store/Store";
8 | import loadable from '@loadable/component';
9 | const App = loadable(() => import(/* webpackChunkName: "app" */'./App'));
10 | // 创建store注入
11 | const store = configureStore(createBrowserHistory());
12 | import './Static/Css/Reset.css';
13 | import 'antd-mobile/dist/antd-mobile.css'; // or 'antd-mobile/dist/antd-mobile.less'
14 | ReactDOM.render(
15 |
16 |
17 |
18 |
19 |
20 | ,
21 | document.getElementById('root') as HTMLElement
22 | );
23 | registerServiceWorker();
24 |
--------------------------------------------------------------------------------
/src/Utils/MapCallback/MapCallback.ts:
--------------------------------------------------------------------------------
1 | /** 坐标逆解析
2 | * @param base city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
3 | */
4 | export const locationInverseAnalysis: (base: string) => Promise = (base: string) => {
5 | return new Promise((resolve, reject) => {
6 | const aMap = new AMap.Map("container");
7 | aMap.plugin("AMap.Geocoder", function() {
8 | const geocoder = new AMap.Geocoder({
9 | // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
10 | city: base,
11 | })
12 | geocoder.getLocation('北京市海淀区苏州街', function(status: string, result: any) {
13 | if (status === 'complete' && result.info === 'OK') {
14 | // result中对应详细地理坐标信息
15 | resolve(result);
16 | }
17 | })
18 | });
19 | }).then(res => {
20 | return res;
21 | })
22 |
23 | }
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | let argv = process.argv.slice(2);
20 |
21 | // Watch unless on CI, in coverage mode, or explicitly running all tests
22 | if (
23 | !process.env.CI &&
24 | argv.indexOf('--coverage') === -1 &&
25 | argv.indexOf('--watchAll') === -1
26 | ) {
27 | argv.push('--watch');
28 | }
29 |
30 |
31 | jest.run(argv);
32 |
--------------------------------------------------------------------------------
/config/polyfills.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof Promise === 'undefined') {
4 | // Rejection tracking prevents a common issue where React gets into an
5 | // inconsistent state due to an error, but it gets swallowed by a Promise,
6 | // and the user has no idea what causes React's erratic future behavior.
7 | require('promise/lib/rejection-tracking').enable();
8 | window.Promise = require('promise/lib/es6-extensions.js');
9 | }
10 |
11 | // fetch() polyfill for making API calls.
12 | require('whatwg-fetch');
13 |
14 | // Object.assign() is commonly used with React.
15 | // It will use the native implementation if it's present and isn't buggy.
16 | Object.assign = require('object-assign');
17 |
18 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
19 | // We don't polyfill it in the browser--this is user's responsibility.
20 | if (process.env.NODE_ENV === 'test') {
21 | require('raf').polyfill(global);
22 | }
23 |
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/SharePoster/CreateQrcode.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useCallback, useMemo, useEffect, useRef, RefObject} from 'react';
2 | import QRcode from 'qrcode'
3 | /** 生成二维码组件
4 | * @param props 对象值
5 | * @param url 二维码url
6 | * @param width 二维码宽度
7 | * @param height 二维码高度
8 | */
9 | const CreateQrcode = (props: {url: string, width: number, height: number}) => {
10 | const [getQrCodeImg, setQrcodeImg] = useState(''); // 生成二维码
11 | const qrCodeRef:RefObject = useRef(null);
12 | useEffect(() => {
13 | createQrcodeImg();
14 | }, [])
15 | // 生成二维码函数
16 | const createQrcodeImg = useCallback(() => {
17 | //
18 | }, [getQrCodeImg]);
19 | return (
20 |
21 |

22 |
23 | )
24 | }
25 |
26 | export default CreateQrcode;
--------------------------------------------------------------------------------
/src/Components/AppointmentDate/AppointmentDateHeader/AppointmentDateHeader.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import styles from "./AppointmentDateHeader.scss";
3 | const AppointmentDateHeader = (props: any) => {
4 | const [getDateWeek, setDateWeek] = useState(["周日","周一","周二","周三","周四","周五","周六"]);
5 | const [getSelectDate, setSelectDate] = useState(-1); // 当前星期几
6 | useEffect(() => {
7 | const dateNow: Date = new Date(); // 当前时间
8 | const nowWeek = dateNow.getDay();
9 | setSelectDate(nowWeek);
10 | },[]);
11 | const titleDate = getDateWeek.map((data: string, index: number) => {
12 | return {data}
13 | })
14 | return (
15 |
20 | )
21 | }
22 |
23 |
24 |
25 | export default AppointmentDateHeader
26 |
27 |
--------------------------------------------------------------------------------
/src/Utils/Wx/WxShare.ts:
--------------------------------------------------------------------------------
1 | /** 微信分享配置参数 参数没有则设置为空
2 | * @param title 分享标题
3 | * @param desc 分享描述
4 | * @param link 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
5 | * @param imgUrl 分享图标
6 | * @param successFn 成功回调
7 | * @param cancelFn 失败回调
8 | */
9 | const wxShare = (title: string, desc: string, link: string, imgUrl: string, successFn: () => void, cancelFn: () => void) => {
10 | // 分享平台类型
11 | const wxShareArr: string[] = ['onMenuShareWeibo', 'onMenuShareQZone', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ'];
12 | wx.ready(() => {
13 | wxShareArr.forEach((item: string, index: number) => {
14 | wx[item]({
15 | title,
16 | desc,
17 | link,
18 | imgUrl,
19 | success: () => {
20 | successFn();
21 | },
22 | cancel: () => {
23 | cancelFn();
24 | }
25 | })
26 | });
27 | })
28 | };
29 | export default wxShare;
--------------------------------------------------------------------------------
/src/Redux/State/State.ts:
--------------------------------------------------------------------------------
1 | import { LocationType } from './StateType';
2 |
3 | export const userStatus: boolean = localStorage.getItem("userStatus") ?
4 | localStorage.getItem("userStatus") === "true" ? true : false
5 | : false; // 用户状态
6 |
7 | export const token: string = ''; // 用户token
8 |
9 | export const userLocal: LocationType = sessionStorage.getItem("userLocal") ? JSON.parse(sessionStorage.getItem("userLocal")!) : {
10 | addressComponent: {
11 | adcode: "", // 城市编码
12 | city: "", // 城市
13 | district: "",// 区
14 | neighborhood: "", // 区的具体位置
15 | province: "",// 省份
16 | street: "", // 街道
17 | township: "", // 街道名称
18 | streetNumber: "", // 门牌号
19 | },
20 | position: {
21 | lat: 0, // 纬度
22 | lng: 0, // 经度
23 | }
24 | };
25 |
26 | // 是否iphoneX
27 | export const isIphoneX: boolean = JSON.parse(localStorage.getItem('isIphoneX')!) || false;
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "tslint:recommended",
4 | "tslint-react",
5 | "tslint-config-prettier"
6 | ],
7 | "linterOptions": {
8 | "exclude": [
9 | "config/**/*.js",
10 | "node_modules/**/*.ts",
11 | "coverage/lcov-report/*.js"
12 | ]
13 | },
14 | "rules":{
15 | "no-shadowed-variable": false, // 允许接口内使用其他接口
16 | "no-debugger": false,
17 | "no-console": false,
18 | "no-empty-interface":true,
19 | "only-arrow-functions": false, // 允许箭头函数中使用 es5 函数
20 | "interface-name":false, // 接口开头不必用I
21 | //需要按字母顺序引入模块
22 | "ordered-imports": false,
23 | // jsx中匿名函数
24 | "jsx-no-lambda": false,
25 | "no-string-literal":false,
26 | "object-literal-sort-keys": false, // 检查对象文字中键的排序
27 | "no-floating-promises": false, //必须正确处理promise的返回函数
28 | "promise-function-async": false, //要求异步函数返回promise
29 | "no-empty": false,
30 | "no-implicit-dependencies":[false], // 此参数配置alias必须
31 | "no-submodule-imports": [false, "src"],// 次参数配置alias必须
32 | "forin":true,
33 | "variable-name": false, // 后台接口带下划线,不是驼峰格式需关闭
34 | "prefer-for-of":false,
35 | "no-unused-expression": false
36 | },
37 | "jsRules": {
38 |
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "build/dist",
5 | "module": "esnext",
6 | "target": "es5",
7 | "lib": ["esnext", "dom"],
8 | "sourceMap": true,
9 | "allowJs": true,
10 | "jsx": "react",
11 | "moduleResolution": "node",
12 | "rootDir": "..",
13 | "forceConsistentCasingInFileNames": true,
14 | "noImplicitReturns": true,
15 | "noImplicitThis": true,
16 | "noImplicitAny": true,
17 | "importHelpers": true,
18 | "strictNullChecks": true,
19 | "suppressImplicitAnyIndexErrors": true,
20 | "noUnusedLocals": false,
21 | "experimentalDecorators":true,
22 | "allowUnusedLabels": true, // 不报告未使用标签错误
23 | "diagnostics": false, // 显示诊断信息
24 | "allowSyntheticDefaultImports": true,
25 | "downlevelIteration": true, // 开启全迭代模式
26 | "paths": {
27 | "@/*": ["src/*"],
28 | "@Components/*": ["src/Components/*"],
29 | "@Static/*": ["src/Static/*"],
30 | "@Utils/*": ["src/Utils/*"],
31 | "@Page/*": ["src/Page/*"],
32 | "@Redux/*": ["src/Redux/*"],
33 | }
34 | },
35 | "exclude": [
36 | "node_modules",
37 | "build",
38 | "scripts",
39 | "acceptance-tests",
40 | "webpack",
41 | "jest",
42 | "src/setupTests.ts"
43 | ],
44 | }
45 |
--------------------------------------------------------------------------------
/src/Redux/Actions/HandleAction.ts:
--------------------------------------------------------------------------------
1 | import { handleActions, Action } from "redux-actions";
2 | import { userStatus, userLocal, isIphoneX } from '../State/State';
3 | import { ActionsEnum } from '../Types/Types';
4 | import { LocationType } from '../State/StateType';
5 |
6 | // 用户状态
7 | const userStatusReducer = handleActions({
8 | [ActionsEnum.UserStatusAction]: (state: boolean, action: Action) => {
9 | // 需要持久保留的状态存在localStorage里, 不需要持久保存的存在sessionStorage里;
10 | localStorage.setItem("userStatus", JSON.stringify(action.payload))
11 | return action.payload
12 | }
13 | }, userStatus);
14 |
15 | // 用户地理位置
16 | const userLocaltionReducer = handleActions({
17 | [ActionsEnum.userLocalAction]: (state: LocationType, action: Action) => {
18 | sessionStorage.setItem("userLocal", JSON.stringify(action.payload));
19 | return action.payload;
20 | }
21 | }, userLocal)
22 |
23 | // 是否iphoneX
24 | const isIphoneXReducer = handleActions({
25 | [ActionsEnum.iphoneXAction]: (state: boolean, action: Action) => {
26 | localStorage.setItem("isIphoneX", JSON.stringify(action.payload));
27 | return action.payload;
28 | }
29 | }, isIphoneX)
30 |
31 | export {
32 | userStatusReducer,
33 | userLocaltionReducer,
34 | isIphoneXReducer
35 | }
--------------------------------------------------------------------------------
/src/Page/Shop/Shop.scss:
--------------------------------------------------------------------------------
1 | .shop {
2 | width: 690px;
3 | border-radius: 30px;
4 | margin: 20px auto;
5 | background: #ffffff;
6 | padding-top: 30px;
7 | padding-bottom: 30px;
8 | .christmas {
9 | width: 600px;
10 | height: 600px;
11 | margin: 0 auto;
12 | position: relative;
13 | .top {
14 | width: 100%;
15 | display: flex;
16 | }
17 | .right {
18 | position: absolute;
19 | right: 0;
20 |
21 | }
22 | .bottom {
23 | position: absolute;
24 | bottom: 0;
25 | display: flex;
26 | right: 150px;
27 |
28 | }
29 | .left {
30 | position: absolute;
31 | left: 0;
32 | top: 150px;
33 | }
34 | .active {
35 | -webkit-filter: drop-shadow(6px 6px 10px green) blur(2px);
36 | filter: drop-shadow(6px 6px s10px green) blur(2px);
37 | transform: scale(1.08);
38 | }
39 | }
40 | .childNode {
41 | width: 150px;
42 | height: 150px;
43 | // background: red;
44 | // flex: 1;
45 | // border: 1px solid #999999;
46 | background: url(http://pic.90sjimg.com/design/00/07/85/23/5a3c63e0854b9.png);
47 | background-size: cover;
48 | }
49 | }
--------------------------------------------------------------------------------
/src/Components/UniversalComponents/FormValidate/FormValidate.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo, useState, useCallback, ChangeEvent, memo } from 'react'
2 | import styles from "./FormValidate.scss";
3 | import { PropsType, DataType } from './FromValidateType';
4 |
5 | const FormValidate = (props: PropsType) => {
6 | const [getData, setData] = useState([...props.data])
7 |
8 | const changeDataFn = useCallback((index: number, value: string) => {
9 | console.log(value, 'event');
10 | props.changeFn(index, value)
11 | }, [getData]);
12 |
13 |
14 | const validateMemo: JSX.Element[]| JSX.Element = useMemo(() => {
15 | return props.data.map((_: DataType, index: number) => {
16 | return
17 |
18 | ) => changeDataFn(index, event.target.value)}/>
19 |
20 | })
21 | }, [props.data])
22 | return (
23 |
24 | { validateMemo }
25 |
26 | )
27 | }
28 |
29 | function propsChange(curProps: PropsType, nextProps: PropsType): boolean {
30 | if(JSON.stringify(curProps.data) !== JSON.stringify(nextProps)) {
31 | return true;
32 | }
33 | return false;
34 | }
35 |
36 | export default memo(FormValidate, propsChange)
37 |
--------------------------------------------------------------------------------
/src/Static/Css/Reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 | /* HTML5 display-role reset for older browsers */
27 | article, aside, details, figcaption, figure,
28 | footer, header, hgroup, menu, nav, section {
29 | display: block;
30 | }
31 | body {
32 | line-height: 1;
33 | }
34 | ol, ul {
35 | list-style: none;
36 | }
37 | blockquote, q {
38 | quotes: none;
39 | }
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {
42 | content: '';
43 | content: none;
44 | }
45 | table {
46 | border-collapse: collapse;
47 | border-spacing: 0;
48 | }
49 | *:focus { outline: none; }
50 | html body {
51 | width: 100vw;
52 | overflow-x: hidden;
53 | }
54 | div {
55 | cursor: pointer;
56 | }
57 | li {
58 | list-style: none;
59 | }
60 |
--------------------------------------------------------------------------------
/src/Utils/HttpList/PublicHttp/PublicHttp.ts:
--------------------------------------------------------------------------------
1 | import { imgToBase64, base64ToBolb } from '@/Utils/Base/Base';
2 | import axiosInit from "../../Axios/Axios";
3 | /** 上传图片并且压缩
4 | * @param file file对象
5 | */
6 | export const upload = async (file: File) => {
7 | const name = file.name.split(".")[0];
8 | const fileSize: number = file.size;
9 | // 最大尺寸
10 | const maxSize: number = 2 * 1024 * 1024;
11 | const formData = new FormData();
12 | const reader = new FileReader();
13 | let result;
14 | if(fileSize > maxSize) {
15 | result = await new Promise((resolve, reject) => {
16 | reader.readAsDataURL(file);
17 | reader.onload = async (e:any) => {
18 | const base64 = await imgToBase64(e.target.result) as string;
19 | const toBolb = await base64ToBolb(base64);
20 | resolve(toBolb)
21 | }
22 | }).then(async (res: Blob) => {
23 | const file = new File([res], Date.now() + name + ".jpeg", {type: "image/jpeg"})
24 | formData.append("file", file)
25 | const data = await axiosInit("xxx",{
26 | formData
27 | });
28 | return data;
29 | }).catch(err => {
30 | return null;
31 | })
32 | }else {
33 | formData.append("file", file)
34 | result = await axiosInit("xxx", {
35 | formData
36 | });
37 | return result;
38 | }
39 |
40 | return result["data"]
41 |
42 | }
--------------------------------------------------------------------------------
/src/Utils/Base/Times.ts:
--------------------------------------------------------------------------------
1 | import { DateFormatType } from './TimesType';
2 |
3 | class Times {
4 | public static instance = new Times();
5 | /** 时间格式化
6 | * @param date 时间戳
7 | * @returns DateFormatType
8 | */
9 | public dateFormat(date: number):DateFormatType {
10 | const currentDate = new Date(date);
11 | const year = currentDate.getFullYear();
12 | const month = currentDate.getMonth() + 1;
13 | const day = currentDate.getDate();
14 | const hour = currentDate.getHours();
15 | const milliseconds = currentDate.getMilliseconds();
16 | return {
17 | year,
18 | month,
19 | day,
20 | hour,
21 | milliseconds
22 | }
23 | }
24 |
25 | /** 获取周几
26 | * @param date 时间戳
27 | * @returns number
28 | */
29 | public dateWeek(date: number): number {
30 | const currentWeek = new Date(date).getDay();
31 | return currentWeek;
32 | }
33 |
34 | /** 获取这个月有多少天
35 | * @param date 时间戳
36 | */
37 | public monthHaveDay(date: number): number {
38 | const current = this.dateFormat(date);
39 | const { year, month, day} = current;
40 | const currentMonthHaveDay = new Date(year, month, 0).getDate();
41 | return currentMonthHaveDay;
42 | }
43 |
44 | /** 获取今天的00:00的时间戳
45 | * @param date 时间戳
46 | */
47 | public currentTime(date: number): number {
48 | const current = this.dateFormat(date);
49 | const { year, month, day} = current;
50 | const currentMonthHaveDay = new Date(`${year}/${month}/${day}`).getTime();
51 | return currentMonthHaveDay;
52 | }
53 | }
54 | const TimesInstance = Times.instance;
55 | export default TimesInstance;
--------------------------------------------------------------------------------
/src/Router/Router.scss:
--------------------------------------------------------------------------------
1 |
2 | .appBar {
3 | position: fixed;
4 | bottom: 0;
5 | height:100px;
6 | // padding-bottom: calc(env(safe-area-inset-bottom));
7 | width: 100vw;
8 | background: #ffffff;
9 |
10 | // 适配iphoneX
11 | // bottom: calc();
12 | .navBox {
13 | // width: 590px;
14 | // margin: 0 auto;
15 | display: flex;
16 | }
17 | a {
18 | flex: 1;
19 | height: 100%;
20 | div {
21 | margin: .16px auto;
22 | }
23 | }
24 | .navItem {
25 | flex: 1;
26 | height: 100%;
27 | .navitemBox {
28 | // padding: 16px 143px 12px 0;
29 | img {
30 | width: 40px;
31 | height: 40px;
32 | margin-bottom: 12px;
33 | display: block;
34 | margin: 16px auto 16px;
35 | }
36 | p {
37 | margin: 0;
38 | text-align: center;
39 | font-size: 20px;
40 | white-space: nowrap;
41 | color: black;
42 | }
43 | }
44 | }
45 | }
46 | .selectColor {
47 | color: #e81844!important;
48 | }
49 | .oageView {
50 | height: 100%;
51 | }
52 | /* x xs */
53 | @media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
54 | // iphoneX iphoneXS样式
55 | .appBar {
56 | padding-bottom: 15px;
57 | .navBox {
58 | height: 115px;
59 | }
60 | }
61 | }
62 | /* xr */
63 | @media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) {
64 | // iphoneXR样式
65 | .appBar {
66 | padding-bottom: 15px;
67 | .navBox {
68 | height: 115px;
69 | }
70 | }
71 | }
72 | /* xs max */
73 | @media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) {
74 | // iphoneXR样式
75 | .appBar {
76 | padding-bottom: 15px;
77 | .navBox {
78 | height: 115px;
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/src/Utils/Axios/Axios.ts:
--------------------------------------------------------------------------------
1 | import axios , { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource, CancelTokenStatic, Canceler}from "axios";
2 | import queryString from "qs";
3 | import { Toast } from "antd-mobile";
4 | import { baseUrl } from "./AxiosConfig";
5 |
6 | const mapList:Map= new Map();
7 |
8 | let cancelResult = null;
9 |
10 | // 取消http请求,防止多次点击触发
11 | const cancelToken:CancelTokenStatic = axios.CancelToken;
12 |
13 | /** 请求拦截, 相应拦截
14 | * @param url 请求路径
15 | * @param axiosInit axios实例
16 | */
17 | const httpInit = async (url: string, axiosInit: AxiosInstance) => {
18 |
19 | axiosInit.interceptors.request.use((config: AxiosRequestConfig) => {
20 | // 不存在set一个对象
21 | if(!mapList.get(url)) {
22 | mapList.set(url, url);
23 | }else {
24 | // 存在则取消上一个请求
25 | config.cancelToken = new cancelToken((cancel: Canceler) => {
26 | mapList.delete(url);
27 | cancelResult = cancel;
28 | });
29 | }
30 | // doSomthing
31 | return config;
32 | });
33 | axiosInit.interceptors.response.use((config: AxiosResponse) => {
34 | if(mapList.has(url)) {
35 | mapList.delete(url);
36 | }
37 | return Promise.resolve(config.data);
38 | }, (err: Error) => {
39 | Toast.fail("网络错误, 请刷新重试");
40 | })
41 | };
42 |
43 | /** 创建axios请求对象
44 | * @param url 请求路径
45 | * @param params 请求参数
46 | */
47 | const init = async (url: string, paramsData: any): Promise => {
48 | const haveAxios: string = mapList.get(url)!;
49 | console.log(haveAxios, 'mmm');
50 | const axiosInit = axios.create({
51 | baseURL: baseUrl,
52 | method: "post",
53 | timeout: 10000,
54 | // withCredentials: false, // 表示跨域请求时是否需要使用凭证
55 | });
56 | await httpInit(url, axiosInit);
57 | return axiosInit(url, paramsData);
58 | }
59 |
60 | /** http 请求
61 | * @param url 请求地址
62 | * @param params 请求参数
63 | * @param method get | post
64 | */
65 | const httpConnect = (url: string, params: any, method?: string) => {
66 | return init(url,{
67 | method: method || "post",
68 | data: queryString.stringify(params)
69 | })
70 | }
71 |
72 | export default httpConnect;
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right -->
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
38 |
39 | 主页
40 |
41 |
42 |
45 |
46 |
47 |
48 |
49 |
52 |
53 |