以XXX男裝top店與其檔口,供貨商的交流痛點爲出發,解決選款,上架,交流等問題。css
供應鏈APP提報商品 --> 密選供應商編輯併發送到密選 --> 密選選款並直接淘寶天貓上架html
UI框架:react
UI組件庫:Ant Design
HTTP庫:Axios
APP狀態管理:Redux
代碼風格:ESLint Prettier
css預處理:Less
打包工具:webpack前端
七牛圖片上傳:qiniu-js
react添加多個className:classNames
複製功能:clipboard
文件下載保存:file-saver
文件壓縮:jszip
時間處理:moment
......node
淘寶天貓上架:mx-quick-shelfreact
├── /config/ # 配置相關:devServer配置,env多環境的配置,項目文件夾絕對路徑,antd定製主題 ├── /dist/ # 輸出目錄 ├── /public/ # html模板icon文件 ├── /scripts/ # 構建配置 ├── /src/ # 業務邏輯代碼 │ ├── /assets/ # 項目靜態資源文件 │ ├── /common/ # 路由表及頁面組件loader&菜單管理 │ ├── /components/ # UI組件及UI相關方法 │ │ ├── /Authorized/ # 權限組件&權限管理 │ ├── /global/ # 全局狀態管理 │ ├── /layouts/ # 項目佈局組件 │ ├── /pages/ # 項目頁面組件 │ ├── /styles/ # 全局樣式 │ ├── /utils/ # 工具函數 │ ├── App.js # 項目入口組件 │ ├── index.js # 項目入口文件,掛載組件,初始化 │ ├── reducers.js # 合併combine reducers │ └── store.js # compose middlewares & create store ├── .gitignore # git 配置 ├── .babelrc # babel-loader 配置 ├── .eslintrc # Eslint 配置 ├── .prettierrc # Prettierrc 配置 └── package.json # 項目信息
├── /pages/ # 項目頁面組件 │ ├── /Home/ # 首頁 │ │ ├── /components/ # 頁面私有組件 │ │ ├── /view/ # 視圖組件 │ │ │ ├── /index.js # dom與控制 │ │ │ ├── /index.less # 樣式 │ │ ├── /actions.js # reduex action │ │ ├── /actionTypes.js # reduex action type │ │ ├── /index.js # 入口 │ │ ├── /reducer.js # reduex reducer │ │ └── /service.js # http請求
## [3.1.0] - 2019-09-19 ### Added - 淘寶上架 ### Changed - 供應商標題與計劃標題代碼整合 ### Fixed - 搜索調用接口屢次觸發 ### Removed - 刪除圖片放大功能 ### Deprecated - 不建議使用,將來會刪掉 ### Security - 安全相關的bug
在頁面上選擇狀態,選擇子類,刷新頁面保持webpack
// 進入頁面 獲取分銷商分組 componentDidMount() { this.getSendList({ redirect: true }) } // 從新渲染的時候調用,把路由中的值賦值到state static getDerivedStateFromProps(nextProps, prevState) { const { match } = nextProps const { queryType, dayCollectId } = match.params if (prevState.queryType !== Number(queryType)) { return { ...prevState, queryType: Number(queryType || 0) } } if (prevState.dayCollectId !== dayCollectId) { return { ...prevState, dayCollectId: dayCollectId || '' } } return null } // 有值改變的時候執行 async componentDidUpdate(prevProps, prevState) { const { dayCollectId, queryType } = this.state // 從新獲取分銷商分組 if (queryType !== prevState.queryType) { this.getSendList({ redirect: true // 是否重定向 }) } // if (dayCollectId !== prevState.dayCollectId && dayCollectId) { this.setSendInfo({ redirect: false }) this.getSendItemInfo() } } // 獲取分銷商分組 async getSendList(option) { const { pageNum, pageSize, queryType, vagueSearch } = this.state await getSendList({ vagueSearch, pageNum, pageSize, queryType }).then(json => { const { success, data: sendList } = json if (success) { this.setState( { sendList }, () => { this.setSendInfo(option) } ) } }) } // 設置分銷商詳情 setSendInfo(option) { const { history } = this.props const { sendList, queryType, dayCollectId } = this.state option = Object.assign( { redirect: false, resume: true }, option || {} ) if (sendList.length < 1) { return } const existed = sendList.find(item => { return item.id === dayCollectId }) const selectSendItem = option.resume && existed ? existed : sendList[0] this.setState({ spuItem: selectSendItem, sendItemList: [] }) option.redirect && history.replace(`/goods/distributors_sent/${queryType}/${selectSendItem.id}`) } // 獲取分銷商詳情 getSendItemInfo(){ // ... }
// CategoryModal.js <div style={styles.categoryChooseContent}> {categoryData.map((item, index) => ( <div key={item.id} style={styles.categoryItem}> <CategoryItem loading={item.loading} categorys={item.categorys} onChoose={item => { handleCategorChoose(item, index) }} /> </div> ))} // CategoryItem.js function CategoryItem({loading = false, categorys, onChoose }) { const [categorysList, setCategorysList] = useState([]) const [selected, setSelected] = useState('') // 在load之後渲染類目。 useEffect(() => { if (!loading) { setSelected('') setCategorysList(categorys) } else { setCategorysList([]) } }, [loading]) // 選中類目 const handleChoose = item => { setSelected(item.cid) onChoose(item) } // 搜索 const handleChange = e => { const { value } = e.target delay(() => { const filterList = categorys.filter(item => item.name.indexOf(value) >= 0) setCategorysList(filterList) }, 800) } return ( <Spin spinning={loading}> <div style={styles.header}> <Search placeholder="名稱/拼音字母" onChange={handleChange} /> </div> <div style={styles.body}> {categorysList && categorysList.length > 0 && ( <ul> {categorysList.map(item => ( <li key={item.cid} className={item.cid === selected ? 'qs_category_selected' : 'qs_category'} style={styles.category} onClick={() => handleChoose(item)}> <span>{item.name}</span> {item.isParent ? <Icon type="right" style={styles.iconRight} /> : null} </li> ))} </ul> )} </div> </Spin> ) }
➜ [mx-quick-shelf] npm linkios
➜ [secret-goods-pc] npm link mx-quick-shelf 原則上這步就行可是須要:git
➜ [mx-quick-shelf] npm link ../../work/secret-goods-pc/node_modules/react
➜ [mx-quick-shelf] npm link ../../work/secret-goods-pc/node_modules/react-domweb
如今解決辦法webpack alias: { react: utils.resolve('./node_modules/react') }
<Form.Item label={_attributes.name} {...itemLayout} {...extraProps}> {getFieldDecorator(`${_attributes.id}`, { rules: _rules, initialValue: _value, validateFirst: true })( formItemDom() )} </Form.Item>
要實現 內部驗證與外部驗證,最好的方法是 form 嵌套form。剛開始的方法:npm