精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

電子發燒友App

硬聲App

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示
電子發燒友網>電子資料下載>電子資料>opennft-front開源NFT前端平臺

opennft-front開源NFT前端平臺

2022-06-06 | zip | 6.32 MB | 次下載 | 2積分

資料介紹

授權協議 Apache
開發語言 JavaScript HTML/CSS
操作系統 跨平臺
軟件類型 開源軟件

軟件簡介

?

項目開始 BEGIN

項目說明

基于 React16.x、Ant Design4.x,react-admin

目錄結構

├── config              // 項目構建配置
├── public              // 不參與構建的靜態文件
├── scripts             // 構建腳本
├── src
│   ├── assets          // 全項目通用圖片文件等
│   ├── commons         // 全項目通用js,業務相關
│   ├── components      // 全項目通用組件,業務相關
│   ├── config          // 項目構建補充配置
│   ├── layouts         // 頁面框架布局組件+
│   ├── mock            // 模擬數據
│   ├── models          // 模塊封裝,基于redux,提供各組件共享數據、共享邏輯
│   ├── pages           // 主項目頁面目錄
│   ├── ├── Project                 // 子項目頂級目錄
│   ├── ├── ├── nft                 // NFT--PC版本項目目錄
│   ├── ├── ├── ├── assets               // NFT--PC版本公共圖片文件
│   ├── ├── ├── ├── components           // NFT--PC版本公共組件庫
│   ├── ├── ├── ├── pages                // NFT--PC版本頁面目錄
│   ├── ├── ├── mobile              // 移動端項目目錄
│   ├── ├── ├── ├── nft-mobile           // NFT--微信版本項目目錄
│   ├── ├── ├── ├── ├── assets              //  NFT--微信版本公共圖片文件
│   ├── ├── ├── ├── ├── components          //  NFT--微信版本公共組件庫
│   ├── ├── ├── ├── ├── pages               //  NFT--微信版本頁面目錄
│   ├── router              // 路由
│   ├── ant.less            // 主體配置
│   ├── App.js              // 根組件
│   ├── index.css           // 全局樣式 慎用
│   ├── index.dark.css       // 全局樣式 慎用
│   ├── index.js            // 項目入口
│   ├── menus.js            // 菜單配置
│   ├── setupProxy.js       // 后端聯調代理配置
│   └── theme.less          // 主題變量
├── package.json
├── README.md
└── yarn.lock

安裝依賴

$ yarn

啟動注意事項

依賴安裝完成后,src/setupProxy.js 為項目本地代理文件,請及時更改您需要代理的接口地址!

!!!微信版本只可以在微信打開運行,并直接在 router/AuthRoute.jsx 中填入自己申請的 appid,目前為''

此為兩個項目依托同一底層框架,PC 及微信端口分離,如需切換請在 router/app.router.js 中更換路由,router/AppRoute.jsx 中切換引入的 AuthRoute(分別為微信版本:AuthRoute.jsx,PC 版本:AuthRoutePC.jsx) 并在 src/commons/PRE_ROUTER.js 中進行相關配置,以及 package.json 中更改 homepage 為相應的項目名稱。

兩套 PRE_ROUTER.js 中配置分別如下:

微信版本: 路由前綴----/front_nft_mobile 請求地址前綴----/api/nft 登錄頁面----/nft_mobile_home

PC 版本: 路由前綴----/front_nft_pc 請求地址前綴----/api/nft 登錄頁面----/nft_home

開發啟動

$ yarn start

#指定端口
$ PORT=8080 yarn start

# HTTPS方式啟動
$ HTTPS=true yarn start

生產構建

$ yarn build

// 構建輸入到指定目錄
$ BUILD_PATH=../dist yarn build

域名子目錄發布項目

// 開發啟動
$ BASE_NAME=/synext-admin yarn start

// 開發訪問
'http://localhost:XXXX/synext-admin/'

//生產環境 同上
$ BASE_NAME=/synext-admin yarn start
// 訪問
'http://xxx.com/synext-admin'

菜單配置

//在/src/menus.js文件中配置菜單數據,前端硬編碼或異步加載菜單數據。
// 菜單支持頭部、左側、頭部+左側三種布局方式,默認左側菜單。如需放開設置,請到'src/layouts/index.jsx'放開注釋
//菜單字段說明。
字段	必須	說明
key	    	//需要唯一
parentKey		//用于關聯父級
path		//菜單對應的路由地址
text		//菜單標題
icon		//菜單圖標配置
url	    	//菜單對應會打開url對應的iframe頁面,如果配置了url,path將無效
target		//配合url使用,菜單將為a標簽 {text}
order		//菜單排序,數值越大越靠前顯示
type		//如果菜單數據中攜帶功能權限配置,type= 為菜單,type=為功能
code		//功能碼,如果是type=,會用到此字段

