




下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1章:準
項目-管理系. 管理的 包括前端PC應用和后端應 /// 前端:ReactAntdAxiosES6后端NodeExpressMongodb1.2.其它的界面功能運行其它的界面功能運行final技術選前端路API/接你能從此項目中學到什么流程及開發方法熟悉一個項目的開發流程學會模塊化、組件化、工程化的開發模npmconfigsetregistryyarnconfigsetyarninit-ynpminit- npm掌握使用create-react-app腳手架初始化react學會使用node+express+mongoose+mongodb搭 應1.6.2.React插件或第庫掌握使用react-router-dom開發單頁應學會使用redux+react-redux+redux-thunk掌握使用axios/jsonp與后端進行數據交掌握使用antd學會使用echarts/bizcharts學會使用react-draft-wysiwyg實現富文本編輯1.7.npm/yarnyarn命令文檔/"usernamegitconfigglobal gitinitgitadd //添加gitcommitmmessagegitremoteaddoriginurl//關聯 gitpushoriginmaster//推送本地master分支 gitcheckoutbdevgitpushogigindev//推送本地dev分支 gitpullorigindev// gitcloneurl// yarnadd npminstall ck@3.2.1-yarnaddw ck@3.2.1-Dnpminstallw ck@3.2.1-D yarnglobaladdw npminstallw ck-gyarnremovew npmremovew ck-Syarnglobalremove npmremove ck-yarnrunnpmrunnpminfo1.8.git參考手冊/2章:應用開發詳開啟項目開使用create-react-app(腳手架)搭建項目create-react-app是 提供的用于搭建基于 ck+es6項目的腳手操作npmnpminstall-gcreate-react-app:全 工create-react-appreact-admin cdreact-adminnpmstart:部分同學可能會出現包版本差異的導致異常的問解決:添加.env編碼測試與打包發布項目npm:(live-reload),npmrunnpminstall-gserveservebuild:功能需求分,項目源碼基 設基本結構importimportReact,{Component}from應用根組classAppextends{render()returnreturn)}}exportdefaultimportimportReactfromimportReactDOMfrom'react-importAppfromReactDOM.render(<App 2.3.3..參考文檔組件庫包2.4.3.實現組件的按需打yarnadd 依賴模 constconst{override,fixBabelImports}=require('customize-modulemodule.exportsoverride(fixBabelImports('import',{libraryName:'antd',libraryDirectory:'es',style:'css',修改配置.4.在應用中使用antdimportReact,{Component}from'react'import{Button,message}from'antd'classAppextendsComponenthandleClick=()}render()return')}}"scripts":"start":"react-app-rewiredstart","build":"react-app-rewiredbuild","test":"react-app-rewiredtest","eject":"react-scriptseject"自定antd需求yarnaddyarnaddlessless-const{override,fixBabelImports,const{override,fixBabelImports,addLessLoader}=require('customize-module.exportsoverride(fixBabelImports('import',{libraryName:'antd',libraryDirectory:'es',style:true,javascriptEnabled:modifyVars:{'@primary-color':應用中使用的組件項目中用到的antd組.引入路路由包:react-router-2.5.2.前臺應用路由.3.路由組件用戶登陸的路由組importReact,{Component}fromexportdefaultclassLoginextends{render()return)}}importReact,{Component}importReact,{Component}fromexportdefaultclassAdminextends{render()return)}}路由:importReact,{Component}fromimport{BrowserRouter,Switch,Route}from'react-router-importLoginfrom'./pages/login/login'importAdminfrom應用根組classAppextendsComponentrender()return<Routepath='/login'<Routepath='/')}}exportexportdefault2.6. 組件(不與交互.6.1.靜態組件資——————————————————————————h6margin:padding:}h6font-size:font-weight:}ullist-style:}textarea{margin:}htmlbox-sizing:border-}*,*:before,*:afterbox-sizing:}}{height:auto;max-width:100%;}audiomax-width:}iframeborder:}tableborder-collapse:collapse;border-spacing:0;}thpadding:text-align:}html,bodyheight:}#root注意:index.htmlheight:}width:.loginwidth:height:background-image:url('./images/bg.jpg');background-size:100%100%;{display:flex;align-items:center;height:80px;background-color:rgba(21,20,13,imgwidth:40px;height:40px;margin-left:50px;}h1font-size:30px;color:white;margin:00015px;}}.login-content{margin:50pxauto;width:400px;height:300px;background-color:#fff;padding:20px40px;h3font-size:30px;font-weight:bold;text-align:center;margin-bottom:20px;}.login-form.login-form-buttonwidth:}}}}importimportReact,{Component}from'react'import{}fromimportlogofrom'./images/logo.png'import'./login.less'constItem=登陸classLoginextends{render()return<div<imgsrc={logo} <Inputprefix={<Icontype="user"style={{color: placeholder="用戶名<Inputprefix={<Icontype="lock"style={{color: type="password" .6.2.前臺表單驗證與數據收集用戶名的要求的要必須大于等于4必須小于等于12importReact,{Component}from'react'import{}fromimportlogofrom'./images/logo.png'import'./login.less'constItem=<Buttontype="primary"htmlType="submit"className="login-form-)}}exportdefault——————————————————————————classLoginextendsComponent登login=(e)=> 事件默認行為(不提交表單//進行表單ps.form.validateFields(async(err,values)=>if(!err)校驗成const{username,password}=console.log('提交登陸請求'username}else校驗失}}*自定validator=(rule,value,callback)=>//console.log(rule,constlength=value&&value.lengthconstpwdReg=/^[a-zA-Z0-9_]+$/if(!value)//callback如果不傳參代表校驗成功,如果傳參代表校驗失敗,并且會callback('必須輸 }elseif(length<4){ 必須4位')}elseif(length> }elseif }elsecallback()//必須調用}——————————————————————————}render()const{getFieldDecorator}=ps.formreturn(<div<imgsrc={logo} {將被form組成
getFieldDecorator包裝的表單控件會自動添value和onChange//根據內置驗證規則進 式驗rules:{requiredtruewhitespacetruemessage'必須輸入用戶名{min4message'4位{max12,message'12位{pattern:/^[a-zA-Z0-9_]+$/,message:']<Inputprefix={<Icontype="user"style={{color:'rgba(0,0,0,.25)'}}/>}placeholder="用戶名"/>)}{rules:{validator:]<Icontype="lock" )}<Buttontype="primary"htmlType="submit"className="login-form-)}}用戶名 必須大于4exportdefault說 咱們的項目是一個前分離的項目 前臺應用與應 應用負責處理前臺應用提交的請求 并給前臺應用返回json數前臺應用負責展現數據,與用戶交互,與應用交運行應用確保啟動mongodb服API接口文:登根據分類ID根據ID/Name上刪20)..postman前交互依賴包2.15.2.ajax請求模 能發送ajax請求的函數模塊函數的返回值是promise對象axios.get()/post()返回的就是promise對象返回自己創建的promise對象:異步返回結果數據,而不是包含結果數據的importaxiosfrom'axios'import{message}from'antd'exportdefaultfunctionajax(url,data={},method='GET')returnnewPromise(function(resolve,reject)let//執行異步ajax請if(method==='GET')}elsepromise=axios.post(url,yarnadd}}promise.then(response=>如果成功了調用}).catch(error=>{//對所有ajax請求出錯 message.error('請求錯誤} 2.15.3.配2.15.4.請求測試"proxy": 包含n個接口請求函數的模塊importajaxfrom登exportconstreqLogin=(username,password)=>ajax('/login',{username,////請 login=async(username,password)=>console.log('發送登陸的ajax請求'usernamepassword)constresult=awaitreqLogin(username,password)console.log('login()',result)} 組件(完成登陸功能2.9.1.依..3.importReact,{Component}from'react'import{}fromimportimportlogofromimportmemoryUtilsfrom'../../utils/memoryUtils'import{reqLogin}from'../../api'exportdefaultuser:{}//內存中保存登陸的user信息}yarnadd登陸的路由組classLoginextendsComponenthandleSubmit=(event)=> //對所有表ps.form.validateFields(async(err,values)=>檢驗成if(!err)//console.log('提交登陸的ajax請求',const{username,password}=constresult=awaitreqLogin(username,//console.log('login()',if(result.status===0)提示,保存用戶登memoryUtils.user= 跳轉}else}}elseconsole.log('檢驗失敗}//得到form對//constform=//獲取表單項的輸入數//constvalues=//console.log('handleSubmit()',} ——————————————————————————用戶名 必須必須大于等于4必須小于等于12必須是英文、數字或validatePwd=(rule,value,callback)=>{console.log('validatePwd()',rule,value)if(!value){ 必須輸入}elseif }elseif }elseif(!/^[a-zA-Z0- }elsecallback()驗證} x')//驗證失敗并指定}render()//得到具強大功能的form對constform=const{getFieldDecorator}=return<div<imgsrc={logo} {——————————————————————————用戶名 必須必須大于等于4必須小于等于12必須是英文、數字或}{線組成
getFieldDecorator('username',{//配置對象:屬性名是特定的一 式驗證:直接使用別人定義好的驗證rules:requiredtruewhitespacetruemessage'用戶名必須輸入min4message'4位max12message'12位pattern/^[a-zA-Z0-9_]+$/message' prefix={<Icontype="user"style={{color:'rgba(0,0,0,.25)'}} placeholder="用戶名 )}{rules:{validator:}] prefix={<Icontype="lock"style={{color:'rgba(0,0,0,.25)'}} )}importimportReact,{Component}from'react'import{Redirect}from'react-router-dom'importmemeoryUtilsfromexportdefaultclassAdminextends{render()constuser=memeoryUtils.userif(!user._id){return<Redirect}return o)}}.9.4.<Buttontype="primary"htmlType="submit"className="login-form-)}}constWrapLogin=exportdefault維持登陸與自動登登陸,刷新后依然是已登陸狀態(維持登陸,關閉瀏覽器后打開瀏覽器依然是已登陸狀態(自動登登陸 登陸路徑自動跳轉到管理界importimportstorefromconstUSER_KEY=包含n個操作localstorage的工export{{//localStroage只能保存string,如果傳遞是對象,會自動調用對象的toString()并保//localStorage.setItem(USER_KEY,JSON.stringify(user))//保存的必須是對象的jsonstore.set(USER_KEY,user) 會自動轉換成json再保//returnJSON.parse(localStorage.getItem(USER_KEY)||'{}')//[object,returnstore.get(USER_KEY)||removeUser()//}.10.3.importstorageUtilsfrom'./utils/storageUtils'importmemoryUtilsfrom'./utils/memoryUtils'//如果local中保存了user,將user保存到內存中constuser=storageUtils.getUser()if(user&&user._id){memoryUtils.user=}判斷登錄是if(result.status===0)登錄成 提示登錄成功,保存用戶登錄信message.success('登錄成功保存constuser=resu memoryUtils.user=user//跳轉 管理路由(已經登錄成功,不需要回退了}render()if(memoryUtils.user&&memoryUtils.user._id)return<Redirect}} 組件(搭建整體結構整體組件組成 importReact,{Component}from'react'import'./index.less'左側exportdefaultclassLeftNavextendsComponentrender()return<divclassName="left-nav">.left-navcolor:}))}}Header組 importReact,{Component}from'react'import'./index.less'頭部exportdefaultclassHeaderextendsComponentrender()return<divclassName='header'>)}}.headerheight:}Admin組 importimportReact,{Component}from'react'import{Redirect}from'react-router-dom'import{Layout}fromimportimportmemeoryUtilsfrom'../../utils/memoryUtils'importHeaderfrom' importLeftNavfrom' const{Footer,Sider,Content}=exportdefaultclassAdminextends{render()constuser=memeoryUtils.userif(!user._id){return<Redirect}return<Layoutstyle={{height:<Contentstyle={{backgroundColor:<Footerstyle={{textAlign:'center',color:'#aaaaaa'}}> )}}組定義各個子路由組件路由:importReact,{Component}fromimport{Redirect,Route,Switch}from'react-router-dom'import{Layout}from'antd'importmemeoryUtilsfrom'../../utils/memoryUtils'importHeaderfrom' importLeftNavfrom' importHomefrom'../home/home'importCategoryfrom'../category/category'importProductfrom'../product/product'importRolefrom'../role/role'importUserfrom'../user/user'importBarfrom'../charts/bar'importLinefrom'../charts/line'importPiefrom'../charts/pie'const{Footer,Sider,Content}=exportdefaultclassAdminextends{render()constuser=memeoryUtils.userif(!user._id){return<Redirect}return<Layoutstyle={{height:<Contentstyle={{backgroundColor:<Routepath='/home'<Routepath='/category'<Routepath='/product'<Routepath='/role'<Routepath='/user'<Routepath='/charts/bar'<Routepath='/charts/line'<Routepath='/charts/pie'<Redirectto='/home'<Footerstyle={{textAlign:'center',color:'#aaaaaa'}}> )}}導航菜單配置: {List=title:'首頁',//菜單標題key'/home'對應的icon'home'圖標名{title:'商品',key'/products',iconchildren//{title'品類管理',key:'/category',icon:'bars'{key:'/product',icon:'tool']{title'用戶管理key:'/user',icon:'user'{title'角色管理key:'/role',{titletitle'圖形圖表key:'/charts',children:[{title:'柱形圖',icon:'bar-chart'{title:'折線圖',icon:'line-chart'{title'餅圖icon:'pie-chart']]export.left-nav.logo-linkdisplay:flex;height:80px;background-color:#002140;img{width:height:margin:015px0}h1margin-bottom:color:whitecolor:white;font-size:20px;}}}2.13.3.導航菜單組件:left-importimportReact,{Component}fromimport{Link,withRouter}from'react-router-dom'import{ ,Icon}from'antd'Configfrom importlogofromimportconst = 左側classLeftNavextendsComponent 使用reduce()+遞歸 Nodes= List)=>constpath=List.reduce((pre,item)=>if{ .Item<Link<Icon ——————————————————————————}{ <Icon} if(item.children.find(cItem=>path.indexOf(cItem.key)===0))this.openKey=}}return},} 使用map()+遞歸 Nodes2= List)=>constpath= List.map(item=>if(!item.children)return .Item<Link<Icon—————————————————————————— )}elseif(item.children.find(cItem=>path.indexOf(cItem.key)===0))this.openKey=}return <Icon} )}}在第一次render()之前執行一componentWillMount()// Nodes= Nodes= }render()//得到當前請求路徑,作為選中菜單項的constselectKey=ps.location.pathnameconstopenKey=this.openKeyreturn<divclassName="left-<Linkto='/home'className='logo-<imgsrc={logo}2.142.14Header依 < { } )}}history/location/matchexportdefaultyarnyarnadd2.14.2. importimportjsonpfromexportfunctionreqWeather(city)consturl/returnnewPromise((resolve,reject){jsonp(url,param:},(error,response)=>if(!error&&response.status=='success')const{dayPictureUrl,weather}=response.results[0].weather_data[0]resolve({dayPictureUrl,weather})}elsealert('獲取天氣信息失敗}}2.14.3..headerheight:background-color:.header-topheight:line-height:40px;text-align:right;border-bottom:1pxsolid}}{display:flex;height:40px; font-size:20px;&::after{content:'';top:30px;right:transform:translateX(50%);border-top:20pxsolidwhite;border-right:20pxsolidtransparent;border-bottom:20pxsolidtransparent;border-left:20pxsolidtransparent;}}.header-bottom-rightwidth:text-align:right;img{width:30px;height:20px;margin:015px;}}}}.4.5.抽取通用組件:link-1).2).{border:none;outline:none;color:#1DA57A;cursor:}importReactfrom'react'import'./index.less' 的button組exportdefaultfunctionLinkButton(props)return<button{...props}className='link-}包含nexportfunctionformateDate(time)if(!time)returnletdate=newreturndate.getFullYear()+'-'+(date.getMonth()+1)+'-'++''+date.getHours()+':'+date.getMinutes()+':'+}2.14.6.importimportReact,{Component}from'react'import{Modal}from'antd'import{withRouter}from'react-router-importLinkButtonfrom'../link-button' Listfrom'../../config/ import{reqWeather}from'../../api'import{formateDate}from'../../utils/dateUtils'importmemoryUtilsfrom'../../utils/memoryUtils'importstorageUtilsfrom'../../utils/storageUtils'import'./index.less'頭部classHeaderextendsComponentstate=sysTime:formateDate(Date.now()),dayPictureUrl:'',//天氣 weather:''}發異步ajax獲取天氣數據并更新狀getWeather=async()=>const{dayPictureUrl,weather}=awaitreqWeather(' this.setState({dayP}啟動循環定時器,每隔1s更新一次getSysTime=()=>ervalId=setInterval(()=>sysTime:},}退出logout=()=>{Modal.confirm({content'確定退出嗎?'()=>//移除保存的usermemoryUtils.user={}跳轉到onCancel()}根據請求的path得到對應的標getTitle=(path)=>let enu=> .key===path){title= }elseif {title=}}——————————————————————————return}}componentWillUnmount()清除定}render()const{sysTime,dayPictureUrl,weather}=得到constuser=得到當前constpath=得到對應的標consttitle=return<div<span>歡迎<divclassName="header-<imgsrc={dayPictureUrl})}importimportReactfrom'react'import'./home.less'Home路由組exportdefaultfunctionHome(props)return<div )exportexportdefault.152.15Home.15.1.width:height:100%;display:flex;justify-content:center;font-size:30px;}<Contentstyle={{backgroundColor:'white',margin:'20px20px分類管.16.2.importReact,{Component}from'react'import{}fromimportUpdateFormfrom'./update-//獲取一級或某個二級exportconstreqCategorys=(parentId)=>ajax('/manage/category/list',添加分{},更新exportconstreqUpdateCategory=({categoryId,categoryName})},——————————————————————————importAddFormfrom'./add-importLinkButtonfrom ponents/link-import{reqCategorys,reqAddCategory,reqUpdateCategory}fromexportdefaultclassCategoryextendsComponentstate=categorys:[],//一級分類列表subCategorys:[],//二級分類列表parentId:'0',//父分類的IDparentName:'',//父分類的名稱示 示}getCategorys=async(parentId)=>g:trueparentId=parentId||constresult=awaitreqCategorys(parentId)//{status:0,data:g:falseif(result.status==={constcategorys ataif(parentId'0')——————————————————————————}elses:categorys}}elsemessage.error('獲取列表失敗}}showSubCates=(category)=>//console.log('set之前',this.state.parentId)//this.setState({:parentName: //console.log('set之后',this.state.parentId)}showCategorys=()=>tId:'0',parentName:'',showStatus:0,} ——————————————————————————showAdd=()({1} showUpdate=(category)=>this.category=s:2}addCategory=async()=>const{parentId,categoryName}= s:0constresult=awaitreqAddCategory(categoryName,if(result.status===0)if(parentId===this.state.parentId)}elseif(parentId==='0')——————————————————————————}}}updateCategory=async()=>constcategoryId=const{categoryName}= 0constresult=awaitreqUpdateCategory({categoryId,if(result.status===0)}}componentWillMount()this.columns={title'分類名稱',dataIndex:{width:300,render:(category)=><LinkButtononClick={()=>this.showUpdate(category)}>修改分 ——————————————————————————{this.state.parentId==='0'<LinkButtononClick={()=>this.showSubCates(category)}>查看子分類</LinkButton>:)}componentDidMount()}render()const{categorys,subCategorys,parentId,parentName,loading,showStatus}=constcategory=this.category||consttitleparentId'0'一級分類列表<LinkButtononClick={this.showCategorys}>一級分類列表</LinkButton> <Icontype='arrow- )constextra=<Buttontype='primary'<Icontype='plus'/>添)return<Cardtitle={title} dataSource={parentId==='0'?categorys: pagination={{pageSize:5,showQuickJumper:true,showSizeChanger: ———————————————————————————————————————————————————— title="添加分類 visible={showStatus=== onCancel={()=>this.setState({showStatus: setForm={form=>this.form= title="修改分類 visible={showStatus=== onCancel={()=>this.setState({showStatus: setForm={form=>this.form= )}}importimportReact,{Component}from'react'import{Form,Select,Input}from'antd'importPropTypesfrom'prop-——————————————————————————constItem=constOption=添加分類的Form組classAddFormextendsComponentstaticpropTypes=categorys:PropTypes.array.isRequired,parentId:PropTypes.string.isRequired,setForm:PropTypes.func.isRequired,}componentWillMount()}render()const{getFieldDecorator}=ps.formconst{categorys,parentId}=psreturn(<Itemlabel='所屬分類{initialValue:<Optionkey='0'value='0'>一級分類{categorys.map(c=><Optionkey={c._id}})}<Itemlabel='分類名稱)}}exportdefaultAddForm=importReact,{Component}from'react'import{Form,Input}from'antd'importPropTypesfrom'prop-types'constItem=更新分類的Form組classUpdateFormextendsComponentstaticpropTypes=categoryName:setForm:}componentWillMount()}render(){initialValue:)}initialValue:initialValue:<Input )})}}2.17.商2.17.商品管依2.17.2.const{getFieldDecorator}=ps.formconst{categoryName}=psreturn{exportdefaultUpdateForm=根據分類ID獲取獲取商品分//根據ID/Name搜索產品分頁列exportconstreqAddOrUpdateProduct=(product)=>ajax('/manage/product/'(product._id?'update':'add'),product,exportconstreqUpdateProductStatus=(productId,status){productId,},.17.3.importReact,{Component}fromimport{Switch,Route,Redirect}from'react-router-importProductHomefromimportProductAddUpdatefrom'./add-update'importProductDetailfrom'./detail'import管理的商品管理路由exportdefaultclassProductextends{render()return<Routepath='/product'exactexportconstreqSearchProducts=({pageNum,pageSize,searchType,searchName}){pageNum,[searchType]:exportconstreqDeleteImg=(name)=>ajax('/manage/img/delete',{name},<Route<Routepath='/product/addupdate'<Routepath='/product/detail'<Redirect)}}importimportReact,{Component}fromimport{}fromimportLinkButtonfromimport{reqProducts,reqSearchProducts,reqUpdateProductStatus}fromimport{PAGE_SIZE}fromconstOption=exportdefaultclassProductHomeextendsComponentstate=total0商品的總products當前頁列表數searchType'productName'搜索類型productNamesearchName'',//}2.17.4.——————————————————————————更新指定產品的狀updateProductStatus=async(productId,status)=>constresult=awaitreqUpdateProductStatus(productId,if(result.status===}}initColumns=()=>this.columns={dataIndex{dataIndex{title:'價格',render:(price)=>{title:'狀態',width:100,dataIndex'status',renderstatusproduct1:在售2:letb ext='下架'letstatusText'在售'if(status==={ ext'上架statusText'已下架}——————————————————————————status=status===1?2:return<Buttontype='primary'onClick={() )}{width:100,render:(product)=><LinkButtononClick=ps.history.push('/product/detail', <LinkButtononClick=ps.history.push('/product/addupdate',)]}getProducts=async(pageNum)=>this.pageNum=const{searchType,searchName}=this.stateletresultresult=awaitreqSearchProducts({pageNum,pageSize:PAGE_SIZE,searchType,else一般result=awaitreqProducts(pageNum,}——————————————————————————if(result.status===0)const{total,list}=resu products:}}componentWillMount()}componentDidMount()}render()const{products,total,searchType}=this.stateconsttitle=(<Selectvalue={searchType}onChange={value=>this.setState({searchType:關鍵字
''<Inputstyle={{width:150,marginLeft:10,marginRight:10}} onChange={(e)=>this.setState({searchName: <Buttontype='primaryonClick=this.getProducts(1)}>搜索)constextra=<Buttontype='primary'style={{float:'right'}}onClick={()<Icon)defaultPageSize:onChange:)}}.17.5.importReact,{Component}from'react'import{List,Icon,Card}from'antd'import{reqCategory}fromimport{BASE_IMG_PATH}from'../../utils/constants'importLinkButtonfrom" 商品exportdefaultclassProductDetailextendsComponentstate=,return<Cardtitle={title} ——————————————————————————cName2二級分類名}getCategoryName=async()=>const{categoryId,pCategoryId}=ps.location.stateif(pCategoryId==='0'){獲取一級分constresult=awaitreqCategory(categoryId)constcName1=resu }else獲取一級分/*constresult1=awaitreqCategory(pCategoryId)constcName1=獲取二級分constresult2=awaitreqCategory(categoryId)constcName2=this.setState({cName1,cName2})*/一次發多個請求,等所有請求都返回后一起處理,如果有一個請求出錯了,Promise.all([promise1,promise2])返回值一個promise對象,異步成功返[result1,constresults=awaitconstresult1=constresult2=constcName1=constcName2=this.setState({cName1,cName2})}}componentDidMount()}render()——————————————————————————const{name,desc,price,imgs,detail}=const{cName1,cName2}=this.stateconsttitle=(<LinkButtononClick={()=><Icontype="arrow-left"style={{fontSize: )return<CardclassName='product-detail'<span>{price'元<span>{cName1+(cName2?'-->'+cName2:<spanclassName='left'>商 {imgs.map(img=>}<divdangerouslySetInnerHTML={{html:)}}product/add-importReact,{Component}from'react'import{}fromimportLinkButtonfrom' importPicturesWallfrom'./pictures-wall'importRichTextEditorfrom'./rich-text-import{reqCategorys,reqAddOrUpdateProduct}fromconst{Item}=const{TextArea}=商品添加/更新的路由組classProductAddUpdateextendsComponentstate=options:[],//用來顯}constructor(props)this.pw=this.editor=}loadData=async(selectedOptions)=>//console.log('loadDate()', OptionselectedOptions[selectedOptions.length1]Option.loading=true//顯示loading——————————————————————————//異步請求獲取對constsubCategorys=awaitthis.getCategorys( constcOptions=subCategorys.map(c=>value:c._id,label:,isLeaf:true,//添加為對應的option的children(子Option.children=Option.isLeaf=}//更新options狀options:}獲取指定分類id的子分類列如果parentId為0時獲取一級列getCategorys=async(parentId)=>constresult=awaitif(result.status===0)constcategorys=resu if(parentId==='0'){//根據一級分類數組初始化生成options數}else{當前得到是二級分類列return}}——————————————————————————}生成級聯的一級列initOptions=async(categorys)=>//根據一級分類數組生成option的數constoptions=categorys.map(c=>value:c._id,label:,isLeaf://如果當前是更新,且商品是一個二級分類的const{product,isUpdate}=thisif(isUpdate&&product.pCategoryId!=='0'){//異步獲取product.pCategoryId的二級分類列constsubCategorys=awaitthis.getCategorys(product.pCategoryId)if(subCategorys&&subCategorys.length>0){//生成二級的option數constcOptions=subCategorys.map(c=>value:c._id,isLeaf:true,找到對應的 //將cOptions添加為對應的一級option的Option.children=}}更新狀}——————————————————————————對商品價格進行自定義驗validatePrice=(rule,value,callback){value=value*{}elsecallback('價格必須是大于0的數值}}submit=()=>ps.form.validateFields(async(err,values)=>if(!err)收集產品相const{name,desc,price,categoryIds}=//在父組件中得到子組件對象,調用子組constimgs=constdetail=letpCategoryId=''letcategoryId=''if(categoryIds.length===1){//選擇的是一級分pCategoryId=categoryId=}else{//選擇的是二級分類pCategoryIdcategoryIds[0]categoryId=categoryIds[1]}封裝成constproduct={name,desc,price,pCategoryId,categoryId,detail,if(this.isUpdate)product._id=}請求保constresult=await}else——————————————————————————message.success('保存商品失敗}}}componentDidMount()}componentWillMount()取出跳轉constproduct=ps.location.stateduct=product||{}this.isUpdate }render()const{product,isUpdate}=const{pCategoryId,categoryId}=productconst{options}=this.stateconst{getFieldDecorator}=//準備用于級聯列表顯示的數組constcategoryIds=[]if(isUpdate){{)}}consttitle=<LinkButtononClick={()=><Icontype='arrow-left'style={{fontSize:——————————————————————————{isUpdate'修改商品'添加商品)//指定form的item布局的constformItemLayout{labelCol:{span:2wrapperCol:{span:8}return<Card<Itemlabel="商品名稱{{initialValue:,rules:[{requiredtruemessage'商品名稱必須輸入])}<Itemlabel="商品描述{{initialValue:product.desc,rules:[{requiredtruemessage'商品描述必須輸入]<TextAreaplaceholder="請輸入商品描述autosize)}<Itemlabel="商品價格{{initialValue:product.price,rules:[{requiredtruemessage'商品價格必須輸入{validator:]'')}<Itemlabel="商品分類{{initialValue:rules:{requiredtruemessage'商品分類必須輸入] )}<Itemlabel="商 "<PicturesWallref={this.pw} label="商品詳情 labelCol={{span:2 wrapperCol={{span:20<RichTextEditorref={this.editor}')}}exportdefaultproduct/pictures-importimportReactfromimportPropTypesfrom'prop-import{Upload,Icon,Modal,message}fromimport{BASE_IMG_PATH,UPLOAD_IMG_NAME}fromimport{reqDeleteImg}from)exportdefaultclassPicturesWallponentstaticpropTypes=imgs:}constructor(props)letfileList=如果傳入了imgs,生成一個對應的constimgs=ps.imgsif(imgs&&imgs.length>0){fileList=imgs.map((img,index)=>uid:-name:status'done'loading上傳中done:上傳完成remove刪url:BASE_IMG_PATH+}this.state=previewVisible:false,//是否顯示大圖預previewImage:'',//大圖的fileList:fileList//所有需要顯示 }} 文件名的數getImgs=()=>this.state.fileList.map(file=>關閉handleCancel=()=>this.setState({previewVisible:預覽handlePreview=(file)=>previewVisible:}file:當前操fileList:所有文件信息對象的數handleChange=async({file,fileList})=>console.log('handleChange()',file,//如果上 if(file.status==={constresult=file.responseif(result.status===0){message.success('上傳成功了const{name,url}=resu file=fileList[fileList.length-1]file.url=url}elsemessage.error('上傳失敗了}elseif(file.status'removed'刪除constresult=awaitreqDeleteImg()if(result.status===0){message.success('刪 成功}}elsemessage.error('刪 失敗}}//更新fileList}render()const{previewVisible,previewImage,fileList}=constuploadButton=<Icon )return name= <Modalvisible={previewVisible}footer={null}<imgalt="example"style={{width:'100%'}})}}product/rich-text-importimportReact,{Component}from'react'importPropTypesfrom'prop-types'import{Editor}from'react-draft-import{EditorState,convertToRaw,ContentState}from'draft-js'importdraftToHtmlfrom'draftjs-to-html'importhtmlToDraftfrom'html-to-用來指定商品詳情信exportdefaultclassRichTextEditorextendsComponentstaticpropTypes=detail:}constructor(props)//根據傳入的html文本初始顯示ps.detailleteditorStateif(detail){//如果傳入才需要constblocksFromHtml=const{contentBlocks,entityMap}=editorState=EditorState.createWithContent(contentState)}elseeditorState=}初始化{editorStat}}當輸入改變時立即保.17.9..product-detail.leftfont-size:18px;font-weight:bold;}}onEditorStateChange=(editorState)=>}getDetail=()=>return}render()const{editorState}=return editorStyle={{height:250,border:'1pxsolid#000',padding:'0 )}}2.17.10.包包含n個應用中的常量字符串exportconstUPLOAD_IMG_NAME'image上'//上傳 的參importReact,ponent}fromimportPropTypesfrom'prop-{Form,}from2.18.角色管2.18.1.添加角exportconstreqAddRole=(roleName)=>ajax('/manage/role/add',{roleName},獲取exportconstreqRoles=()=>exportconstreqUpdateRole=(role)=>ajax('/manage/role/update',role,classclassAddFormponentstaticpropTypes=setForm:}componentWillMount()}render()const{getFieldDecorator}=ps.formconstformItemLayout={labelCol:{span:wrapperCol:{span:}return<Form.Itemlabel="角色名稱{initialValue:)})}}exportdefaultAddForm=importimportReact,ponent}fromimportPropTypesfrom'prop-import——————————————————————————}from Listfrom'../../config/ constItem=Form.Itemconst{TreeNode}=添加分類的form組exportdefaultclassAuthForm ponentstaticpropTypes=role:}constructor(props)//根據傳入角色的 s生成初始狀態const{ s}=ps.rolethis.state={ }} s數據的方 s=()=>getTreeNodes= List)=> List.reduce((pre,item){<TreeNodetitl
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 綿陽師范學院《臨床醫學工程技術》2023-2024學年第二學期期末試卷
- 上海市高境第一中學2024-2025學年高三第二次綜合考試試題含解析
- 四川民族學院《機器人學》2023-2024學年第二學期期末試卷
- 許昌學院《醫學科學研究導論》2023-2024學年第二學期期末試卷
- 宣化科技職業學院《新媒體藝術傳播》2023-2024學年第二學期期末試卷
- 四川工業科技學院《結構疲勞與斷裂力學》2023-2024學年第一學期期末試卷
- 邢臺學院《醫學人文導論》2023-2024學年第一學期期末試卷
- 山東省德州市齊河縣一中2025年高三教學測試(二)英語試題含解析
- 嘉應學院《創新方法與實踐(以競賽導向的信息技術創新實踐)》2023-2024學年第二學期期末試卷
- 石家莊二手房房屋買賣合同二零二五年
- 復旦大學附屬眼耳鼻喉醫院耳鼻喉進修匯報
- DB33-1036-2021《公共建筑節能設計標準》
- 巖芯鑒定手冊
- 快速排序算法高校試講PPT
- 甘肅歷史與甘肅文化
- 工程勘察設計收費標準
- 高邊坡施工危險源辨識及分析
- 江蘇工業企業較大以上風險目錄
- 《村衛生室管理辦法(試行)》課件(PPT 49頁)
- 監理質量評估報告(主體分部)
- 鍋爐爆炸事故演練方案(模板)
評論
0/150
提交評論