摘要:重要功能一些擴(kuò)展的重要功能將在這里一點(diǎn)點(diǎn)從零開始進(jìn)行思考。假設(shè)現(xiàn)在的數(shù)據(jù)是這樣的演示項(xiàng)目接口示例超長字符串測試項(xiàng)目描述前端工程師宋青樹后端工程師獲取接口描述增加接口描述刪除接口描述更新接口描述我們需要將里面所有的字段數(shù)組去除。
前言
二月初想想這個(gè)月還得搗鼓一篇文章,也沒啥好的想法那還是記錄一下畢設(shè)的一些思路吧。
重要功能一些擴(kuò)展的重要功能將在這里一點(diǎn)點(diǎn)從零開始進(jìn)行思考。
項(xiàng)目導(dǎo)入導(dǎo)出功能項(xiàng)目導(dǎo)入導(dǎo)出的構(gòu)想是在設(shè)定特色功能時(shí)候想到的,主要是用于不同服務(wù)器上如果部署了平臺(tái),如果想要自己私下部署測試,那么重新建立項(xiàng)目,然后再一個(gè)個(gè)配置接口路徑,配置返回?cái)?shù)據(jù)是一件很麻煩的事情。為了以后用(自)戶(己)用的順暢,想了一鍵各種版本的功能,其中就包括項(xiàng)目的導(dǎo)入導(dǎo)出。
因此在設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)的時(shí)候,我將最終返回結(jié)果數(shù)據(jù)設(shè)計(jì)成如下形式
{ project:{ projectId:, ... interfaceList: [] } }
也就是前端本地緩存的數(shù)據(jù)就可以直接導(dǎo)出。
當(dāng)然導(dǎo)出可以把一些信息先過濾處理一遍,比如項(xiàng)目Id ,接口 Id。
于是導(dǎo)出可以為一個(gè)純 Json 文本。
然后倒入時(shí)候需要驗(yàn)證 Json 格式,其實(shí)就是需要做個(gè)遍歷,看看該有的屬性有沒有,沒有的話就報(bào)錯(cuò)不進(jìn)行數(shù)據(jù)導(dǎo)入。
而且導(dǎo)入的時(shí)候需要做個(gè)分類,是導(dǎo)入到項(xiàng)目示例還是個(gè)人/團(tuán)隊(duì)項(xiàng)目。
常見的是打包下載 zip。這個(gè)大概需要后端處理,因此先找找有沒有前端處理的。
搜了一下方案,再結(jié)合 github 上一些項(xiàng)目的源碼,可以簡單的寫出一個(gè)導(dǎo)出模塊
export function exportFile(data: string, filename: string, type: string) { var typeList = { json: "application/json;charset=utf-8", markdown: "text/markdown;charset=utf-8", doc: "application/mswordcharset=utf-8", } // 創(chuàng)建隱藏的可下載鏈接 var eleLink = document.createElement("a"); eleLink.download = filename; eleLink.style.display = "none"; // 字符內(nèi)容轉(zhuǎn)變成blob地址 var blob ; blob= new Blob(["uFEFF" + data],{type: typeList[type]}); eleLink.href = URL.createObjectURL(blob); document.body.appendChild(eleLink); eleLink.click(); document.body.removeChild(eleLink); }
調(diào)用方式很簡單,就是傳入三個(gè)參數(shù):
exportFile(JSON.stringify(this.state.currentProjectData), "default.md", "markdwon")
當(dāng)然我們現(xiàn)在獲得的數(shù)據(jù)是沒有進(jìn)行處理的,我們需要對數(shù)據(jù)做個(gè)過濾,剔除一些關(guān)鍵信息以及沒必要的數(shù)據(jù)。
假設(shè)現(xiàn)在的數(shù)據(jù)是這樣的
{ "_id": "project001", "projectName": "演示項(xiàng)目 - REST接口示例超長字符串測試asd123", "projectUrl": "/project001", "projectDesc": "項(xiàng)目描述", "version": "v1.0", "transferUrl": "http://haoqiao.me/api/project", "status": "transfer", "type": "demo", "teamMember": [ { "_id": "user001", "username": "2333", "role": "前端工程師", "avatar": "https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" }, { "_id": "user002", "username": "宋青樹", "role": "后端工程師", "avatar": "https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" } ], "interfaceList": [ { "_id": "interface001", "interfaceName": "獲取", "url": "/getAll", "method": "get", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface002", "interfaceName": "增加", "url": "/add", "method": "post", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface003", "interfaceName": "刪除", "url": "/delete", "method": "delete", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface004", "interfaceName": "更新", "url": "/update", "method": "put", "desc": "接口描述", "mode": "{data: 1 || 2}" } ] }
我們需要將里面所有的 _id(字段), teamMember(數(shù)組) 去除。這里大家想想如果是自己要怎么處理?
其實(shí)非常簡單,只要你對原生的 JSON.stringify 比較熟悉,你就知道它的完整定義如下
JSON.stringify(value, replacer?, space?)
replacer 是一個(gè)過濾函數(shù)或則一個(gè)數(shù)組包含要被 stringify 的屬性名。如果沒有定義,默認(rèn)所有屬性都被 stringify。
可以做一個(gè)遍歷器,遍歷Json里的屬性名。然后內(nèi)部做個(gè)剔除。
比如這樣
filterData = (json: any) =>{ console.log(json) let expectArr = ["_id", "teamMember"] let filterArr = [] let result = "" for( let key in json){ if (expectArr.indexOf(key) === -1){ filterArr.push(key) } result = JSON.stringify(this.state.currentProjectData, filterArr) console.log(result) return result }
但這樣只能拿到第一層的屬性名,如何拿到嵌套的數(shù)組里的Json的屬性呢?
我們只需要再做個(gè)判斷就可以了
filterData = (json: any) =>{ console.log(json) let expectArr = ["_id", "teamMember"] let filterArr = [] let result = "" for( let key in json){ if (expectArr.indexOf(key) === -1){ filterArr.push(key) // 如果是嵌套數(shù)組,而且數(shù)組內(nèi)有數(shù)據(jù) if(Object.prototype.toString.call(json[key]) == "[object Array]" && json[key].length > 0){ for( let item in json[key][0]){ // 同樣對里面的json數(shù)據(jù)進(jìn)行屬性字段過濾 if (expectArr.indexOf(item) === -1){ filterArr.push(item) } } } } } result = JSON.stringify(this.state.currentProjectData, filterArr) console.log(result) return result }
這樣就把該有的屬性篩選出來了。然后做個(gè)轉(zhuǎn)換就能過濾只剩需要的數(shù)據(jù)。
數(shù)據(jù)清理后就變成如下格式
{ "_id": "project001", "projectName": "演示項(xiàng)目 - REST接口示例超長字符串測試asd123", "projectUrl": "/project001", "projectDesc": "項(xiàng)目描述", "version": "v1.0", "transferUrl": "http://haoqiao.me/api/project", "status": "transfer", "type": "demo", "teamMember": [ { "_id": "user001", "username": "2333", "role": "前端工程師", "avatar": "https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" }, { "_id": "user002", "username": "宋青樹", "role": "后端工程師", "avatar": "https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" } ], "interfaceList": [ { "_id": "interface001", "interfaceName": "獲取", "url": "/getAll", "method": "get", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface002", "interfaceName": "增加", "url": "/add", "method": "post", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface003", "interfaceName": "刪除", "url": "/delete", "method": "delete", "desc": "接口描述", "mode": "{data: 1 || 2}" }, { "_id": "interface004", "interfaceName": "更新", "url": "/update", "method": "put", "desc": "接口描述", "mode": "{data: 1 || 2}" } ] }
之后是要考慮導(dǎo)入項(xiàng)目,我首先想到點(diǎn)擊上傳 JSON 格式文件然后讀取里面的內(nèi)容,然后驗(yàn)證數(shù)據(jù)再讓后臺(tái)將其導(dǎo)入到指定表中。
這里面發(fā)生了一些事情,比如我肯定不希望用戶真的把json文件上傳到服務(wù)器上,我覺得這玩意前端肯定能解析和解決,但是我們肯定還是需要一個(gè)上傳的按鈕和UI交互。
這里我直接用了 antd 的 upload 組件,它里面有個(gè)方法就是 beforeUpload , 只要我們在這個(gè)函數(shù)里直接返回 false 那么是不會(huì)真正觸發(fā)上傳動(dòng)作的,但是我們又可以拿到本地的 File,可以用 HTML5 的新方法 FileReader 來幫助讀取內(nèi)容。
我們的組件可以這么修改
const uploadProps = { name: "file", action: "", showUploadList: false, beforeUpload: (file: any) => { const isJSON = file.type === "application/json"; if (!isJSON) { Message.error("只允許上傳JSON格式文件!"); } const isLt2M = file.size / 1024 / 1024 < 2; if (!isLt2M) { Message.error("JSON文件大小必須小于 2MB!"); } var reader = new FileReader(); // 讀取操作都是由FileReader完成的 var that = this reader.readAsText(file); reader.onload = function(){//讀取完畢從中取值 const json = this.result if(isJson(json) && that.state.uploadJsonData.length === 0){ that.setState({ uploadProject:true, uploadJsonData: json }) Message.success("Json文件上傳識(shí)別成功!"); } } return false; }}, onChange: (info: any) => { }, };
點(diǎn)擊上傳JSON文件或者拖拽上傳JSON文件
來看下實(shí)際的交互效果
這樣我們就打通了項(xiàng)目的導(dǎo)入導(dǎo)出功能的交互。之后就是接口對接一下就行了。
項(xiàng)目克隆 / 接口克隆這兩個(gè)功能其實(shí)很類似,主要是用于幫助用戶能夠復(fù)制已經(jīng)存在的接口或者項(xiàng)目。
比如我已經(jīng)之前建立了一套系統(tǒng)的接口,包括了增刪減改。我下一個(gè)系統(tǒng)和這套系統(tǒng)很類似,可能只需改幾個(gè)字段就可以用了。
我們當(dāng)然可以利用導(dǎo)入和導(dǎo)入功能,但是在系統(tǒng)內(nèi)部我們最好有一鍵遷移的方式,那就是克隆。
克隆我們需要注意,首先是接口克隆,假設(shè)我們接口定義的格式如下:
_id(pin): "interface005" interfaceName(pin): "注冊" url(pin): "/reg" method(pin): "post" desc(pin): "接口描述" mode(pin): "{data: 1 || 2}"
然后我為了方便定義的項(xiàng)目 Model 里面包含了接口 Model。
也就是我只需把 接口 Id,和 項(xiàng)目 Id 傳給后臺(tái),讓后臺(tái)做一個(gè)查詢接口內(nèi)容,然后新建接口把查詢到的內(nèi)容插入到指定 Id 就可以了。
這很簡單。主要部分是 UI 這塊,不過通過對數(shù)據(jù)流的管理也是花時(shí)間就能解決的事情。如下圖:
之后是克隆項(xiàng)目這塊,
我們首先已經(jīng)知道項(xiàng)目 Model 里面包含了 接口 Model,因此我們克隆整個(gè)項(xiàng)目其實(shí)是需要將整個(gè)接口提取出來,團(tuán)隊(duì)成員是需要剔除的,因?yàn)樾驴寺№?xiàng)目應(yīng)該是只有創(chuàng)建者,因此我們需要把 用戶 Id 也從前端傳過去,當(dāng)然也可不傳,通過 Jwt 對 token 解析也能識(shí)別用戶信息。
主要是后端拿到信息之后它的思路應(yīng)該是先查詢這個(gè)項(xiàng)目的信息,然后提取部分信息創(chuàng)建新項(xiàng)目, 然后遍歷原有項(xiàng)目的接口列表,批量創(chuàng)建接口。
個(gè)人信息的更改基本上中后臺(tái)的應(yīng)用都會(huì)有個(gè)人信息管理這項(xiàng),有的用表單,有的拆分。
其余數(shù)據(jù)都好搞定,無非是傳參的問題,前后端約定的問題。
當(dāng)然比較麻煩的其實(shí)是頭像的更改。
假設(shè)你注冊的時(shí)候默認(rèn)分配給一個(gè)用戶頭像,然后再個(gè)人信息里用戶想要更改。
這時(shí)候問題來了。更改頭像其實(shí)是一個(gè)交互問題,你肯定不能讓用戶一步步操作。而是一步到位,符合要求的圖片上傳之后,拿到上傳后的圖片地址。然后更改本地的數(shù)據(jù)。還需要在后臺(tái)自動(dòng)更新數(shù)據(jù)。
這里是用 redux 維護(hù)了一個(gè)本地的前端數(shù)據(jù)層,所有顯示的變更顯示操作需要對其進(jìn)行更新。
然后是 reducer 里監(jiān)聽了動(dòng)作, 定義為 UPDATE_LOCALXXX 的動(dòng)作是用于提交數(shù)據(jù)后等待后臺(tái)處理完畢后返回成功,然后將本地的數(shù)據(jù)進(jìn)行更新。
顯而易見這個(gè)動(dòng)作是異步操作。如果很多個(gè)類似操作需要管理我們代碼寫起來肯定會(huì)很亂。因此我在技術(shù)評估階段引入了 rxjs。
通過其特點(diǎn)時(shí)間線的管理,就很容易了。以下是簡單的示例代碼
export const userUpdate = (action$: any) => action$.ofType(UPDATE_USER) .mergeMap((action: any) => { return fetch.post(updateUser, action.data) // 登錄驗(yàn)證情況 .map((response: any) => { console.log(response); if (response.state.code === 1) { updateUserSuccess(response.state.msg); return updateLocalUser(action.data); } else { console.log("token error") updateUserError(response.state.msg); return nothing(); } }) // 只有服務(wù)器崩潰才捕捉錯(cuò)誤 .catch((e: any): any => { // console.log(e) return Observable.of(({ type: USER_LOGINERROR })).startWith(loadingError()) }) });結(jié)尾
還有一些功能需要等后端開發(fā)的時(shí)候再記錄思路,因此這部分先到這里。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107283.html
摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫函數(shù)庫中高級前端面試手寫代碼無敵秘籍如何用不到行代碼寫一款屬于自己的類庫原理講解實(shí)現(xiàn)一個(gè)對象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...
摘要:前言最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實(shí)用的最終核心思路還是一樣的。 前言 最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的Mock平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互?,F(xiàn)在進(jìn)度推到如何設(shè)計(jì)核心功能,也就是Mock數(shù)據(jù)的解析。 根據(jù)之前的需求設(shè)定加上一些思考...
摘要:前言最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實(shí)用的最終核心思路還是一樣的。 前言 最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的Mock平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互?,F(xiàn)在進(jìn)度推到如何設(shè)計(jì)核心功能,也就是Mock數(shù)據(jù)的解析。 根據(jù)之前的需求設(shè)定加上一些思考...
摘要:前言最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互。核心代碼就是這么一句。經(jīng)過各種猜想和測試,發(fā)現(xiàn)是模擬有問題。其實(shí)用的最終核心思路還是一樣的。 前言 最近一直在搗鼓畢設(shè),準(zhǔn)備做的是一個(gè)基于前后端開發(fā)的Mock平臺(tái),前期花了很多時(shí)間完成了功能模塊的交互?,F(xiàn)在進(jìn)度推到如何設(shè)計(jì)核心功能,也就是Mock數(shù)據(jù)的解析。 根據(jù)之前的需求設(shè)定加上一些思考...
閱讀 2538·2021-07-26 23:38
閱讀 3437·2019-08-30 13:10
閱讀 2324·2019-08-29 18:33
閱讀 2326·2019-08-29 16:12
閱讀 993·2019-08-29 10:59
閱讀 1803·2019-08-26 17:40
閱讀 775·2019-08-26 11:59
閱讀 817·2019-08-26 11:41