頁面開發

//配置組件
import React, {Component} from 'react';
import config from 'src/commons/config-hoc';

@config({
    title: '頁面title',
    ajax: true,
    ...
})
export default class SomePage extend Component {
    componentDidMount() {
        this.props.ajax
            .get(...)
            .then(...)
    }
    ...
}
參數 類型 默認值 說明
noFrame boolean false 標記當前頁面為不需要導航框架的頁面,比如登錄頁,通過腳本抓取實現
noAuth boolean false 標記當前頁面為不需要登錄即可訪問的頁面,通過腳本抓取實現
keepAlive boolean - 標記當前頁面內容在頁面切換之后是否保持
title boolean 或 string 或 ReactNode 或 object 或 function(props) true true:當前頁面顯示通過菜單結構自動生成的 title;false:當前頁面不顯示 title;string:自定義 title;object:{text,icon} text 為顯示的名稱,icon 為圖標;function(props): 返回值作為 title
breadcrumbs boolean 或 array 或 function(props) true true:當前頁面顯示通過菜單結構自動生成的面包屑;false:當前頁面不顯示面包屑;object:[{icon, text, ...}];function(props): 返回值作為面包屑
appendBreadcrumbs array 或 function(props) [] 在當前面包屑基礎上添加;function(props): 返回值作為新添加的面包屑
pageHead boolean - 頁面頭部是否顯示
side boolean - 頁面左側是否顯示
sideCollapsed boolean - 左側是否收起
ajax boolean true 是否添加 ajax 高階組件,內部可以通過 this.props.ajax 使用 ajax API,組件卸載時,會自動打斷未完成的請求
router boolean false 是否添加 withRouter 裝飾器,組件內部可以使用 this.props.history 等 API
query boolean false 是否添加地址查詢字符串轉換高階組件,內部可以通過 this.props.query 訪問查詢字符串
connect boolean 或 function(state) false 是否與 redux 進行連接,true:只注入了 this.props.action 相關方法;false:不與 redux 進行連接;(state) => ({title: state.page.title}):將函數返回的數據注入 this.props
event boolean false 是否添加 event 高階組件,可以使用 this.props.addEventListener 添加 dom 事件,并在組件卸載時會自動清理;通過 this.props.removeEventListener 移出 dom 事件
pubSub boolean false 是否添加發布訂閱高階組件,可以使用 this.props.subscribe(topic, (msg, data) => {...})訂閱事件,并在組件卸載時,會自動取消訂閱; 通過 this.props.publish(topic, data)發布事件
modal string 或 object false 當前組件是否是 modal。string: 彈框標題;object:彈框配置

注:

  • noFramenoAuthkeepAlive?只有配置了path才有效!
  • config 裝飾器可以用于任何組件,但是titlebreadcrumbsappendBreadcrumbspageHeadsidesideCollapsed最好在路由對應的頁面組件中使用
//頁面保持
//頁面渲染一次之后會保持狀態,再次跳轉到此頁面不會重新創建或重新渲染
開啟方式
1.  /src/models/system.js initState.keepAlive 屬性修改默認值
2.  config裝飾器 keepAlive屬性

頁面顯示/隱藏事件

config?裝飾器為組件注入了兩個事件?onComponentWillShowonComponentWillHide?,如果頁面使用了 Keep Alive 功能,切換顯示/隱藏時會觸發

@config({
    ...
})
export default class SomePage extends React.Component {
    constructor(...props) {
        super(...props);

        this.props.onComponentWillShow(() => {
            // do some thing
        });

        this.props.onComponentWillHide(() => {
            // do some thing
        });
    }
    ...
}

頁面容器 PageContent

系統提供了頁面的跟節點 PageContent,有如下特性:

  • 添加了 margin padding 樣式;
  • 添加了 footer;
  • 支持頁面 loading;
  • 自動判定是否有底部工具條 FixBottom 組件,為底部工具條騰出空間;

是否顯示 footer,默認 true

<PageContent footer={false}>...</PageContent>

顯示 loading,有兩種方式。

  1. model 方式

    this.props.action.page.showLoading();
    this.props.action.page.hideLoading();
    ?
  2. props 方式

    const { loading } = this.state;
    
    <PageContent loading={loading}>...</PageContent>;
    

彈框頁面開發

添加、修改等場景,往往會用到彈框,antd Modal 組件使用不當會產生臟數據問題(兩次彈框渲染數據互相干擾)

系統提供了基于 modal 封裝的高階組件,每次彈框關閉,都會銷毀彈框內容,避免互相干擾

modal 高階組件

modal 高階組件集成到了 config 中,也可以單獨引用:import { ModalContent } from 'src/commons/ra-lib';

import React from "react";
import config from "src/commons/config-hoc";
import { ModalContent } from "src/commons/ra-lib";

export default config({
    modal: {
        title: "彈框標題",
    },
})((props) => {
    const { onOk, onCancel } = props;

    return (
        <ModalContent onOk={onOk} onCancel={onCancel}>
            彈框內容
        ModalContent>
    );
});

modal 所有參數說明如下:

  1. 如果是 string,作為 modal 的 title
  2. 如果是函數,函數返回值作為 Modal 參數
  3. 如果是對象,為 Modal 相關配置,具體參考?antd Modal 組件
  4. options.fullScreen boolean 默認 false,是否全屏顯示彈框

ModalContent 組件

彈框內容通過 ModalContent 包裹,具體參數如下:

參數 類型 默認值 說明
surplusSpace boolean false 是否使用屏幕垂直方向剩余空間
otherHeight number - 除了主體內容之外的其他高度,用于計算主體高度;
loading boolean false 加載中
loadingTip - - 加載提示文案
footer - - 底部
okText string - 確定按鈕文案
onOk function - 確定按鈕事件
cancelText string - 取消按鈕文案
onCancel function - 取消按鈕事件
resetText string - 重置按鈕文案
onReset function - 重置按鈕事件
style object - 最外層容器樣式
bodyStyle object - 內容容器樣式

系統路由

系統路由使用 react-router,通過 route-loader 將路由內容填充到/src/pages/page-routes.js 文件,支持兩種寫法:

  1. 常量方式
    export const PAGE_ROUTE = "/path";
    ?
  2. 頁面 config 裝飾器(推薦)
    @config({
        path: '/path',
    })
    export default class SomePage extends React.Component {
        ...
    }
    

二級頁面

二級頁面如果要保持父級菜單的選中狀態,以父級 path 開始并以/_/作為分隔符即可:parent/path/_/child/path

// parent page
@config({
    path: '/parent/path'
})
export default class Parent extends React.Component {
    ...
}

// child page
@config({
    path: '/parent/path/_/child/path'
})
export default class Parent extends React.Component {
    ...
}

AJAX 請求

系統的 ajax 請求基于 axios 封裝。 基于 restful 規范,提供了 5 個方法:

  • get 獲取服務端數據,參數拼接在 url 上,以 query string 方式發送給后端
  • post 新增數據,參數以 body 形式發送給后端
  • put 修改數據,參數以 body 形式發送給后端
  • del 刪除數據,參數拼接在 url 上,以 query string 方式發送給后端
  • patch 修改部分數據,參數以 body 形式發送給后端

調用方式 三種

//第一種  config裝飾器ajax屬性(推薦)
 import React, {Component} from 'react';
    import config from 'src/commons/config-hoc';

    @config({
        ajax: true,
        ...
    })
    export default class SomePage extend Component {
        componentDidMount() {
            this.props.ajax
                .get(...)
                .then(...)
        }
        ...
    }
//第二種 ajax裝飾器
 import React, {Component} from 'react';
    import {ajaxHoc} from 'src/commpons/ajax';

    @ajaxHoc()
    export default class SomePage extend Component {
        componentDidMount() {
            this.props.ajax
                .get(...)
                .then(...)
        }
        ...
    }
//第三種 直接引入ajax對象
import React, {Component} from 'react';
import {sxAjax} from 'src/commpons/ajax';

    export default class SomePage extend Component {
        componentDidMount() {
            sxAjax.post(...).then(...);

            // 組件卸載或者其他什么情況,需要打算ajax請求,可以用如下方式
            const ajax = sxAjax.get(...);
            ajax.then(...).finally(...);
            ajax.cancel();
        }
        ...
    }

注:config、ajaxHoc 方式做了封裝,頁面被卸載之后會自動打斷未完成的請求

接收參數

所有的 ajax 方法參數統一,都能夠接受三個參數: 參數|說明 ---|--- url|請求地址 params|請求傳遞給后端的參數 options|請求配置,即 axios 的配置。

options 配置

參數 說明
axios 配置 可以接受 axios 參數
successTip 擴展的參數,成功提示
errorTip 擴展的參數,失敗提示
noEmpty 擴展的參數,過濾掉 ''、null、undefined 的參數,不提交給后端
originResponse 擴展參數,.then 中可以拿到完整的 response,而不只是 response.data

注:全局默認參數可以在 src/commons/ajax.js 中進行配置,默認 、timeout=1000 * 60。

請求結果提示

  1. 系統對 ajax 失敗做了自動提示,開發人員可通過 src/commons/handle-error.js 進行配置;
  2. 成功提示默認不顯示,如果需要成功提示,可以配置 successTip 參數,或者.then()中自行處理;
  3. 成功提示在 src/commons/handle-success.js 中配置;
this.props.ajax.del("/user/1", null, {
    successTip: "刪除成功!",
    errorTip: "刪除失敗!",
    noEmpty: true,
});

loading 處理

系統擴展了 promise,提供了 finally 方法,用于無論成功還是失敗,都要進行的處理。一般用于關閉 loading

this.setState({loading: true});
this.props.ajax
    .get('/url')
    .then(...)
    .finally(() => this.setState({loading: false}));

Mock 模擬數據

前后端并行開發,為了方便后端快速開發,不需要等待后端接口,系統提供了 mock 功能。基于mockjs

編寫模擬數據

在/src/mock 目錄下進行 mock 數據編寫,比如:

import { getUsersByPageSize } from "./mockdata/user";

export default {
    "post /mock/login": (config) => {
        const { userName, password } = JSON.parse(config.data);
        return new Promise((resolve, reject) => {
            if (userName !== "test" || password !== "111") {
                setTimeout(() => {
                    reject({
                        code: 1001,
                        message: "用戶名或密碼錯誤",
                    });
                }, 1000);
            } else {
                setTimeout(() => {
                    resolve([
                        200,
                        {
                            id: "1234567890abcde",
                            name: "MOCK 用戶",
                            loginName: "MOCK 登錄名",
                        },
                    ]);
                }, 1000);
            }
        });
    },
    "post /mock/logout": {},

    "get /mock/user-center": (config) => {
        const { pageSize, pageNum } = config.params;

        return new Promise((resolve) => {
            setTimeout(() => {
                resolve([
                    200,
                    {
                        pageNum,
                        pageSize,
                        total: 888,
                        list: getUsersByPageSize(pageSize),
                    },
                ]);
            }, 1000);
        });
    },
    "get re:/mock/user-center/.+": {
        id: 1,
        name: "熊大",
        age: 22,
        job: "前端",
    },
    "post /mock/user-center": true,
    "put /mock/user-center": true,
    "delete re:/mock/user-center/.+": "id",
};

簡化

為了方便 mock 接口編寫,系統提供了簡化腳本(/src/mock/simplify.js),上面的例子就是簡化寫法

對象的 key 由 method url delay,各部分組成,以空格隔開

字段 說明
method 請求方法 get post 等
url 請求的 url
delay 模擬延遲,毫秒 默認 1000

調用

系統封裝的 ajax 可以通過以下兩種方式,自動區分是 mock 數據,還是真實后端數據,無需其他配置

mock 請求:

  • url 以/mock/開頭的請求
  • /src/mock/url-config.js 中配置的請求
this.props.ajax.get('/mock/users').then(...);

如果后端真實接口準備好之后,去掉 url 中的/mock 即可

注:mock 功能只有開發模式下開啟了,生產模式不會開啟 mock 功能,如果其他環境要開啟 mock 使用 MOCK=true 參數,比如?MOCK=true yarn build

樣式

系統使用less進行樣式的編寫。 為了避免多人合作樣式沖突,系統對 src 下的 less 文件啟用了 Css Module,css 文件沒有使用 Css Module。

style.less

.root {
    width: 100%;
    height: 100%;
}

Some.jsx

import "/path/to/style.less";

export default class Some extends React.Component {
    render() {
        return <div styleName="root">div>;
    }
}
?

注:基礎組件不使用 Css Module,不利于樣式覆蓋;

主題

使用 less,通過樣式覆蓋來實現。

編寫主題

  • less 文件中使用主題相關變量;
  • 編寫/src/theme.less通過less-loadermodifyVars覆蓋 less 中的變量;

注:目前每次修改了 theme.less 需要重新 yarn start 才能生效

參考

導航布局

為了滿足不同系統的需求,提供了四種導航布局:

  • 頭部菜單
  • 左側菜單
  • 頭部+左側菜單
  • tab 頁方式

更改方式

  • 用戶可以通過 頁面有上角用戶頭像 -> 設置 頁面進行選擇(如果您為用戶提供了此頁面);
  • 開發人員可以通過修改src/models/index.js指定布局方式;

不需要導航

有些頁面可能不需要顯示導航,可以通過如下任意一種方式進行設置:

  • 頁面配置高級組件
    @config({
        noFrame: true,
    })
    ?
  • 瀏覽器 url 中 noFrame=true 參數
    /path/to?noFrame=true
    

Tab 標簽頁

頁面頭部標簽,有如下特性:

  1. 在當前 tab 標簽之后打開新的 tab 標簽;
  2. 記錄并恢復滾動條位置;
  3. 保持頁面狀態(需要開啟Keep Page Alive);
  4. tab 標簽右鍵操作;
  5. tab 頁操作 API;
  6. tab 標簽拖拽排序;
  7. 關閉一個二級頁面 tab,嘗試打開它的父級;

Tab 操作 API

system model(redux)中提供了如下操作 tab 頁的方法:

API 說明
setCurrentTabTitle(title) 設置當前激活的 tab 標題 title: stirng 或 {text, icon}
refreshTab(targetPath) 刷新 targetPath 指定的 tab 頁內容(重新渲染)
refreshAllTab() 刷新所有 tab 頁內容(重新渲染)
closeCurrentTab() 關閉當前 tab 頁
closeTab(targetPath) 關閉 targetPath 對應的 tab 頁
closeOtherTabs(targetPath) 關閉除了 targetPath 對應的 tab 頁之外的所有 tab 頁
closeAllTabs() 關閉所有 tab 頁,系統將跳轉首頁
closeLeftTabs(targetPath) 關閉 targetPath 對應的 tab 頁左側所有 tab 頁
closeRightTabs(targetPath) 關閉 targetPath 對應的 tab 頁右側所有的 tab 頁

使用方式:

import config from 'src/commons/config-hoc';

@config({
    connect: true,
})
export default class SomeComponent extends React.Component {
    componentDidMount() {
        this.props.action.system.closeTab('/some/path');
    }
    ...
}

注:

  1. tab 基于頁面地址,每當使用this.props.history.push('/some/path'),就會選中或者新打開一個 tab 頁(/path??/path?name=Tom屬于不同 url 地址,會對應兩個 tab 頁);
  2. 沒有菜單對應的頁面,需要單獨設置 title,否則 tab 標簽將沒有 title;

models(redux) 封裝

基于redux進行封裝,不改變 redux 源碼,可以結合使用 redux 社區中其他解決方案。

注:一般情況下,用不到 redux~

models 用于管理數據,解決的問題:

  1. 命名空間(防止數據、方法命名沖突):數據與方法,都歸屬于具體 model,比如:state.userCenter.xxx,this.props.action.userCenter.xxx();
  2. 如何方便的獲取數據:connect 與組件連接;@connect(state => ({name: state.user.name}));
  3. 如何方便的修改數據:this.props.action 中方法;
  4. 客戶端數據持久化(保存到 LocalStorage 中):syncStorage 配置;
  5. 異步數據處理:基于 promise 異步封裝;
  6. 請求錯誤提示:error 處理封裝,errorTip 配置,自動提示;
  7. 請求成功提示:successTip 配置,自動提示;
  8. 簡化寫法:types actions reducers 可以在一個文件中編寫,較少沖突,方便多人協作,參見models/page.js中的寫法;
  9. 業務代碼可集中歸類:在 models 目錄中統一編寫,或者在具體業務目錄中,模塊化方式。

src/models

所有的 model 直接在 models 或 pages 下定義:

model 模塊名規則:

/path/to/models/user-center.js --> userCenter;
/path/to/models/user.js --> user;

/path/to/pages/users/model.js --> users;
/path/to/pages/users/job.model.js --> job;
/path/to/pages/users/user-center.model.js --> userCenter;
/path/to/pages/users/user.center.model.js --> userCenter;

組件與 redux 進行連接

提供了多種種方式,裝飾器方式、函數調用、hooks、js 文件直接使用;

裝飾器

推薦使用裝飾器方式

import {connect} from 'path/to/models';

@connect(state => {
    return {
        ...
    }
})
class Demo extends Component{
    ...
}

函數

import {connectComponent} from 'path/to/models';

class Demo extends Component {
   ...
}
function mapStateToProps(state) {
    return {
        ...
    };
}

export default connectComponent({LayoutComponent: Demo, mapStateToProps});
?

hooks

import { useSelector } from "react-redux";
import { useAction } from "src/models";

export default () => {
    const action = useAction();
    const show = useSelector((state) => state.side.show);

    console.log(show);

    useEffect(() => {
        action.side.hide();
    }, []);

    return <div />;
};

對 useSelector 的說明

useSelector(select) 默認對 select 函數的返回值進行引用比較 ===,并且僅在返回值改變時觸發重渲染。

即:如果 select 函數返回一個臨時對象,會多次 re-render

最好不要這樣使用:
const someData = useSelector(state => {

    // 每次都返回一個新對象,導致re-render
    return {name: state.name, age: state.age};
})

最好多次調用useSelector,單獨返回數據,或者返回非引用類型數據
const name = useSelector(state => state.firstName + state.lastName);
const age = useSelector(state => state.age);

js 文件中使用

沒有特殊需求,一般不會在普通 js 文件中使用

import { action, store } from "src/models";

// 獲取數據
const state = store.getState();

// 修改數據
action.side.hide();

簡化寫法

action reducer 二合一,省去了 actionType,簡化寫法;

注意:

  • 所有的 reducer 方法,無論是什么寫法中的,都可以直接返回新數據,不必關心與原數據合并(...state),封裝內部做了合并;
  • 一個 model 中,除了 initialState syncStorage actions reducers 等關鍵字之外的屬性,都視為 action reducer 合并寫法;

一個函數

一個函數,即可作為 action 方法,也作為 reduce 使用

  • 調用 action 方法傳遞的數據將不會做任何處理,會直接傳遞給 reducer
  • 只能用第一個參數接收傳遞過來的數據,如果多個數據,需要通過對象方式傳遞,如果不需要傳遞數據,但是要使用 state,也需要定義一個參數占位
  • 第二個參數固定為 state,第三個參數固定為 action,不需要可以缺省(一般都是缺省的)
  • 函數的返回值為一個對象或者 undefined,將于原 state 合并,作為 store 新的 state
// page.model.js
export default {
    initialState: {
        title: void 0,
        name: void 0,
        user: {},
        toggle: true,
    },

    setTitle: (title) => ({ title }),
    setName: (name, state, action) => {
        const { name: prevName } = state;
        if (name !== prevName) return { name: "Different Name" };
    },
    setUser: ({ name, age } = {}) => ({ user: { name, age } }),
    setToggle: (arg, state) => ({ toggle: !state.toggle }),
};

// 使用
this.props.action.page.setTitle("my title");

數據同步

通過配置的方式,可以讓 redux 中的數據自動與 localStorage 同步

export default {
    initialState: {
        title: '',
        show: true,
        user: {},
        users: [],
        job: {},
        total: 0,
        loading: false,
        ...
    },

    // initialState會全部同步到localStorage中
    // syncStorage: true,

    // 配置部分存數據儲到localStorage中
    syncStorage: {
        titel: true,
        user: { // 支持對象指定字段,任意層次
            name: true,
            address: {
                city: true,
            },
        },
        job: true,
        users: [{name: true, age: true}], // 支持數組
    },
}

action reducer 合并寫法

如果 action 有額外的數據處理,并且一個 action 只對應一個 reducer,這種寫法不需要指定 actionType,可以有效簡化代碼;

export default {
    initialState: {
        title: '',
        ...
    },

    arDemo: {
        // 如果是函數返回值將作為action.payload 傳遞給reducer,如果非函數,直接將payload的值,作為action.payload;
        payload(options) {...},

        // 如果是函數返回值將作為action.meta 傳遞給reducer,如果非函數,直接將meta的值,作為action.meta;
        meta(options) {...},
        reducer(state, action) {
            returtn {...newState}; // 可以直接返回要修改的數據,內部封裝會與原state合并`{...state, ...newState}`;
        },
    },
};

異步 action 寫法

export default {
    initialState: {
        title: '',
        ...
    },
    fetchUser: {
        // 異步action payload 返回promise
        payload: ({params, options}) => axios.get('/mock/users', params, options),

        // 異步action 默認使用通用異步meta配置 commonAsyncMeta,對successTip errorTip onResolve onReject onComplete 進行了合理的默認值處理,需要action以對象形式傳參調用
        // meta: commonAsyncMeta,
        // meta: {
        //     successTip: '查詢成功!歐耶~',
        //     errorTip: '自定義errorTip!馬丹~',
        // },
        // meta: () => {
        //    return {...};
        // },

        // 基于promise 異步reducer寫法;
        reducer: {
            pending: (state, action) => ({loading: true}),
            resolve(state, {payload = {}}) {
                const {total = 0, list = []} = payload;
                return {
                    users: list,
                    total,
                }
            },
            complete: (state, action) => ({loading: false}),
        }
    },
};

調用方式:

this.props.action.user.fetchUser({
    params,
    options,
    successTip,
    errorTip,
    onResolve,
    onReject,
    onComplete,
});

參數約定為一個對象,各個屬性說明如下:

參數 說明
params 請求參數
options 請求配置
successTip 成功提示信息
errorTip 錯誤提示信息
onResolve 成功回調
onReject 失敗回調
onComplete 完成回調,無論成功、失敗都會調用

單獨定義 action 和 reducer

支持這種比較傳統的寫法,一般也不會太用到

import {createAction} from 'redux-actions';

export const types = {
    GET_MENU_STATUS: 'MENU:GET_MENU_STATUS', // 防止各個模塊沖突,最好模塊名開頭
};

export default {
    initialState: {
        title: '',
        ...
    },

    // 單獨action定義,需要使用actionType與reducer進行關聯
    actions: {
        getMenuStatus: createAction(types.GET_MENU_STATUS),
    },

    // 單獨reducer定義,使用了actionType,不僅可以處理當前model中的action
    // 也可以處理其他任意action(只要actionType能對應)
    reducers: {
        [types.GET_MENU_STATUS](state) {
            ...
            return {
                ...
            };
        }
    },
}

權限控制

系統菜單、具體功能點都可以進行權限控制。

菜單權限

菜單由后端提供(一般系統都是后端提供),后臺通過登錄用戶返回用戶的菜單權限;頁面只顯示獲取到的菜單;

系統提供了一個基礎的菜單、權限管理頁面,需要后端配合存儲數據。

功能權限

可以通過src/components/permission組件對功能的權限進行控制

import React, { Component } from "react";
import Permission from "src/components/permission";

export default class SomePage extends Component {
    render() {
        return (
            <div>
                <Permission code="USER_ADD">
                    <Button>添加用戶</Button>
                </Permission>
            </div>
        );
    }
}
?

注:權限的 code 前端使用時會硬編碼,注意語義化、唯一性。

角色

一般系統都會提供角色管理功能,系統中提供了一個基礎的角色管理功能,稍作修改即可使用。

開發代理

開發時,要與后端進行接口對接,可以通過代理與后端進行連接,開發代理配置在src/setupProxy.js中編寫

const proxy = require("http-proxy-middleware");

const prefix = process.env.AJAX_PREFIX || "/api";

module.exports = function (app) {
    app.use(
        proxy(prefix, {
            target: "http://localhost:3000/",
            pathRewrite: {
                ["^" + prefix]: "", // 如果后端接口無前綴,可以通過這種方式去掉
            },
            changeOrigin: true,
            secure: false, // 是否驗證證書
            ws: true, // 啟用websocket
        })
    );
};

注:更多代理配置請參考http-proxy-middleware

前端默認 ajax 前綴 /api 可以通過 AJAX_PREFIX 參數進行修改。

nginx 配置參考

這里只是參考文件,根據自己的項目需求自行配置

一個域名對應單個項目

目錄結構

.
├── /usr/local/nginx/html
│   ├── static
│   ├── index.html
│?? └── favicon.ico
?

nginx 配置

# 后端服務地址
upstream api_service {
  server xxx.xxx.xxx.xxx:xxxx;
  keepalive 2000;
}

server {
    listen      80;
    server_name www.xxxx.com xxxx.com; # 域名地址
    root        /usr/local/nginx/html; # 前端靜態文件目錄
    location / {
      index index.html;
      try_files $uri $uri/ /index.html; #react-router 防止頁面刷新出現404
    }

    # 靜態文件緩存,啟用Cache-Control: max-age、Expires
    location ~ ^/static/(css|js|media)/ {
      expires 10y;
      access_log off;
      add_header Cache-Control "public";
    }

     # 代理ajax請求 前端ajax請求以 /api 開頭
    location ^~/api {
       rewrite ^/api/(.*)$ /$1 break; # 如果后端接口不是統一以api開頭,去掉api前綴
       proxy_pass http://api_service/;
       proxy_set_header Host  $http_host;
       proxy_set_header Connection close;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-Server $host;
    }
}

一個域名對應多個項目

多個項目掛載到同一個域名下,可以通過子目錄方式區分

比如,如下地址各對應一個項目

前端項目構建時,添加 BASE_NAME PUBLIC_URL 參數

BASE_NAME=/project1 PUBLIC_URL=/project1 yarn build

nginx 靜態文件目錄結構

.
├── /home/ubuntu/synext-admin
│?? ├── build   // 主項目 靜態文件目錄
│   │   ├── static
│   │   ├── index.html
│   │?? └── favicon.ico
│?? ├── project1   // 子項目靜態目錄 名稱與 location /project1 location ~ ^/project1/static/.*  配置對應
│   │   ├── static
│   │   ├── index.html
│   │?? └── favicon.ico

nginx 配置

upstream api_service {
  server xxx.xxx.xxx.xxx:xxxx;
  keepalive 2000;
}

upstream api_service_project1 {
  server xxx.xxx.xxx.xxx:xxxx;
  keepalive 2000;
}
server {
    listen 80;
    server_name www.xxxx.com xxxx.com; # 域名地址
    # Allow file uploads
    client_max_body_size 100M;

    # 主項目配置,訪問地址 http://www.xxxx.com
    location / {
        root /home/ubuntu/synext-admin/build;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
    # 靜態文件緩存,啟用Cache-Control: max-age、Expires
    location ~ ^/static/.* {
        root /home/ubuntu/synext-admin/build;
        expires 20y;
        access_log off;
        add_header Cache-Control "public";
    }
    # 代理ajax請求 前端ajax請求以/api開頭
    location ^~/api {
       rewrite ^/api/(.*)$ /$1 break; # 如果后端接口不是統一以api開頭,去掉api前綴
       proxy_pass http://api_service/;
       proxy_set_header Host  $http_host;
       proxy_set_header Connection close;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-Server $host;
    }

    # 子項目配置 訪問地址 http://www.xxxx.com/project1
    location /project1 {
        root /home/ubuntu/synext-admin;
        index index.html;
        try_files $uri $uri/ /project1/index.html;
    }
    # 靜態文件緩存,啟用Cache-Control: max-age、Expires
    location ~ ^/project1/static/.* {
        root /home/ubuntu/synext-admin;
        expires 10y;
        access_log off;
        add_header Cache-Control "public";
    }
    # 代理ajax請求 前端ajax請求以 /project1_api 開頭
    location ^~/project1_api {
       rewrite ^/api/(.*)$ /$1 break; # 如果后端接口不是統一以api開頭,去掉api前綴
       proxy_pass http://api_service_project1/;
       proxy_set_header Host  $http_host;
       proxy_set_header Connection close;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-Server $host;
    }
}

其他

頁面打印

通過給元素添加相應的 class,控制打印內容:

  • .just-print?只在打印時顯示
  • .no-print?在打印時不顯示

ESLint 說明

如果前端項目,不是 git 根目錄,在提交的時候,會報錯?Not a git repository

修改 package.json,lint-staged 如下即可

"lint-staged": {
    "gitDir": "../",
    "linters": {
        "**/*.{js,jsx}": "lint-staged:js",
        "**/*.less": "stylelint --syntax less"
    }
},

Webpack

使用了 alias {'@': '/path/to/src', src:'/path/to/src'}

  • config/webpack.config.js
  • 方便路徑書寫,不必關心相對路徑結構
  • 復制粘貼到其他文件,不必修改路徑

支持判斷運算符

const name = res?.data?.user?.name || "匿名";

form 表單

  1. FormElement:類型有:
'input', 'hidden', 'number', 'textarea', 'password', 'mobile', 'email', 'select', 'select-tree', 'checkbox', 'checkbox-group', 'radio', 'radio-button', 'radio-group', 'switch', 'date', 'time', 'date-time', 'date-range', 'cascader', 'transfer', 'icon-picker'
?

下載該資料的人也在下載 下載該資料的人還在閱讀
更多 >

評論

查看更多

下載排行

本周

  1. 1山景DSP芯片AP8248A2數據手冊
  2. 1.06 MB  |  532次下載  |  免費
  3. 2RK3399完整板原理圖(支持平板,盒子VR)
  4. 3.28 MB  |  339次下載  |  免費
  5. 3TC358743XBG評估板參考手冊
  6. 1.36 MB  |  330次下載  |  免費
  7. 4DFM軟件使用教程
  8. 0.84 MB  |  295次下載  |  免費
  9. 5元宇宙深度解析—未來的未來-風口還是泡沫
  10. 6.40 MB  |  227次下載  |  免費
  11. 6迪文DGUS開發指南
  12. 31.67 MB  |  194次下載  |  免費
  13. 7元宇宙底層硬件系列報告
  14. 13.42 MB  |  182次下載  |  免費
  15. 8FP5207XR-G1中文應用手冊
  16. 1.09 MB  |  178次下載  |  免費

本月

  1. 1OrCAD10.5下載OrCAD10.5中文版軟件
  2. 0.00 MB  |  234315次下載  |  免費
  3. 2555集成電路應用800例(新編版)
  4. 0.00 MB  |  33566次下載  |  免費
  5. 3接口電路圖大全
  6. 未知  |  30323次下載  |  免費
  7. 4開關電源設計實例指南
  8. 未知  |  21549次下載  |  免費
  9. 5電氣工程師手冊免費下載(新編第二版pdf電子書)
  10. 0.00 MB  |  15349次下載  |  免費
  11. 6數字電路基礎pdf(下載)
  12. 未知  |  13750次下載  |  免費
  13. 7電子制作實例集錦 下載
  14. 未知  |  8113次下載  |  免費
  15. 8《LED驅動電路設計》 溫德爾著
  16. 0.00 MB  |  6656次下載  |  免費

總榜

  1. 1matlab軟件下載入口
  2. 未知  |  935054次下載  |  免費
  3. 2protel99se軟件下載(可英文版轉中文版)
  4. 78.1 MB  |  537798次下載  |  免費
  5. 3MATLAB 7.1 下載 (含軟件介紹)
  6. 未知  |  420027次下載  |  免費
  7. 4OrCAD10.5下載OrCAD10.5中文版軟件
  8. 0.00 MB  |  234315次下載  |  免費
  9. 5Altium DXP2002下載入口
  10. 未知  |  233046次下載  |  免費
  11. 6電路仿真軟件multisim 10.0免費下載
  12. 340992  |  191187次下載  |  免費
  13. 7十天學會AVR單片機與C語言視頻教程 下載
  14. 158M  |  183279次下載  |  免費
  15. 8proe5.0野火版下載(中文版免費下載)
  16. 未知  |  138040次下載  |  免費