├── src ├── auth │ ├── index.js │ └── authConfig.js ├── views │ ├── mainContent │ │ ├── personal │ │ │ ├── index.scss │ │ │ ├── index.js │ │ │ └── percentageEcharts.js │ │ ├── storeManage │ │ │ ├── list │ │ │ │ ├── listNew │ │ │ │ │ └── index.scss │ │ │ │ ├── index.scss │ │ │ │ ├── listDetailInfo │ │ │ │ │ ├── index.js │ │ │ │ │ └── data.js │ │ │ │ └── data.js │ │ │ ├── index.js │ │ │ └── echarts │ │ │ │ ├── newStoreEcharts.js │ │ │ │ └── storeRankEcharts.js │ │ ├── userManage │ │ │ ├── list │ │ │ │ ├── listNew │ │ │ │ │ └── index.scss │ │ │ │ ├── index.scss │ │ │ │ ├── data.js │ │ │ │ └── listDetailInfo │ │ │ │ │ ├── index.js │ │ │ │ │ └── data.js │ │ │ ├── adminList │ │ │ │ ├── listNew │ │ │ │ │ ├── index.scss │ │ │ │ │ ├── data.js │ │ │ │ │ └── index.js │ │ │ │ ├── index.scss │ │ │ │ ├── data.js │ │ │ │ └── listDetailInfo │ │ │ │ │ ├── data.js │ │ │ │ │ └── index.js │ │ │ ├── grade │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ ├── member │ │ │ │ └── index.js │ │ │ └── echarts │ │ │ │ └── index.js │ │ ├── goodsManage │ │ │ ├── goodsList │ │ │ │ ├── listNew │ │ │ │ │ ├── index.scss │ │ │ │ │ ├── data.js │ │ │ │ │ └── index.js │ │ │ │ ├── index.scss │ │ │ │ ├── listDetailInfo │ │ │ │ │ ├── index.js │ │ │ │ │ └── data.js │ │ │ │ └── data.js │ │ │ └── index.js │ │ ├── home │ │ │ ├── baseMap │ │ │ │ ├── index.scss │ │ │ │ ├── markerContent │ │ │ │ │ ├── index.js │ │ │ │ │ ├── markerContent.scss │ │ │ │ │ └── markerContent.js │ │ │ │ └── index.js │ │ │ ├── index.scss │ │ │ ├── data.js │ │ │ └── index.js │ │ ├── authManage │ │ │ ├── index.js │ │ │ └── roleList │ │ │ │ ├── index.scss │ │ │ │ └── data.js │ │ ├── historyRecord │ │ │ ├── index.js │ │ │ ├── deleteUserList │ │ │ │ ├── index.scss │ │ │ │ └── data.js │ │ │ └── deleteAdminUserList │ │ │ │ ├── index.scss │ │ │ │ └── data.js │ │ ├── index.scss │ │ └── index.js │ ├── App.scss │ ├── header │ │ ├── data.js │ │ └── index.scss │ ├── login │ │ ├── index.scss │ │ └── index.js │ ├── App.js │ └── leftNav │ │ └── index.scss ├── components │ ├── CEcharts │ │ ├── index.scss │ │ └── index.js │ ├── CBreadcrumb │ │ ├── index.scss │ │ └── index.js │ ├── CPage │ │ ├── index.scss │ │ └── index.js │ ├── CDetailInfo │ │ ├── detailInfoTitle.js │ │ ├── index.js │ │ ├── index.scss │ │ └── detailInfoItem.js │ ├── CBaseComponent │ │ └── index.js │ ├── CAvatar │ │ ├── index.scss │ │ └── index.js │ ├── CPageNew │ │ └── index.scss │ ├── CSwiper │ │ ├── index.scss │ │ └── index.js │ ├── CForm │ │ ├── CCheckbox.js │ │ ├── CSwitch.js │ │ ├── CRadio.js │ │ ├── index.scss │ │ ├── CSelect.js │ │ ├── CDatePicker.js │ │ ├── validate.js │ │ └── CInput.js │ ├── CScroll │ │ └── index.jsx │ ├── CButton │ │ ├── index.js │ │ └── index.scss │ └── CTable │ │ ├── index.scss │ │ ├── filterHead.js │ │ └── tableFilter.js ├── assets │ ├── images │ │ ├── login-bg.jpg │ │ ├── map-marker.png │ │ └── projectShot │ │ │ ├── home.jpg │ │ │ ├── login.jpg │ │ │ ├── theme1.jpg │ │ │ ├── goodsManage1.jpg │ │ │ ├── roleManage1.jpg │ │ │ ├── storeManage1.jpg │ │ │ ├── storeManage2.jpg │ │ │ ├── userManage1.png │ │ │ ├── userManage2.jpg │ │ │ ├── userManage3.jpg │ │ │ ├── userManage4.png │ │ │ ├── userManage5.jpg │ │ │ └── historyRecord1.jpg │ └── css │ │ ├── antdReset.scss │ │ ├── common.scss │ │ └── var.scss ├── routers │ ├── homeRouter.js │ ├── personalRouter.js │ ├── authManageRouter.js │ ├── historyRecordRouter.js │ ├── goodsManageRouter.js │ ├── storeManageRouter.js │ ├── userManageRouter.js │ └── index.js ├── servers │ ├── homeApi.js │ ├── authManageApi.js │ ├── goodsManageApi.js │ ├── historyRecordApi.js │ ├── storeManageApi.js │ ├── userManageApi.js │ ├── commonApi.js │ └── index.js ├── redux │ ├── index.js │ └── common │ │ ├── action-type.js │ │ ├── action.js │ │ └── reducer.js ├── config │ └── index.js ├── mock │ ├── authManage │ │ ├── index.js │ │ └── roleList.js │ ├── statistics │ │ ├── index.js │ │ ├── userApiList.js │ │ └── storeApiList.js │ ├── commonSchema.js │ ├── index.js │ ├── createMockData.js │ ├── goodsManage │ │ ├── index.js │ │ └── schema.js │ ├── storeManage │ │ ├── index.js │ │ └── schema.js │ ├── login │ │ └── index.js │ ├── common │ │ └── index.js │ └── userManage │ │ ├── index.js │ │ └── schema.js ├── index.js └── logo.svg ├── public ├── favicon.ico ├── manifest.json └── index.html ├── config ├── jest │ ├── cssTransform.js │ └── fileTransform.js ├── utils.js ├── pnpTs.js ├── modules.js ├── paths.js └── env.js ├── .gitignore ├── scripts └── test.js └── README.md /src/auth/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/mainContent/personal/index.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/CEcharts/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .c-echarts{ 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/list/listNew/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .store-manage-list-new{ 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/list/listNew/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list-new{ 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/listNew/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .store-manage-list-new{ 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/listNew/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list-new{ 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/images/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/login-bg.jpg -------------------------------------------------------------------------------- /src/components/CBreadcrumb/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .c-breadcrumb{ 3 | width: 100%; 4 | justify-content: space-between; 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/images/map-marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/map-marker.png -------------------------------------------------------------------------------- /src/auth/authConfig.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const userRoleList = []; 4 | 5 | // 权限配置 6 | export const authConfig = [ 7 | 8 | ]; 9 | -------------------------------------------------------------------------------- /src/assets/images/projectShot/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/home.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/login.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/login.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/theme1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/theme1.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/goodsManage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/goodsManage1.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/roleManage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/roleManage1.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/storeManage1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/storeManage1.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/storeManage2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/storeManage2.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/userManage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/userManage1.png -------------------------------------------------------------------------------- /src/assets/images/projectShot/userManage2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/userManage2.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/userManage3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/userManage3.jpg -------------------------------------------------------------------------------- /src/assets/images/projectShot/userManage4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/userManage4.png -------------------------------------------------------------------------------- /src/assets/images/projectShot/userManage5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/userManage5.jpg -------------------------------------------------------------------------------- /src/views/mainContent/home/baseMap/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .base-map{ 3 | width: 100%; 4 | height: 400px; 5 | } 6 | 7 | .marker-content{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/images/projectShot/historyRecord1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengllNice/react-store-admin/HEAD/src/assets/images/projectShot/historyRecord1.jpg -------------------------------------------------------------------------------- /src/routers/homeRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import Home from '@/views/mainContent/home' 3 | 4 | export default { 5 | path: '/home', 6 | component: Home, 7 | exact: true 8 | } 9 | -------------------------------------------------------------------------------- /src/servers/homeApi.js: -------------------------------------------------------------------------------- 1 | import {ajax_get} from "./index"; 2 | 3 | // 获取所有商铺列表 4 | export const getStoreAllList = (data) => ajax_get('/fe/storeManage/storeAllList/get/', data); 5 | -------------------------------------------------------------------------------- /src/routers/personalRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import personal from '@/views/mainContent/personal' 3 | 4 | export default { 5 | path: '/personal', 6 | component: personal, 7 | exact: true, 8 | } 9 | -------------------------------------------------------------------------------- /src/assets/css/antdReset.scss: -------------------------------------------------------------------------------- 1 | 2 | .ant-message-notice-content{ 3 | padding: 4px 10px!important; 4 | border-radius: 2px!important; 5 | font-size: 13px; 6 | } 7 | .ant-message .anticon{ 8 | font-size: 14px!important; 9 | } 10 | -------------------------------------------------------------------------------- /src/views/mainContent/authManage/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class AuthManage extends Component{ 4 | render(){ 5 | 6 | return ( 7 |
{this.props.children}
8 | ) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class GoodsManage extends Component{ 4 | render(){ 5 | 6 | return ( 7 |
{this.props.children}
8 | ) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/mainContent/historyRecord/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class HistoryRecord extends Component{ 4 | render(){ 5 | return ( 6 |
{this.props.children}
7 | ) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class StoreManage extends Component{ 4 | render(){ 5 | 6 | return ( 7 |
{this.props.children}
8 | ) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/grade/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class UserManageGrade extends Component{ 4 | render(){ 5 | return ( 6 |
UserManageGrade
7 | ) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class UserManage extends Component{ 4 | render(){ 5 | 6 | return ( 7 |
{this.props.children}
8 | ) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/member/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | 3 | export default class UserManageMember extends Component{ 4 | render(){ 5 | return ( 6 |
UserManageMember
7 | ) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/views/mainContent/home/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .home{ 3 | .home-filter{ 4 | justify-content: flex-end; 5 | margin-bottom: 20px; 6 | .search-input{ 7 | width: 200px; 8 | } 9 | } 10 | .home-base-map{ 11 | border: 1px solid #eeeeee; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/CPage/index.scss: -------------------------------------------------------------------------------- 1 | @import "@/assets/css/var.scss"; 2 | .c-page{ 3 | margin: 10px 0; 4 | .ant-pagination-item-active{ 5 | background-color: $main-base-primary-color; 6 | border-radius: 2px; 7 | a{ 8 | color: $text-color-white!important; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/redux/index.js: -------------------------------------------------------------------------------- 1 | import {createStore, combineReducers, applyMiddleware} from 'redux'; 2 | 3 | import Common from './common/reducer' 4 | 5 | import thunk from 'redux-thunk'; 6 | 7 | const store = createStore( 8 | combineReducers({Common}), 9 | applyMiddleware(thunk) 10 | ); 11 | 12 | export default store; 13 | -------------------------------------------------------------------------------- /src/views/App.scss: -------------------------------------------------------------------------------- 1 | @import "@/assets/css/var.scss"; 2 | .app{ 3 | background-color: $main-background-color; 4 | height: 100%; 5 | .app-content{ 6 | height: calc(100% - 45px); 7 | align-items: start; 8 | .app-mainContent{ 9 | flex: 1; 10 | height: 100%; 11 | overflow: auto; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/views/header/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const menuList = [ 3 | { 4 | id: 'personal', 5 | path: '/personal', 6 | name: '个人信息', 7 | }, 8 | { 9 | id: 'changeAccount', 10 | path: '/changeAccount', 11 | name: '切换账号', 12 | }, 13 | { 14 | id: 'loginOut', 15 | path: '/loginOut', 16 | name: '退出', 17 | } 18 | ]; 19 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | name: 'X-Admin',//项目名称 4 | leftNavdefaultOpenAll: false,//是否默认展开所有侧导航自导航 true展开 false不展开(会展开当前路由所在的一级菜单) 5 | CollapseModel: true,//侧导航切换的模式 true为手风琴模式 默认false 6 | collapsedDefaultOpen: false,//默认是否展开侧导航 true展开 false收起 7 | 8 | mock: true,//是否使用mock数据, 如果是生产环境此项配置不生效(暂无真实接口支持,只能用mock数据接口) 9 | }; 10 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/echarts/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CBaseComponent from '@/components/CBaseComponent' 3 | 4 | @CBaseComponent 5 | class UserManageEcharts extends Component{ 6 | render(){ 7 | return ( 8 |
UserManageEcharts
9 | ) 10 | } 11 | } 12 | 13 | export default UserManageEcharts 14 | -------------------------------------------------------------------------------- /src/servers/authManageApi.js: -------------------------------------------------------------------------------- 1 | import { ajax_post} from "./index"; 2 | 3 | // 删除角色 4 | export const delRoleList = (data) => ajax_post('/fe/authManage/roleList/delete/', data); 5 | // 新增角色 6 | export const insertRoleList = (data) => ajax_post('/fe/authManage/roleList/insert/', data); 7 | // 编辑角色 8 | export const editRoleList = (data) => ajax_post('/fe/authManage/roleList/edit/', data); 9 | -------------------------------------------------------------------------------- /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": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/list/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/list/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/redux/common/action-type.js: -------------------------------------------------------------------------------- 1 | 2 | // 登录用户信息 3 | export const USERINFO = 'USERINFO'; 4 | // 左侧导航切换 5 | export const COLLAPSEDTOGGLE = 'COLLAPSEDTOGGLE'; 6 | // 设置面包屑导航数据 7 | export const SETBREADCRUMB = 'SETBREADCRUMB'; 8 | // 面包屑导航右侧reload的标志 9 | export const RELOAD = 'RELOAD'; 10 | // 浏览器信息(宽度、高度等) 11 | export const WINDOWINFO = 'WINDOWINFO'; 12 | // 切换主题 13 | export const CURRENTTHEME = 'CURRENTTHEME'; 14 | -------------------------------------------------------------------------------- /src/views/mainContent/authManage/roleList/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .auth-manage-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .user-manage-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/routers/authManageRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import authManage from '@/views/mainContent/authManage' 3 | 4 | import authManageRole from '@/views/mainContent/authManage/roleList' 5 | 6 | export default { 7 | path: '/authManage', 8 | component: authManage, 9 | exact: true, 10 | children: [ 11 | { 12 | path: '/authManage/role', 13 | component: authManageRole, 14 | exact: true, 15 | }, 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/views/mainContent/historyRecord/deleteUserList/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .history-record-delete-user-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/views/mainContent/historyRecord/deleteAdminUserList/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .history-record-delete-user-list{ 3 | .filter-wrap{ 4 | justify-content: space-between; 5 | .filter-left{ 6 | justify-content: start; 7 | &>*{ 8 | margin-right: 5px; 9 | } 10 | } 11 | .filter-right{ 12 | justify-content: end; 13 | &>*{ 14 | margin-left: 5px; 15 | } 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.idea 6 | .idea 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /src/mock/authManage/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import { formatURL} from '../index' 3 | 4 | // 权限管理角色 5 | import { 6 | deleteAuthManageRole, 7 | insertAuthManageRole, 8 | editStoreManage,} from "./roleList"; 9 | 10 | // 删除角色 11 | Mock.mock(formatURL('/authManage/roleList/delete'), 'post', deleteAuthManageRole); 12 | // 新建角色 13 | Mock.mock(formatURL('/authManage/roleList/insert'), 'post', insertAuthManageRole); 14 | // 编辑角色 15 | Mock.mock(formatURL('/authManage/roleList/edit'), 'post', editStoreManage); 16 | 17 | -------------------------------------------------------------------------------- /config/utils.js: -------------------------------------------------------------------------------- 1 | var childProcess = require('child_process'); 2 | 3 | const exec = (command) => { 4 | return new Promise(function(resolve, reject) { 5 | let cmd = childProcess.exec(command, {maxBuffer: 50000 * 1024}, function(err, stdout) { 6 | if (err) { 7 | reject(err); 8 | } else { 9 | resolve(stdout); 10 | } 11 | }); 12 | cmd.stdout.pipe(process.stdout); 13 | cmd.stderr.pipe(process.stderr); 14 | }) 15 | }; 16 | 17 | module.exports = { 18 | exec 19 | }; -------------------------------------------------------------------------------- /src/mock/statistics/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import { formatURL} from '../index' 3 | 4 | import { 5 | getStatisticsStoreByCategory, 6 | getStatisticsNewStore, 7 | getStatisticsStoreRank} from "./storeApiList"; 8 | 9 | /*店铺按分类统计数量*/ 10 | Mock.mock(formatURL('/statistics/store/category/get'), 'get', getStatisticsStoreByCategory); 11 | /*新增店铺数量统计*/ 12 | Mock.mock(formatURL('/statistics/store/new/get'), 'get', getStatisticsNewStore); 13 | /*店铺排行榜(信誉、售后、星级)*/ 14 | Mock.mock(formatURL('/statistics/store/rank/get'), 'get', getStatisticsStoreRank); 15 | 16 | -------------------------------------------------------------------------------- /src/views/mainContent/home/baseMap/markerContent/index.js: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react' 3 | import ReactDOM from 'react-dom' 4 | import MarkerContent from './markerContent' 5 | let componentInfoContent = null; 6 | let getRef = (self) => { 7 | componentInfoContent = self.refs.markerContent; 8 | }; 9 | 10 | export const markerContentInit = (data, map, el) => { 11 | ReactDOM.render(, document.createElement('div')); 12 | return new Promise((resolve, reject) => { 13 | resolve(componentInfoContent); 14 | }) 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/CDetailInfo/detailInfoTitle.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import './index.scss' 3 | 4 | class CDetailInfoTitle extends Component{ 5 | render(){ 6 | return ( 7 |
8 |
9 | 10 | {this.props.title} 11 |
12 |
{this.props.children}
13 |
14 | ) 15 | } 16 | } 17 | 18 | 19 | export default CDetailInfoTitle 20 | -------------------------------------------------------------------------------- /src/servers/goodsManageApi.js: -------------------------------------------------------------------------------- 1 | import {ajax_get, ajax_post} from "./index"; 2 | 3 | // 获取商品列表 4 | export const getGoodsList = (data) => ajax_get('/fe/goodsManage/goodsList/get/', data); 5 | // 删除商品 6 | export const delGoodsList = (data) => ajax_post('/fe/goodsManage/goodsList/delete/', data); 7 | // 新增商品 8 | export const insertGoodsList = (data) => ajax_post('/fe/goodsManage/goodsList/insert/', data); 9 | // 编辑商品 10 | export const editGoodsList = (data) => ajax_post('/fe/goodsManage/goodsList/edit/', data); 11 | // 获取商品详情 12 | export const detailGoodsList = (data) => ajax_get('/fe/goodsManage/goodsList/detail/', data); 13 | -------------------------------------------------------------------------------- /src/views/mainContent/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .main-content{ 3 | height: 100%; 4 | overflow: auto; 5 | .main-content-scroll{ 6 | height: 100%; 7 | position: relative; 8 | //min-width: 1000px; 9 | } 10 | .main-breadcrumb{ 11 | background-color: #ffffff; 12 | height: 40px; 13 | justify-content: start; 14 | padding: 0 10px; 15 | span{ 16 | font-size: 12px; 17 | } 18 | } 19 | .main-content-body{ 20 | padding: 10px; 21 | //height: calc(100% - 40px); 22 | .main-content-body-card{ 23 | .ant-card-body{ 24 | padding: 15px; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/CBaseComponent/index.js: -------------------------------------------------------------------------------- 1 | 2 | function InjectUnount(target) { 3 | if(!target) return 4 | // 改装componentWillUnmount,销毁的时候记录一下 5 | let next = target.prototype.componentWillUnmount; 6 | target.prototype.componentWillUnmount = function() { 7 | if (next) next.call(this, ...arguments); 8 | this.unmount = true; 9 | }; 10 | // 对setState的改装,setState查看目前是否已经销毁 11 | let setState = target.prototype.setState; 12 | target.prototype.setState = function() { 13 | if (this.unmount) return; 14 | setState.call(this, ...arguments); 15 | }; 16 | return target 17 | } 18 | 19 | export default InjectUnount; 20 | -------------------------------------------------------------------------------- /src/mock/commonSchema.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import * as commonData from './commonData' 3 | 4 | let length = commonData.data.adminRoleList.length; 5 | 6 | /*角色列表数据*/ 7 | const adminRoleList = { 8 | [`list|${length}`]:[ 9 | { 10 | 'id|+1': 1, 11 | 'uid': function () { 12 | return commonData.data.adminRoleList[this.id-1]['uid'] 13 | },//真实用户姓名 14 | 'name': function () { 15 | return commonData.data.adminRoleList[this.id-1]['name'] 16 | },//登录密码 17 | 'createTime': '@datetime',//创建时间 18 | } 19 | ] 20 | }; 21 | 22 | export default { 23 | adminRoleList: Mock.mock(adminRoleList).list, 24 | } 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | 3 | export const mockConfig = { 4 | baseURL: 'mock/fe', 5 | baseMock: { 6 | status: 200, 7 | code: '', 8 | errmsg: '', 9 | data: {}, 10 | } 11 | }; 12 | 13 | export const formatURL = (url) => { 14 | return new RegExp(`${mockConfig.baseURL}${url}`); 15 | }; 16 | 17 | // import './userManage/index' 18 | require('./common/index'); 19 | require('./login/index'); 20 | require('./userManage/index'); 21 | require('./storeManage/index'); 22 | require('./authManage/index'); 23 | require('./goodsManage/index'); 24 | require('./statistics/index'); 25 | 26 | 27 | Mock.setup({ 28 | timeout: '200-600' 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /src/mock/createMockData.js: -------------------------------------------------------------------------------- 1 | 2 | import userManage from "./userManage/schema"; 3 | import storeManage from "./storeManage/schema"; 4 | import goodsManage from "./goodsManage/schema"; 5 | 6 | // 商户列表数据 7 | export const userListBusniess = userManage.userListBusniess; 8 | // 商户列表数据(已删除数据列表) 9 | // export const userListBusniessDelete = userManage.userListBusniessDelete; 10 | // 管理员数据 11 | export const userListAdmin = userManage.userListAdmin; 12 | // 管理员数据(已删除数据列表) 13 | // export const userListAdminDelete = userManage.userListAdminDelete; 14 | // 店铺列表数据 15 | export const storeManageStoreList = storeManage.storeList; 16 | // 商品列表数据 17 | export const goodsManageList = goodsManage.goodsList; 18 | -------------------------------------------------------------------------------- /src/components/CAvatar/index.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | .c-avatar{ 4 | justify-content: start; 5 | align-items: start; 6 | padding-bottom: 20px; 7 | border-bottom: 1px solid #eeeeee; 8 | .c-avatar-img{ 9 | width: 80px; 10 | height: 80px; 11 | flex: none; 12 | border: 1px solid #eeeeee; 13 | border-radius: 2px; 14 | padding: 5px; 15 | margin-right: 10px; 16 | } 17 | .c-avatar-info{ 18 | padding: 5px 0; 19 | p{ 20 | margin: 0; 21 | } 22 | .c-avatar-title{ 23 | font-weight: bold; 24 | } 25 | .c-avatar-rate{ 26 | font-size: 14px; 27 | } 28 | .c-avatar-description{ 29 | color: #888888; 30 | font-size: 12px; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/mock/goodsManage/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import { formatURL} from '../index' 3 | 4 | import { 5 | deleteGoodsManage, 6 | getGoodsManageList, 7 | insertGoodsManage, 8 | editGoodsManage, 9 | detailGoodsManage} from "./apiList"; 10 | 11 | /*获取商品数据*/ 12 | Mock.mock(formatURL('/goodsManage/goodsList/get'), 'get', getGoodsManageList); 13 | Mock.mock(formatURL('/goodsManage/goodsList/delete'), 'post', deleteGoodsManage); 14 | Mock.mock(formatURL('/goodsManage/goodsList/insert'), 'post', insertGoodsManage); 15 | Mock.mock(formatURL('/goodsManage/goodsList/edit'), 'post', editGoodsManage); 16 | // 获取商品详情 17 | Mock.mock(formatURL('/goodsManage/goodsList/detail'), 'get', detailGoodsManage); 18 | 19 | -------------------------------------------------------------------------------- /src/routers/historyRecordRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import historyRecord from '@/views/mainContent/historyRecord' 3 | 4 | import historyRecordDeleteUserList from '@/views/mainContent/historyRecord/deleteUserList' 5 | import historyRecordDeleteAdminUserList from '@/views/mainContent/historyRecord/deleteAdminUserList' 6 | 7 | export default { 8 | path: '/historyRecord', 9 | component: historyRecord, 10 | exact: true, 11 | children: [ 12 | { 13 | path: '/historyRecord/deleteUser', 14 | component: historyRecordDeleteUserList, 15 | exact: true, 16 | }, 17 | { 18 | path: '/historyRecord/deleteAdminUser', 19 | component: historyRecordDeleteAdminUserList, 20 | exact: true, 21 | }, 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /config/pnpTs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { resolveModuleName } = require('ts-pnp'); 4 | 5 | exports.resolveModuleName = ( 6 | typescript, 7 | moduleName, 8 | containingFile, 9 | compilerOptions, 10 | resolutionHost 11 | ) => { 12 | return resolveModuleName( 13 | moduleName, 14 | containingFile, 15 | compilerOptions, 16 | resolutionHost, 17 | typescript.resolveModuleName 18 | ); 19 | }; 20 | 21 | exports.resolveTypeReferenceDirective = ( 22 | typescript, 23 | moduleName, 24 | containingFile, 25 | compilerOptions, 26 | resolutionHost 27 | ) => { 28 | return resolveModuleName( 29 | moduleName, 30 | containingFile, 31 | compilerOptions, 32 | resolutionHost, 33 | typescript.resolveTypeReferenceDirective 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /src/assets/css/common.scss: -------------------------------------------------------------------------------- 1 | @import "./var.scss"; 2 | @import "./antdReset.scss"; 3 | body{ 4 | font-size: 12px; 5 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 6 | } 7 | body,html{ 8 | width: 100%; 9 | height: 100%; 10 | } 11 | #root{ 12 | width: 100%; 13 | height: 100%; 14 | } 15 | 16 | .flex{ 17 | display: flex; 18 | flex-direction: row; 19 | align-items: center; 20 | justify-content: center; 21 | } 22 | 23 | .ellipsis{ 24 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | white-space: nowrap; 27 | } 28 | 29 | .text-color-white{ 30 | color: $text-color-white; 31 | } 32 | 33 | /*table操作列的样式*/ 34 | .operate{ 35 | &>*{ 36 | margin-right: 5px; 37 | &:nth-last-of-type(1){ 38 | margin-right: 0; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/components/CBreadcrumb/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component} from 'react'; 2 | import PropTypes from 'prop-types' 3 | import { Breadcrumb} from 'antd' 4 | import './index.scss' 5 | 6 | class CBreadcrumb extends Component { 7 | 8 | 9 | render(){ 10 | return ( 11 |
12 | 13 | { 14 | this.props.data.map((item, index)=>{ 15 | return {item.name} 16 | }) 17 | } 18 | 19 | {this.props.children} 20 |
21 | 22 | ) 23 | } 24 | } 25 | 26 | CBreadcrumb.propTypes = { 27 | data: PropTypes.array.isRequired, 28 | children: PropTypes.element 29 | }; 30 | 31 | export default CBreadcrumb 32 | -------------------------------------------------------------------------------- /src/servers/historyRecordApi.js: -------------------------------------------------------------------------------- 1 | 2 | import {ajax_get, ajax_post} from "./index"; 3 | 4 | // 获取已删除的商家用户列表 5 | export const getDeleteUserList = (data) => ajax_get('/fe/historyRecord/deleteUserList/get/', data); 6 | // 恢复已删除用户 7 | export const postResetDeleteUser = (data) => ajax_post('/fe/historyRecord/deleteUserList/reset/', data); 8 | // 永久删除用户 9 | export const postPermanentDeleteUser = (data) => ajax_post('/fe/historyRecord/deleteUserList/delete/', data); 10 | 11 | // 获取已删除的系统用户列表 12 | export const getDeleteAdminUserList = (data) => ajax_get('/fe/historyRecord/deleteAdminUserList/get/', data); 13 | // 恢复已删除系统用户 14 | export const postResetDeleteAdminUser = (data) => ajax_post('/fe/historyRecord/deleteAdminUserList/reset/', data); 15 | // 永久删除系统用户 16 | export const postPermanentDeleteAdminUser = (data) => ajax_post('/fe/historyRecord/deleteAdminUserList/delete/', data); 17 | 18 | -------------------------------------------------------------------------------- /src/mock/storeManage/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import { formatURL} from '../index' 3 | 4 | import { 5 | getStoreAllList, 6 | deleteStoreManage, 7 | getStoreManageList, 8 | insertStoreManage, 9 | editStoreManage, 10 | detailStoreManage} from "./apiList"; 11 | 12 | /*获取店铺列表数据*/ 13 | Mock.mock(formatURL('/storeManage/storeList/get'), 'get', getStoreManageList); 14 | /*获取所有店铺列表数据*/ 15 | Mock.mock(formatURL('/storeManage/storeAllList/get'), 'get', getStoreAllList); 16 | // 删除商铺 17 | Mock.mock(formatURL('/storeManage/storeList/delete'), 'post', deleteStoreManage); 18 | // 新建店铺 19 | Mock.mock(formatURL('/storeManage/storeList/insert'), 'post', insertStoreManage); 20 | // 编辑店铺 21 | Mock.mock(formatURL('/storeManage/storeList/edit'), 'post', editStoreManage); 22 | // 获取用户详情 23 | Mock.mock(formatURL('/storeManage/storeList/detail'), 'get', detailStoreManage); 24 | 25 | -------------------------------------------------------------------------------- /src/views/mainContent/home/baseMap/markerContent/markerContent.scss: -------------------------------------------------------------------------------- 1 | 2 | .marker-content{ 3 | background-color: #ffffff; 4 | border: 1px solid #eeeeee; 5 | border-radius: 2px; 6 | overflow: hidden; 7 | min-width: 200px; 8 | .marker-content-title{ 9 | padding: 5px 10px; 10 | border-bottom: 1px solid #eeeeee; 11 | font-size: 12px; 12 | justify-content: space-between; 13 | span{ 14 | padding-right: 20px; 15 | } 16 | i{ 17 | cursor: pointer; 18 | font-size: 14px; 19 | } 20 | } 21 | .marker-content-body{ 22 | padding: 10px; 23 | .content-item{ 24 | justify-content: start; 25 | padding: 2px 0; 26 | font-size: 12px; 27 | .label{ 28 | margin-right: 5px; 29 | } 30 | } 31 | } 32 | 33 | .marker-content-footer{ 34 | border-top: 1px solid #eeeeee; 35 | text-align: right; 36 | padding: 5px 10px; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/CAvatar/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component} from 'react'; 2 | import PropTypes from 'prop-types' 3 | import { Rate} from 'antd' 4 | import './index.scss' 5 | 6 | class CAvatar extends Component { 7 | render(){ 8 | return ( 9 |
10 | 头像 11 |
12 |

{this.props.title}

13 | {this.props.type === 'rate' &&
} 14 |
{this.props.description}
15 |
16 |
17 | ) 18 | } 19 | } 20 | 21 | CAvatar.defaultProps = { 22 | type: 'user' 23 | }; 24 | 25 | CAvatar.propTypes = { 26 | type: PropTypes.string, 27 | rate: PropTypes.number, 28 | }; 29 | 30 | export default CAvatar 31 | -------------------------------------------------------------------------------- /src/redux/common/action.js: -------------------------------------------------------------------------------- 1 | 2 | import * as Common from './action-type' 3 | 4 | // 修改left-nav状态 5 | export const collapsedToggle = (value)=>{ 6 | return { 7 | type: Common.COLLAPSEDTOGGLE, 8 | value 9 | } 10 | }; 11 | 12 | // 修改left-nav状态 13 | export const setBreadcrumb = (value)=>{ 14 | return { 15 | type: Common.SETBREADCRUMB, 16 | value 17 | } 18 | }; 19 | 20 | // 修改reload状态 21 | export const setReload = (value)=>{ 22 | return { 23 | type: Common.RELOAD, 24 | value 25 | } 26 | }; 27 | 28 | // 修改windowInfo 29 | export const setWindowInfo = (value)=>{ 30 | return { 31 | type: Common.WINDOWINFO, 32 | value 33 | } 34 | }; 35 | 36 | // 修改登录用户信息 37 | export const setUserInfo = (value)=>{ 38 | return { 39 | type: Common.USERINFO, 40 | value 41 | } 42 | }; 43 | 44 | // 切换主题 45 | export const setCurrentTheme = (value)=>{ 46 | return { 47 | type: Common.CURRENTTHEME, 48 | value 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /src/servers/storeManageApi.js: -------------------------------------------------------------------------------- 1 | import {ajax_get, ajax_post} from "./index"; 2 | 3 | // 获取商铺列表 4 | export const getStoreList = (data) => ajax_get('/fe/storeManage/storeList/get/', data); 5 | // 删除商铺 6 | export const delStoreList = (data) => ajax_post('/fe/storeManage/storeList/delete/', data); 7 | // 新增商铺 8 | export const insertStoreList = (data) => ajax_post('/fe/storeManage/storeList/insert/', data); 9 | // 编辑商铺 10 | export const editStoreList = (data) => ajax_post('/fe/storeManage/storeList/edit/', data); 11 | // 获取商铺详情 12 | export const detailStoreList = (data) => ajax_get('/fe/storeManage/storeList/detail/', data); 13 | // 根据店铺分类统计店铺数量 14 | export const statisticsStoreByCategory = (data) => ajax_get('/fe/statistics/store/category/get', data); 15 | // 统计新增店铺数量 16 | export const statisticsNewStore = (data) => ajax_get('/fe/statistics/store/new/get', data); 17 | // 店铺排行榜(信誉、售后、星级) 18 | export const statisticsStoreRank = (data) => ajax_get('/fe/statistics/store/rank/get', data); 19 | 20 | -------------------------------------------------------------------------------- /src/components/CPageNew/index.scss: -------------------------------------------------------------------------------- 1 | 2 | @import "@/assets/css/var.scss"; 3 | 4 | .c-page-new{ 5 | //max-width: 600px; 6 | //min-width: 600px; 7 | .c-page-new-item{ 8 | .c-page-new-item-title{ 9 | justify-content: start; 10 | font-weight: bold; 11 | font-size: 13px; 12 | height: 40px; 13 | line-height: 40px; 14 | margin-bottom: 20px; 15 | .title-before-icon{ 16 | display: inline-block; 17 | width: 4px; 18 | height: 15px; 19 | background: $main-base-primary-color; 20 | border-radius: 2px; 21 | margin-right: 5px; 22 | } 23 | } 24 | .c-page-form{ 25 | justify-content: space-between; 26 | .c-page-form-item{ 27 | flex: 1; 28 | } 29 | } 30 | } 31 | .c-page-footer-button{ 32 | background-color: #ffffff; 33 | padding: 15px 30px; 34 | border-top: 1px solid #eaeaea; 35 | margin-top: 60px; 36 | &>*{ 37 | margin-right: 10px; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/CSwiper/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .c-swiper{ 3 | width: 100%; 4 | .c-swiper-container{ 5 | width: 100%; 6 | .swiper-wrapper{ 7 | .swiper-slide{ 8 | background-color: #ffffff; 9 | img{ 10 | width: 100%; 11 | height: 100%; 12 | } 13 | } 14 | } 15 | 16 | .swiper-button-prev{ 17 | background-image: none; 18 | i{ 19 | font-size: 66px; 20 | position: absolute; 21 | top: -13px; 22 | left: 0; 23 | color: #888888; 24 | } 25 | &:hover{ 26 | i{ 27 | color: #999999; 28 | } 29 | } 30 | } 31 | .swiper-button-next{ 32 | background-image: none; 33 | i{ 34 | font-size: 66px; 35 | position: absolute; 36 | top: -12px; 37 | right: 0; 38 | color: #888888; 39 | } 40 | &:hover{ 41 | i{ 42 | color: #999999; 43 | } 44 | } 45 | } 46 | 47 | .swiper-pagination{ 48 | 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/views/mainContent/personal/index.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 个人中心 4 | * */ 5 | 6 | import React, {Component} from 'react'; 7 | import CBaseComponent from '@/components/CBaseComponent' 8 | import {connect} from 'react-redux' 9 | import { bindActionCreators} from 'redux' 10 | import { setBreadcrumb} from "@/redux/common/action"; 11 | // import PercentageEcharts from './percentageEcharts' 12 | import './index.scss' 13 | 14 | @CBaseComponent 15 | class Personal extends Component{ 16 | 17 | componentWillMount(){ 18 | 19 | } 20 | 21 | componentDidMount(){ 22 | this.props.setBreadcrumb([{name: '个人中心'}]); 23 | } 24 | 25 | render(){ 26 | return ( 27 |
个人中心 28 |
29 | ) 30 | } 31 | } 32 | 33 | const mapStateToProps = (state) => { 34 | return { 35 | 36 | } 37 | }; 38 | 39 | const mapDispatchToProps = (dispatch) => { 40 | return { 41 | setBreadcrumb: bindActionCreators(setBreadcrumb, dispatch) 42 | } 43 | }; 44 | 45 | export default connect(mapStateToProps, mapDispatchToProps)(Personal); 46 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | // import App from './views/App'; 4 | import '@/assets/css/common.scss' 5 | import * as serviceWorker from './serviceWorker'; 6 | import Route from '@/routers/index' 7 | import Store from '@/redux/index' 8 | import { Provider } from 'react-redux' 9 | import { AppContainer} from 'react-hot-loader' 10 | import '@/mock' 11 | 12 | 13 | 14 | const render = (Component) => { 15 | ReactDOM.render( 16 | 17 | 18 | 19 | 20 | , 21 | document.getElementById('root')); 22 | }; 23 | 24 | render(Route); 25 | 26 | if (module.hot) { 27 | module.hot.accept('./routers/', () => { 28 | render(Route); 29 | }) 30 | } 31 | 32 | 33 | 34 | // If you want your app to work offline and load faster, you can change 35 | // unregister() to register() below. Note this comes with some pitfalls. 36 | // Learn more about service workers: https://bit.ly/CRA-PWA 37 | serviceWorker.unregister(); 38 | -------------------------------------------------------------------------------- /src/components/CForm/CCheckbox.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { Checkbox} from 'antd' 4 | import './index.scss' 5 | 6 | class CCheckbox extends Component{ 7 | 8 | constructor(props) { 9 | super(props); 10 | this.changeHandler = this.changeHandler.bind(this); 11 | } 12 | 13 | 14 | state = { 15 | value: false 16 | } 17 | 18 | componentWillReceiveProps(nextProps) { 19 | this.setState({ 20 | value: nextProps.value 21 | }); 22 | } 23 | 24 | changeHandler(e){ 25 | let value = e.target.checked; 26 | this.setState({ 27 | value: value 28 | }); 29 | this.props.onChange && this.props.onChange(value); 30 | } 31 | 32 | componentWillMount(){ 33 | let value = this.props.value || false; 34 | this.setState({ 35 | value: value 36 | }) 37 | } 38 | 39 | render(){ 40 | const {onChange, ...props} = this.props; 41 | return ( 42 | this.changeHandler(e)}>{this.props.children} 43 | ) 44 | } 45 | } 46 | 47 | export default CCheckbox 48 | -------------------------------------------------------------------------------- /src/components/CForm/CSwitch.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { Switch} from 'antd' 4 | import './index.scss' 5 | 6 | class CSwitch extends Component{ 7 | 8 | constructor(props) { 9 | super(props); 10 | this.changeHandler = this.changeHandler.bind(this); 11 | } 12 | 13 | 14 | state = { 15 | value: false 16 | } 17 | 18 | componentWillReceiveProps(nextProps) { 19 | this.setState({ 20 | value: nextProps.value 21 | }); 22 | } 23 | 24 | changeHandler(checked){ 25 | let value = checked; 26 | this.setState({ 27 | value: value 28 | }); 29 | this.props.onChange && this.props.onChange(value); 30 | } 31 | 32 | componentWillMount(){ 33 | let value = this.props.value || false; 34 | this.setState({ 35 | value: value 36 | }) 37 | } 38 | 39 | render(){ 40 | const {onChange, value, ...props} = this.props; 41 | return ( 42 | this.changeHandler(checked)} /> 43 | ) 44 | } 45 | } 46 | 47 | CSwitch.defaultProps = { 48 | size: 'small' 49 | } 50 | 51 | export default CSwitch 52 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'name', 12 | dataIndex: 'name', 13 | title: '姓名', 14 | }, 15 | { 16 | key: 'password', 17 | dataIndex: 'password', 18 | title: '密码', 19 | }, 20 | { 21 | key: 'email', 22 | dataIndex: 'email', 23 | title: '邮箱', 24 | }, 25 | { 26 | key: 'phone', 27 | dataIndex: 'phone', 28 | title: '联系电话', 29 | }, 30 | { 31 | key: 'userRole', 32 | dataIndex: 'userRole.name', 33 | title: '角色', 34 | filterMultiple: false, 35 | filters: [] 36 | }, 37 | { 38 | key: 'createTime', 39 | dataIndex: 'createTime', 40 | title: '创建时间', 41 | filterMultiple: true, 42 | filterDate: 'range', 43 | }, 44 | { 45 | key: 'operate', 46 | dataIndex: 'operate', 47 | title: '操作', 48 | fixed: 'right', 49 | width: 100, 50 | slot: 'operate', 51 | }, 52 | ], 53 | tBody: [], 54 | tPage: { 55 | total: 0, 56 | page: 1, 57 | pageSize: 10 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /src/components/CForm/CRadio.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { Radio} from 'antd' 4 | import './index.scss' 5 | 6 | class CRadio extends Component{ 7 | 8 | constructor(props) { 9 | super(props); 10 | this.changeHandler = this.changeHandler.bind(this); 11 | } 12 | 13 | 14 | state = { 15 | value: '' 16 | } 17 | 18 | componentWillReceiveProps(nextProps) { 19 | this.setState({ 20 | value: nextProps.value 21 | }); 22 | } 23 | 24 | changeHandler(e){ 25 | let value = e.target.value; 26 | this.setState({ 27 | value: value 28 | }); 29 | this.props.onChange && this.props.onChange(value); 30 | } 31 | 32 | componentWillMount(){ 33 | let value = this.props.value || ''; 34 | this.setState({ 35 | value: value 36 | }) 37 | } 38 | 39 | render(){ 40 | return ( 41 | this.changeHandler(e)} value={this.state.value}> 42 | { 43 | this.props.options.map((item=>{ 44 | return {item.name} 45 | })) 46 | } 47 | 48 | ) 49 | } 50 | } 51 | 52 | export default CRadio 53 | -------------------------------------------------------------------------------- /src/components/CScroll/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component} from 'react'; 2 | // import PropTypes from 'prop-types'; 3 | import { Scrollbars } from 'react-custom-scrollbars'; 4 | 5 | export default class CScroll extends Component{ 6 | constructor(props){ 7 | super(props); 8 | this.handleScroll = this.handleScroll.bind(this); 9 | } 10 | static propTypes = { 11 | 12 | }; 13 | renderThumb({ style, ...props }) {//设置滚动条的样式 14 | // 暂时不设置滚动条样式 15 | const thumbStyle = { 16 | width: '4px', 17 | backgroundColor: '#000000', 18 | opacity: '0.2', 19 | borderRadius: '4px', 20 | right: '0px', 21 | }; 22 | return ( 23 |
26 | ); 27 | } 28 | handleScroll(e){ 29 | this.props.onScroll && this.props.onScroll(e); 30 | } 31 | render(){ 32 | return( 33 | 42 | {this.props.children} 43 | 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/mock/login/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { formatURL} from '../index' 3 | import { mockConfig} from '../index' 4 | import { filterByObj} from "../commonUtils"; 5 | import { userListBusniess, userListAdmin} from '../createMockData' 6 | let userList = [...userListBusniess, ...userListAdmin]; 7 | 8 | Mock.mock(formatURL('/user/login'), 'post', (opts) => { 9 | // 获取参数 10 | let name = JSON.parse(opts.body).name; 11 | let password = JSON.parse(opts.body).password; 12 | let result = filterByObj(userList, {name,password}, 'and', 'eq'); 13 | if(!result || !result.length){ 14 | // 支持手机号登录 15 | result = filterByObj(userList, {phone: name,password}, 'and', 'eq'); 16 | console.log(result,'====---result==--') 17 | } 18 | console.log(result,'result==--') 19 | let errmsg = ''; 20 | let code = 10000; 21 | let status = 400; 22 | let data = {}; 23 | if(!result || !result.length){ 24 | errmsg = '登录失败'; 25 | code = 10001; 26 | }else if(result[0].isDelete){ 27 | errmsg = '该用户已被删除,请联系管理员'; 28 | code = 10002; 29 | }else if(!result[0].isActive){ 30 | errmsg = '该用户已被停用,请联系管理员'; 31 | code = 10002; 32 | }else{ 33 | data = result[0]; 34 | status = 200; 35 | } 36 | return {...mockConfig.baseMock, ...{errmsg, code, data, status}} 37 | }); 38 | -------------------------------------------------------------------------------- /src/routers/goodsManageRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import goodsManage from '@/views/mainContent/goodsManage' 3 | 4 | import goodsManageList from '@/views/mainContent/goodsManage/goodsList' 5 | import goodsManageListNew from '@/views/mainContent/goodsManage/goodsList/listNew' 6 | import goodsManageListDetail from '@/views/mainContent/goodsManage/goodsList/listDetailInfo' 7 | 8 | 9 | export default { 10 | path: '/goodsManage', 11 | component: goodsManage, 12 | exact: true, 13 | children: [ 14 | // { 15 | // path: '/storeManage/echarts', 16 | // component: storeManageEcharts, 17 | // exact: true, 18 | // }, 19 | { 20 | path: '/goodsManage/list', 21 | component: goodsManageList, 22 | exact: true, 23 | }, 24 | { 25 | path: '/goodsManage/list/new', 26 | component: goodsManageListNew, 27 | exact: true, 28 | }, 29 | { 30 | path: '/goodsManage/list/detail', 31 | component: goodsManageListDetail, 32 | exact: true, 33 | }, 34 | // { 35 | // path: '/storeManage/grade', 36 | // component: storeManageGrade, 37 | // exact: true, 38 | // }, 39 | // { 40 | // path: '/storeManage/member', 41 | // component: storeManageMemer, 42 | // exact: true, 43 | // } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /src/servers/userManageApi.js: -------------------------------------------------------------------------------- 1 | import {ajax_get, ajax_post} from "./index"; 2 | 3 | // 获取商家用户列表 4 | export const getUserList = (data) => ajax_get('/fe/userManage/userList/get/', data); 5 | // 删除商家用户 6 | export const delUserList = (data) => ajax_post('/fe/userManage/userList/delete/', data); 7 | // 新增商家用户 8 | export const insertUserList = (data) => ajax_post('/fe/userManage/userList/insert/', data); 9 | // 编辑商家用户 10 | export const editUserList = (data) => ajax_post('/fe/userManage/userList/edit/', data); 11 | // 获取商家用户详情 12 | export const detailUserList = (data) => ajax_get('/fe/userManage/userList/detail/', data); 13 | // 激活停用 14 | export const editActiveUserList = (data) => ajax_post('/fe/userManage/userList/active/', data); 15 | 16 | 17 | // 获取管理员用户列表 18 | export const getUserAdminList = (data) => ajax_get('/fe/userManage/adminList/get/', data); 19 | // 删除管理员用户 20 | export const delUserAdminList = (data) => ajax_post('/fe/userManage/adminList/delete/', data); 21 | // 新增管理员用户 22 | export const insertUserAdminList = (data) => ajax_post('/fe/userManage/adminList/insert/', data); 23 | // 编辑管理员用户 24 | export const editUserAdminList = (data) => ajax_post('/fe/userManage/adminList/edit/', data); 25 | // 获取管理员用户详情 26 | export const detailUserAdminList = (data) => ajax_get('/fe/userManage/adminList/detail/', data); 27 | -------------------------------------------------------------------------------- /src/servers/commonApi.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios' 2 | import {ajax_get, ajax_post} from "./index"; 3 | 4 | // 登录 5 | export const postLogin = (data) => ajax_post('/fe/user/login/', data); 6 | 7 | // 获取商家用户角色列表 8 | export const getUserBussinesRoleList = (data) => ajax_get('/fe/common/userBussinesRoleList/get/', data); 9 | // 获取管理员角色列表 10 | export const getUserAdminRoleList = (data) => ajax_get('/fe/common/userAdminRoleList/get/', data); 11 | // 获取商店类型列表 12 | export const getStoreCategoryList = (data) => ajax_get('/fe/common/storeCategoryList/get/', data); 13 | // 获取商家用户列表id name 14 | export const getUserBusniessList = (data) => ajax_get('/fe/common/userListBusniess/get/', data); 15 | 16 | 17 | 18 | 19 | // 高德地图关键字搜索 20 | export const getAMapKeywordsSearch = (data) => { 21 | let url = 'https://restapi.amap.com/v3/place/text'; 22 | data.key = 'ba979a0bcd8b467f8a33479f832077c3';//高德地图web服务的key 23 | data.offset = data.offset || 20; 24 | data.page = data.page || 1; 25 | data.extensions = 'all'; 26 | data.types = data.types || 190400; 27 | data.keywords = data.keywords || ''; 28 | 29 | return Axios.get(url, { 30 | params: data, 31 | }).then(response => { 32 | return Promise.resolve(response && response.data) 33 | }).catch(error=>{ 34 | return Promise.reject(error) 35 | }) 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /src/mock/goodsManage/schema.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import * as commonData from '../commonData' 3 | import storeManage from '../storeManage/schema' 4 | const Random = Mock.Random; 5 | 6 | /*商品列表数据*/ 7 | const goodsList = { 8 | 'list|30-100':[ 9 | { 10 | 'id|+1': 1,//商品id 11 | 'storeInfo|1': storeManage.storeList,//店铺id 12 | 'category': 1,//所属分类 13 | 'name': '@cword',//名称 14 | 'description': '@ctitle',//描述 15 | 'price|10-100': 1,//价格 16 | 'originPrice': function () { 17 | return this.price - Random.integer(0, 8) 18 | },//原来的价格 19 | 'stockNum|100-1000': 0,//数量库存 20 | 'tradingTotalNum|1000-100000': 0,//总交易数量 21 | 'tradingMonthNum|100-500': 0,//月交易数量 22 | 'tradingDayNum|0-100': 0,//日交易数量 23 | 'imgs': commonData.data.images.goodsImg,//图片列表id 24 | 'avatarImg': function () { 25 | return this.imgs[0] 26 | },//展示图片 27 | 'commitIds': [],//评价id列表 28 | 'commitGoodRate|0-100': 0,//好评率 29 | 'specification': 1,//规格参数对应的id 30 | 'packList': 0,//包装清单 31 | 'couponIds': [],//优惠券列表id 32 | 'status': '@boolean',//上架(true)下架(false) 33 | 'createTime': '@datetime',//创建时间 34 | } 35 | ] 36 | }; 37 | 38 | 39 | export default { 40 | goodsList: Mock.mock(goodsList).list 41 | } 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/views/mainContent/historyRecord/deleteAdminUserList/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const tableData = { 3 | tHead: [ 4 | { 5 | key: 'id', 6 | title: 'id', 7 | dataIndex: 'id', 8 | }, 9 | { 10 | key: 'name', 11 | dataIndex: 'name', 12 | title: '姓名', 13 | }, 14 | { 15 | key: 'deleteReason', 16 | dataIndex: 'deleteReason', 17 | title: '删除原因', 18 | width: 100, 19 | }, 20 | { 21 | key: 'email', 22 | dataIndex: 'email', 23 | title: '邮箱', 24 | }, 25 | { 26 | key: 'phone', 27 | dataIndex: 'phone', 28 | title: '联系电话', 29 | }, 30 | { 31 | key: 'userRole', 32 | dataIndex: 'userRole.name', 33 | title: '角色', 34 | filterMultiple: false, 35 | filters: [] 36 | }, 37 | { 38 | key: 'createTime', 39 | dataIndex: 'createTime', 40 | title: '创建时间', 41 | filterMultiple: true, 42 | filterDate: 'range', 43 | }, 44 | { 45 | key: 'deleteTime', 46 | dataIndex: 'deleteTime', 47 | title: '删除时间', 48 | }, 49 | { 50 | key: 'operate', 51 | dataIndex: 'operate', 52 | title: '操作', 53 | fixed: 'right', 54 | width: 100, 55 | slot: 'operate', 56 | }, 57 | ], 58 | tBody: [], 59 | tPage: { 60 | total: 0, 61 | page: 1, 62 | pageSize: 10 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /src/redux/common/reducer.js: -------------------------------------------------------------------------------- 1 | import * as Common from './action-type' 2 | import config from '@/config' 3 | 4 | let defaultState = { 5 | currentTheme: 'default',//当前主题 6 | collapsed: config.collapsedDefaultOpen || true,//左侧导航状态 7 | breadcrumbData: [],//面包屑导航数据 8 | reload: false, 9 | userInfo: null,//登录用户信息 10 | windowInfo: { 11 | screenHeight: window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight,//浏览器高度 12 | screenWidth: window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth,//浏览器宽度 13 | mainContentHeight: '',//主内容区域高度 14 | mainContentWidth: '',//主内容区域宽度 15 | } 16 | }; 17 | 18 | let CommonReducer = (state = defaultState, action) => { 19 | switch (action.type) { 20 | case Common.COLLAPSEDTOGGLE: 21 | return {...state, ...{collapsed: action.value}}; 22 | case Common.SETBREADCRUMB: 23 | return {...state, ...{breadcrumbData: action.value}}; 24 | case Common.RELOAD: 25 | return {...state, ...{reload: action.value}}; 26 | case Common.WINDOWINFO: 27 | return {...state, ...{windowInfo: action.value}}; 28 | case Common.USERINFO: 29 | return {...state, ...{userInfo: action.value}}; 30 | case Common.CURRENTTHEME: 31 | return {...state, ...{currentTheme: action.value}}; 32 | default: 33 | return state; 34 | } 35 | }; 36 | 37 | export default CommonReducer; 38 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const camelcase = require('camelcase'); 5 | 6 | // This is a custom Jest transformer turning file imports into filenames. 7 | // http://facebook.github.io/jest/docs/en/webpack.html 8 | 9 | module.exports = { 10 | process(src, filename) { 11 | const assetFilename = JSON.stringify(path.basename(filename)); 12 | 13 | if (filename.match(/\.svg$/)) { 14 | // Based on how SVGR generates a component name: 15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 16 | const pascalCaseFileName = camelcase(path.parse(filename).name, { 17 | pascalCase: true, 18 | }); 19 | const componentName = `Svg${pascalCaseFileName}`; 20 | return `const React = require('react'); 21 | module.exports = { 22 | __esModule: true, 23 | default: ${assetFilename}, 24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) { 25 | return { 26 | $$typeof: Symbol.for('react.element'), 27 | type: 'svg', 28 | ref: ref, 29 | key: null, 30 | props: Object.assign({}, props, { 31 | children: ${assetFilename} 32 | }) 33 | }; 34 | }), 35 | };`; 36 | } 37 | 38 | return `module.exports = ${assetFilename};`; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/listDetailInfo/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const detailInfoData = [ 3 | { 4 | id: 'baseInfo', 5 | title: '基本信息', 6 | data: [ 7 | { 8 | id: 'id', 9 | name: '用户ID', 10 | value: '', 11 | type: 'input', 12 | jpath: 'id', 13 | }, 14 | { 15 | id: 'name', 16 | name: '姓名', 17 | value: '', 18 | type: 'input', 19 | jpath: 'name', 20 | }, 21 | { 22 | id: 'password', 23 | name: '密码', 24 | value: '', 25 | type: 'input', 26 | jpath: 'password', 27 | }, 28 | { 29 | id: 'phone', 30 | name: '手机号', 31 | value: '', 32 | type: 'input', 33 | jpath: 'phone', 34 | }, 35 | { 36 | id: 'sex', 37 | name: '性别', 38 | value: '', 39 | type: 'input', 40 | jpath: 'sex.name', 41 | }, 42 | { 43 | id: 'userRole', 44 | name: '用户角色', 45 | value: '', 46 | type: 'input', 47 | jpath: 'userRole.name', 48 | }, 49 | { 50 | id: 'email', 51 | name: '邮箱', 52 | value: '', 53 | type: 'input', 54 | jpath: 'email', 55 | }, 56 | { 57 | id: 'createTime', 58 | name: '创建时间', 59 | value: '', 60 | type: 'input', 61 | jpath: 'createTime', 62 | }, 63 | ] 64 | } 65 | ]; 66 | -------------------------------------------------------------------------------- /src/mock/common/index.js: -------------------------------------------------------------------------------- 1 | 2 | import Mock from 'mockjs'; 3 | import { formatURL, mockConfig} from '../index' 4 | import * as commonData from '../commonData' 5 | import commonSchema from '../commonSchema' 6 | import { userListBusniess} from "../createMockData"; 7 | import { urlFormat} from "@/utils"; 8 | import { filterByObj} from '../commonUtils' 9 | 10 | /*获取用户管理员角色数据*/ 11 | Mock.mock(formatURL('/common/userAdminRoleList/get'), 'get', {...mockConfig.baseMock, data: {list: commonSchema.adminRoleList}}); 12 | 13 | /*获取用户商家角色数据*/ 14 | Mock.mock(formatURL('/common/userBussinesRoleList/get'), 'get', {...mockConfig.baseMock, data: {list: commonData.data.userRole}}); 15 | 16 | /*获取商店类型数据*/ 17 | Mock.mock(formatURL('/common/storeCategoryList/get'), 'get', {...mockConfig.baseMock, data: {list: commonData.data.storeCategory}}); 18 | 19 | /*获取商家用户列表id name数据*/ 20 | Mock.mock(formatURL('/common/userListBusniess/get'), 'get', function (opts) { 21 | let search = decodeURI(urlFormat(opts.url, 'search')); 22 | let id = urlFormat(opts.url, 'id'); 23 | let data = []; 24 | let result = userListBusniess; 25 | if(search && search !== 'undefined'){ 26 | result = filterByObj(result, {'name':search}, 'or'); 27 | } 28 | if(id){ 29 | result = filterByObj(result, {'id':id}, 'or', 'eq'); 30 | } 31 | result.forEach(item=>{ 32 | data.push({ 33 | id: item.id, 34 | name: item.name 35 | }) 36 | }); 37 | return {...mockConfig.baseMock, data: {list: data}} 38 | }); 39 | 40 | -------------------------------------------------------------------------------- /src/routers/storeManageRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import storeManage from '@/views/mainContent/storeManage' 3 | import storeManageEcharts from '@/views/mainContent/storeManage/echarts' 4 | // import storeManageGrade from '@/views/mainContent/storeManage/grade' 5 | 6 | import storeManageList from '@/views/mainContent/storeManage/list' 7 | import storeManageListNew from '@/views/mainContent/storeManage/list/listNew' 8 | import storeManageListDetail from '@/views/mainContent/storeManage/list/listDetailInfo' 9 | 10 | // import storeManageMemer from '@/views/mainContent/storeManage/member' 11 | 12 | export default { 13 | path: '/storeManage', 14 | component: storeManage, 15 | exact: true, 16 | children: [ 17 | { 18 | path: '/storeManage/echarts', 19 | component: storeManageEcharts, 20 | exact: true, 21 | }, 22 | { 23 | path: '/storeManage/list', 24 | component: storeManageList, 25 | exact: true, 26 | }, 27 | { 28 | path: '/storeManage/list/new', 29 | component: storeManageListNew, 30 | exact: true, 31 | }, 32 | { 33 | path: '/storeManage/list/detail', 34 | component: storeManageListDetail, 35 | exact: true, 36 | }, 37 | // { 38 | // path: '/storeManage/grade', 39 | // component: storeManageGrade, 40 | // exact: true, 41 | // }, 42 | // { 43 | // path: '/storeManage/member', 44 | // component: storeManageMemer, 45 | // exact: true, 46 | // } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /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 | 19 | const jest = require('jest'); 20 | const execSync = require('child_process').execSync; 21 | let argv = process.argv.slice(2); 22 | 23 | function isInGitRepository() { 24 | try { 25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 26 | return true; 27 | } catch (e) { 28 | return false; 29 | } 30 | } 31 | 32 | function isInMercurialRepository() { 33 | try { 34 | execSync('hg --cwd . root', { stdio: 'ignore' }); 35 | return true; 36 | } catch (e) { 37 | return false; 38 | } 39 | } 40 | 41 | // Watch unless on CI or explicitly running all tests 42 | if ( 43 | !process.env.CI && 44 | argv.indexOf('--watchAll') === -1 45 | ) { 46 | // https://github.com/facebook/create-react-app/issues/5210 47 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 48 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 49 | } 50 | 51 | 52 | jest.run(argv); 53 | -------------------------------------------------------------------------------- /src/components/CForm/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .c-input, .c-input-number, .c-select, .ant-select, .ant-select-selection, .c-date-picker{ 3 | width: 100%; 4 | border-radius: 2px!important; 5 | font-size: 12px!important; 6 | &.ant-input, .ant-input{ 7 | border-radius: 2px!important; 8 | font-size: 12px!important; 9 | } 10 | } 11 | 12 | .ant-input-number.c-input-number{ 13 | width: 100%; 14 | } 15 | 16 | .ant-input-search{ 17 | .ant-input{ 18 | border-radius: 2px; 19 | } 20 | } 21 | 22 | .no-show-number-step{ 23 | .ant-input-number-handler-wrap{ 24 | display: none; 25 | } 26 | } 27 | 28 | .c-select { 29 | min-width: 150px; 30 | } 31 | .ant-select-dropdown{ 32 | font-size: 13px; 33 | .ant-select-dropdown-menu{ 34 | font-size: 13px; 35 | } 36 | } 37 | 38 | .c-upload{ 39 | .ant-upload-text{ 40 | font-size: 12px; 41 | } 42 | } 43 | 44 | 45 | .c-form{ 46 | .ant-form label{ 47 | font-size: 13px; 48 | } 49 | .c-form-content{ 50 | justify-content: start; 51 | .c-form-label{ 52 | width: 120px; 53 | text-align: right; 54 | margin-right: 10px; 55 | font-size: 12px; 56 | .required-icon{ 57 | color: red; 58 | } 59 | } 60 | .c-form-content-form{ 61 | flex: 1; 62 | } 63 | } 64 | .c-form-error-info{ 65 | height: 15px; 66 | color: red; 67 | padding-left: 130px; 68 | font-size: 12px; 69 | } 70 | .c-form-none-label{ 71 | padding-left: 0; 72 | } 73 | .c-form-item{ 74 | margin-bottom: 0; 75 | } 76 | } 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/mock/storeManage/schema.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import * as commonData from '../commonData' 3 | import userList from '../userManage/schema' 4 | import {randomDate} from "@/utils"; 5 | import {randomLongLat} from "../commonUtils"; 6 | 7 | // const Random = Mock.Random; 8 | 9 | /*店铺列表数据*/ 10 | const storeList = { 11 | 'list|30-150': [ 12 | { 13 | 'id|+1': 1,//店铺id 14 | 'user|1': userList.userListBusniess,//商家id 15 | 'storeName': '@ctitle',//店铺名称 16 | 'description': '@cparagraph',//店铺描述 17 | 'address': '@COUNTY(true)',//店铺地址 18 | 'category|1': commonData.data.storeCategory,//店铺所属分类 19 | 'organizationCode': /[A-Z0-9]{8}-[A-Z0-9]$|[A-Z0-9]{8}-[A-Z0-9]-[0-9]{2}$/,//组织机构代码 20 | 'businessLicenseImg|1': commonData.data.images.businessLicenseImg,//营业执照 21 | 'storeAge|0-500': 0,//店铺年限(按天计) 22 | 'focusNum|100-10000000': 0,//被关注数量(粉丝) 23 | 'avatarImg|1': commonData.data.images.avatar,//店铺头像 24 | 'grade': 1,//店铺等级 25 | 'creditGrade|1': commonData.data.creditGrade,//店铺信誉等级 26 | 'serviceScore|0-9.0-1': 0,//店铺售后评分 27 | 'rate|0-9.0-1': 0,//店铺星级 28 | 'latlong': function () { 29 | return randomLongLat([87.9345703125,118.5644531250], [21.8614987344,42.0329743324]); 30 | },//经纬度 31 | 'createTime': function () { 32 | return randomDate('2017-01-01', new Date()) 33 | },//创建时间 34 | // 'createTime': '@datetime',//创建时间 35 | } 36 | ] 37 | }; 38 | 39 | 40 | export default { 41 | storeList: Mock.mock(storeList).list 42 | } 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/components/CButton/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component} from 'react'; 2 | import PropTypes from 'prop-types' 3 | import { Button, Icon} from 'antd' 4 | import './index.scss' 5 | 6 | class CButton extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.clickHandler = this.clickHandler.bind(this); 10 | } 11 | 12 | clickHandler(e){ 13 | e.preventDefault(); 14 | this.props.onClick && this.props.onClick(); 15 | } 16 | 17 | render(){ 18 | const {icon, type, size, disabled, className, authId, ...props} = this.props; 19 | const iconRender = icon.includes('fa') ? : ; 20 | return ( 21 |
22 | 31 |
32 | ) 33 | } 34 | } 35 | 36 | CButton.defaultProps = { 37 | type: 'default', 38 | size: 'default', 39 | icon: '', 40 | disabled: false, 41 | loading: false, 42 | }; 43 | 44 | CButton.propTypes = { 45 | type: PropTypes.string, 46 | icon: PropTypes.string, 47 | shape: PropTypes.string, 48 | disabled: PropTypes.bool, 49 | loading: PropTypes.bool, 50 | onClick: PropTypes.func, 51 | authId: PropTypes.string,//权限id 52 | }; 53 | 54 | export default CButton 55 | -------------------------------------------------------------------------------- /src/components/CEcharts/index.js: -------------------------------------------------------------------------------- 1 | 2 | import React, {Component} from 'react' 3 | import { connect} from 'react-redux' 4 | import Echarts from 'echarts' 5 | import './index.scss' 6 | 7 | class CEcharts extends Component{ 8 | 9 | constructor(props) { 10 | super(props); 11 | this.initEcharts = this.initEcharts.bind(this); 12 | this.initOptions = this.initOptions.bind(this); 13 | this.resizeHandler = this.resizeHandler.bind(this); 14 | } 15 | 16 | state = { 17 | echarts: null, 18 | options: null 19 | } 20 | 21 | initEcharts(){ 22 | let echarts = Echarts.init(this.refs.CEcharts); 23 | this.setState({ 24 | echarts: echarts 25 | }, () => this.initOptions(this.props.options)); 26 | } 27 | 28 | initOptions(options){ 29 | if(this.state.echarts && options){ 30 | this.state.echarts.setOption(options) 31 | } 32 | } 33 | 34 | resizeHandler(){ 35 | this.state.echarts && this.state.echarts.resize(); 36 | } 37 | 38 | componentWillReceiveProps(nextProps) { 39 | this.initOptions(nextProps.options); 40 | this.resizeHandler(); 41 | } 42 | 43 | 44 | componentWillMount(){ 45 | 46 | } 47 | 48 | componentDidMount(){ 49 | this.initEcharts(); 50 | } 51 | 52 | render(){ 53 | const { height} = this.props; 54 | let style = {}; 55 | if(height) style = {height: height}; 56 | return ( 57 |
58 | ) 59 | } 60 | } 61 | 62 | 63 | const mapStateToProps = (state) => { 64 | return { 65 | windowInfo: state.Common.windowInfo, 66 | } 67 | }; 68 | 69 | export default connect(mapStateToProps)(CEcharts); 70 | -------------------------------------------------------------------------------- /src/components/CTable/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .c-table{ 3 | .ant-table{ 4 | border-radius: 2px; 5 | } 6 | .ant-table-body{ 7 | margin: 0!important; 8 | } 9 | .c-table-column{ 10 | white-space: nowrap; 11 | overflow: hidden; 12 | font-size: 13px; 13 | } 14 | table thead, .ant-table .ant-table-head{ 15 | th{ 16 | background-color: #fafafa!important; 17 | font-weight: bold; 18 | color: rgba(0,0,0,0.7); 19 | font-size: 13px; 20 | } 21 | } 22 | } 23 | 24 | //表格头部展示的筛选项样式 25 | .filter-head{ 26 | justify-content: start; 27 | margin: 10px 0; 28 | align-items: baseline; 29 | flex-wrap: wrap; 30 | .filter-label{ 31 | justify-content: start; 32 | width: 80px; 33 | i{ 34 | font-size: 13px; 35 | } 36 | span{ 37 | margin-left: 5px; 38 | font-size: 13px; 39 | } 40 | } 41 | .filter-content{ 42 | justify-content: start; 43 | flex-wrap: wrap; 44 | flex: 1; 45 | .filter-head-item{ 46 | margin: 5px 0; 47 | margin-right: 20px; 48 | .label{ 49 | font-size: 12px; 50 | font-weight: bold; 51 | } 52 | .filter-tag{ 53 | margin-left: 5px; 54 | } 55 | } 56 | } 57 | } 58 | 59 | //表格下拉的筛选项样式 60 | .table-filter-dropdown-list{ 61 | font-size: 12px; 62 | border-radius: 2px; 63 | .table-filter-item{ 64 | cursor: pointer; 65 | span{ 66 | font-size: 12px; 67 | } 68 | &:hover{ 69 | background-color: rgba(30, 159, 255, 0.2); 70 | } 71 | } 72 | 73 | .table-filter-dropdown-footer{ 74 | width: 100%; 75 | justify-content: flex-end; 76 | &>*{ 77 | margin-left: 3px; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/views/mainContent/authManage/roleList/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'uid', 12 | title: 'uid', 13 | dataIndex: 'uid', 14 | }, 15 | { 16 | key: 'name', 17 | dataIndex: 'name', 18 | title: '角色', 19 | }, 20 | { 21 | key: 'createTime', 22 | dataIndex: 'createTime', 23 | title: '创建时间', 24 | }, 25 | { 26 | key: 'operate', 27 | dataIndex: 'operate', 28 | title: '操作', 29 | width: 100, 30 | slot: 'operate', 31 | }, 32 | ], 33 | tBody: [], 34 | tPage: { 35 | total: 0, 36 | page: 1, 37 | pageSize: 10 38 | } 39 | }; 40 | 41 | 42 | export const authManageRoleListNewData = [ 43 | { 44 | id: 'baseInfo', 45 | title: '', 46 | data: [ 47 | { 48 | id: 'uid', 49 | name: 'uid', 50 | placeholder: '请输入uid', 51 | type: 'input', 52 | checkType: 'required', 53 | newDisabled: false, 54 | editDisabled: false, 55 | newShow: true, 56 | editShow: true, 57 | value: '', 58 | options: [], 59 | expand: {}, 60 | jpath: 'uid' 61 | }, 62 | { 63 | id: 'name', 64 | name: '角色名', 65 | placeholder: '请输入角色名', 66 | type: 'input', 67 | checkType: 'required', 68 | newDisabled: false, 69 | editDisabled: false, 70 | newShow: true, 71 | editShow: true, 72 | value: '', 73 | options: [], 74 | expand: {}, 75 | jpath: 'name' 76 | }, 77 | ] 78 | } 79 | ]; 80 | -------------------------------------------------------------------------------- /src/views/header/index.scss: -------------------------------------------------------------------------------- 1 | @import "@/assets/css/var.scss"; 2 | @import "@/assets/css/themeFn.scss"; 3 | 4 | .header{ 5 | height: $header-height; 6 | background: $header-background; 7 | @include themify(){ 8 | background: themed('header-background-color'); 9 | } 10 | .logo{ 11 | width: 200px; 12 | font-size: 18px; 13 | padding: 0 20px; 14 | } 15 | .info{ 16 | padding-right: 20px; 17 | flex: 1; 18 | justify-content: space-between; 19 | .collapsed{ 20 | background-color: rgba(255,255,255,0.1); 21 | padding: 8px; 22 | border-radius: 2px; 23 | cursor: pointer; 24 | &:hover{ 25 | background-color: rgba(255,255,255,0.3); 26 | } 27 | i{ 28 | font-size: 16px; 29 | } 30 | } 31 | 32 | .info-right{ 33 | justify-content: flex-end; 34 | .theme-config{ 35 | margin-right: 20px; 36 | .theme-config-name{ 37 | font-size: 12px; 38 | margin-right: 10px; 39 | } 40 | .themeItem{ 41 | .themeItemColor{ 42 | width: 20px; 43 | height: 20px; 44 | border-radius: 2px; 45 | margin: 0 5px; 46 | } 47 | } 48 | } 49 | 50 | .user-info{ 51 | color: $text-color-white; 52 | .user-name{ 53 | margin-right: 8px; 54 | } 55 | .user-avatar{ 56 | width: 30px; 57 | height: 30px; 58 | border-radius: 50%; 59 | margin-right: 5px; 60 | } 61 | } 62 | 63 | .ant-dropdown-trigger{ 64 | display: inline-block; 65 | height: $header-height; 66 | line-height: $header-height; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/listDetailInfo/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CDetailInfo from '@/components/CDetailInfo' 3 | import CAvatar from '@/components/CAvatar' 4 | import CBaseComponent from '@/components/CBaseComponent' 5 | import { detailInfoData} from "./data"; 6 | import { detailUserAdminList} from "@/servers/userManageApi"; 7 | import { urlFormat, setPageNewValue} from "@/utils"; 8 | 9 | @CBaseComponent 10 | class UserManageAdminListDetailInfo extends Component{ 11 | 12 | constructor(props) { 13 | super(props); 14 | this.getUserDetailData = this.getUserDetailData.bind(this); 15 | } 16 | 17 | 18 | state = { 19 | data: detailInfoData, 20 | avatar: { 21 | img: '', 22 | title: '', 23 | description: '' 24 | } 25 | }; 26 | 27 | getUserDetailData(){ 28 | let id = urlFormat(this.props.history.location.search).query.id; 29 | detailUserAdminList({id}).then(res=>{ 30 | let userInfo = res.data.userInfo; 31 | let data = setPageNewValue(detailInfoData, userInfo); 32 | this.setState({ 33 | data: data, 34 | avatar: { 35 | img: userInfo.avatar && userInfo.avatar.url, 36 | title: userInfo.name, 37 | description: '' 38 | } 39 | }) 40 | }).catch(err=>{ 41 | 42 | }) 43 | } 44 | 45 | componentDidMount(){ 46 | this.getUserDetailData(); 47 | } 48 | 49 | render(){ 50 | return ( 51 | <> 52 | 53 | 54 | 55 | 56 | ) 57 | } 58 | } 59 | 60 | export default UserManageAdminListDetailInfo 61 | -------------------------------------------------------------------------------- /src/mock/authManage/roleList.js: -------------------------------------------------------------------------------- 1 | 2 | import { mockConfig} from '../index' 3 | // import _ from 'lodash' 4 | import commonSchema from '../commonSchema' 5 | import { filterByObj, deleteDataByKeys} from "../commonUtils"; 6 | import { formatDate} from "@/utils"; 7 | 8 | /*系统角色列表*/ 9 | let adminRoleListData = commonSchema.adminRoleList.reverse(); 10 | 11 | /*获取角色列表在commmonApi中*/ 12 | 13 | /*删除角色*/ 14 | export const deleteAuthManageRole = (opts) => { 15 | // 获取参数 16 | let id = JSON.parse(opts.body).id; 17 | 18 | let delArray = deleteDataByKeys(adminRoleListData, 'id', id); 19 | 20 | let errmsg = ''; 21 | if(delArray.length !== id.length){ 22 | errmsg = '删除失败'; 23 | mockConfig.baseMock.code = 10001; 24 | } 25 | 26 | return {...mockConfig.baseMock, errmsg} 27 | }; 28 | 29 | /*添加角色*/ 30 | export const insertAuthManageRole = (opts) => { 31 | // 获取参数 32 | let roleInfo = JSON.parse(opts.body); 33 | let popRoleInfo = adminRoleListData[0];//第一项 34 | let id = Number(popRoleInfo.id) + 1;//取第一项的id+1为新项id 35 | roleInfo.id = id; 36 | roleInfo.createTime = formatDate(); 37 | adminRoleListData.unshift(roleInfo); 38 | 39 | return {...mockConfig.baseMock, ...{data: {id}}} 40 | }; 41 | 42 | /*编辑角色*/ 43 | export const editStoreManage = (opts) => { 44 | // 获取参数 45 | let editRoleInfo = JSON.parse(opts.body); 46 | let {id, ...editPropsRoleInfo} = editRoleInfo;//获取角色id及其他信息 47 | let roleInfo = filterByObj(adminRoleListData, {id: id}, 'or', 'eq')[0]; 48 | let newRoleInfo = Object.assign({}, roleInfo, editPropsRoleInfo); 49 | 50 | let index = adminRoleListData.findIndex(item=>{ 51 | return item.id.toString() === id.toString() 52 | }); 53 | 54 | adminRoleListData.splice(index, 1, newRoleInfo); 55 | 56 | return {...mockConfig.baseMock} 57 | }; 58 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/listDetailInfo/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CDetailInfo from '@/components/CDetailInfo' 3 | import CBaseComponent from '@/components/CBaseComponent' 4 | import CAvatar from '@/components/CAvatar' 5 | import {detailInfoData} from "./data"; 6 | import {detailGoodsList} from "@/servers/goodsManageApi"; 7 | import {urlFormat, setPageNewValue} from "@/utils"; 8 | 9 | @CBaseComponent 10 | class StoreManageListDetailInfo extends Component { 11 | 12 | constructor(props) { 13 | super(props); 14 | this.getStoreDetailData = this.getStoreDetailData.bind(this); 15 | } 16 | 17 | 18 | state = { 19 | data: detailInfoData, 20 | avatar: { 21 | img: '', 22 | title: '', 23 | description: '', 24 | } 25 | }; 26 | 27 | getStoreDetailData() { 28 | let id = urlFormat(this.props.history.location.search).query.id; 29 | detailGoodsList({id}).then(res => { 30 | let goodsInfo = res.data.goodsInfo; 31 | let data = setPageNewValue(detailInfoData, goodsInfo); 32 | this.setState({ 33 | data: data, 34 | avatar: { 35 | img: goodsInfo.avatarImg && goodsInfo.avatarImg.url, 36 | title: goodsInfo.name, 37 | description: goodsInfo.description, 38 | } 39 | }) 40 | }).catch(err => { 41 | 42 | }) 43 | } 44 | 45 | render() { 46 | return ( 47 | <> 48 | 50 | 51 | 52 | ) 53 | } 54 | 55 | componentDidMount() { 56 | this.getStoreDetailData(); 57 | } 58 | } 59 | 60 | export default StoreManageListDetailInfo 61 | -------------------------------------------------------------------------------- /src/components/CDetailInfo/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import PropTypes from 'prop-types' 3 | import _ from 'lodash' 4 | import CDetailInfoTitle from './detailInfoTitle' 5 | import CDetailInfoItem from './detailInfoItem' 6 | import './index.scss' 7 | 8 | class CDetailInfo extends Component{ 9 | 10 | componentWillMount(){ 11 | 12 | } 13 | 14 | render(){ 15 | console.log(this.props.children,'this.props.children') 16 | return ( 17 |
18 | { 19 | this.props.data && !!this.props.data.length && this.props.data.map((baseItem, baseIndex) => { 20 | return
21 | { 22 | baseItem.title && 23 | } 24 | { 25 | !!baseItem.data.length && !baseItem.slot && 26 | } 27 | {/*如果children是数组则循环判断用到的是哪一个children*/} 28 | { 29 | !!baseItem.data.length && baseItem.slot && _.isArray(this.props.children) && this.props.children.map((slotItem, slotIndex) => { 30 | return slotItem.props.slot === baseItem.slot && slotItem 31 | }) 32 | } 33 | {/*如果children是对象并且children的props.slot为data中定义的slot则展示*/} 34 | { 35 | baseItem.slot && !_.isArray(this.props.children) && this.props.children.props.slot === baseItem.slot && this.props.children 36 | } 37 |
38 | }) 39 | } 40 |
41 | ) 42 | } 43 | } 44 | 45 | CDetailInfo.defaultProps = { 46 | data: [] 47 | }; 48 | 49 | CDetailInfo.propTypes = { 50 | data: PropTypes.array, 51 | }; 52 | 53 | export default CDetailInfo 54 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'name', 12 | dataIndex: 'name', 13 | title: '商品名称', 14 | }, 15 | { 16 | key: 'storeInfo', 17 | dataIndex: 'storeInfo.storeName', 18 | title: '所属店铺', 19 | }, 20 | { 21 | key: 'category', 22 | dataIndex: 'category', 23 | title: '所属分类', 24 | }, 25 | { 26 | key: 'price', 27 | dataIndex: 'price', 28 | title: '价格(元)', 29 | }, 30 | { 31 | key: 'stockNum', 32 | dataIndex: 'stockNum', 33 | title: '库存(件)', 34 | }, 35 | { 36 | key: 'tradingTotalNum', 37 | dataIndex: 'tradingTotalNum', 38 | title: '总交易数量(件)', 39 | }, 40 | { 41 | key: 'tradingMonthNum', 42 | dataIndex: 'tradingMonthNum', 43 | title: '月交易数量(件)', 44 | }, 45 | { 46 | key: 'tradingDayNum', 47 | dataIndex: 'tradingDayNum', 48 | title: '日交易数量(件)', 49 | }, 50 | { 51 | key: 'commitGoodRate', 52 | dataIndex: 'commitGoodRate', 53 | title: '好评率(%)', 54 | }, 55 | { 56 | key: 'createTime', 57 | dataIndex: 'createTime', 58 | title: '创建时间', 59 | filterMultiple: true, 60 | filterDate: 'range', 61 | }, 62 | { 63 | key: 'status', 64 | dataIndex: 'status', 65 | title: '上下架', 66 | fixed: 'right', 67 | slot: 'status', 68 | }, 69 | { 70 | key: 'operate', 71 | dataIndex: 'operate', 72 | title: '操作', 73 | fixed: 'right', 74 | width: 100, 75 | slot: 'operate', 76 | }, 77 | ], 78 | tBody: [], 79 | tPage: { 80 | total: 0, 81 | page: 1, 82 | pageSize: 10 83 | } 84 | }; 85 | -------------------------------------------------------------------------------- /src/views/login/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .login{ 3 | height: 100%; 4 | min-height: 500px; 5 | background: url("../../assets/images/login-bg.jpg") no-repeat; 6 | background-size: cover; 7 | display: flex; 8 | flex-direction: column; 9 | .login-header{ 10 | justify-content: space-between; 11 | padding: 20px 50px; 12 | .login-header-logo{ 13 | color: #ffffff; 14 | font-size: 26px; 15 | } 16 | .login-header-href{ 17 | a:hover{ 18 | color: #dddddd; 19 | } 20 | } 21 | a{ 22 | color: #ffffff; 23 | } 24 | } 25 | .login-content{ 26 | padding: 20px 50px; 27 | justify-content: flex-end; 28 | flex: 1; 29 | .login-form{ 30 | width: 400px; 31 | overflow: hidden; 32 | transform: translateY(-30%); 33 | border-radius: 2px; 34 | .login-form-title{ 35 | width: 100%; 36 | padding: 20px; 37 | justify-content: space-between; 38 | color: #ffffff; 39 | background: rgba(0,0,0,0.4); 40 | color: rgba(255,255,255,0.8); 41 | i{ 42 | font-size: 24px; 43 | color: rgba(255,255,255,0.3); 44 | } 45 | } 46 | .login-form-content{ 47 | width: 100%; 48 | padding: 20px; 49 | background: rgba(0,0,0,0.3); 50 | &>*{ 51 | margin: 10px 0; 52 | } 53 | input{ 54 | background-color: rgba(255, 255, 255, 0.2); 55 | border: none; 56 | color: rgba(255,255,255,0.8); 57 | &::-webkit-input-placeholder{ 58 | color: rgba(255,255,255,0.8); 59 | } 60 | } 61 | .ant-input-suffix{ 62 | i{ 63 | color: #cccccc; 64 | } 65 | } 66 | } 67 | 68 | .login-button{ 69 | width: 100%; 70 | font-size: 12px; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/list/listDetailInfo/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CDetailInfo from '@/components/CDetailInfo' 3 | import CBaseComponent from '@/components/CBaseComponent' 4 | import CAvatar from '@/components/CAvatar' 5 | import {detailInfoData} from "./data"; 6 | import {detailStoreList} from "@/servers/storeManageApi"; 7 | import {urlFormat, setPageNewValue} from "@/utils"; 8 | 9 | @CBaseComponent 10 | class StoreManageListDetailInfo extends Component { 11 | constructor(props) { 12 | super(props); 13 | this.getStoreDetailData = this.getStoreDetailData.bind(this); 14 | } 15 | 16 | 17 | state = { 18 | data: detailInfoData, 19 | avatar: { 20 | img: '', 21 | title: '', 22 | description: '', 23 | rate: 0 24 | } 25 | }; 26 | 27 | getStoreDetailData() { 28 | let id = urlFormat(this.props.history.location.search).query.id; 29 | detailStoreList({id}).then(res => { 30 | let userInfo = res.data.userInfo; 31 | let data = setPageNewValue(detailInfoData, userInfo); 32 | this.setState({ 33 | data: data, 34 | avatar: { 35 | img: userInfo.avatarImg && userInfo.avatarImg.url, 36 | title: userInfo.storeName, 37 | description: userInfo.description, 38 | rate: userInfo.rate 39 | } 40 | }) 41 | }).catch(err => { 42 | 43 | }) 44 | } 45 | 46 | render() { 47 | return ( 48 | <> 49 | 51 | 52 | 53 | ) 54 | } 55 | 56 | componentDidMount() { 57 | this.getStoreDetailData(); 58 | } 59 | } 60 | 61 | export default StoreManageListDetailInfo 62 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/list/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'storeName', 12 | dataIndex: 'storeName', 13 | title: '店铺名称', 14 | /*filterMultiple: true, 15 | filters: [ 16 | { 17 | value: '1', 18 | text: '用户类型1' 19 | }, 20 | { 21 | value: '2', 22 | text: '用户类型2' 23 | }, 24 | { 25 | value: '3', 26 | text: '用户类型3' 27 | } 28 | ]*/ 29 | }, 30 | { 31 | key: 'storeAge', 32 | dataIndex: 'storeAge', 33 | title: '店铺年限(天)', 34 | }, 35 | { 36 | key: 'name', 37 | dataIndex: 'user.name', 38 | title: '所属用户', 39 | }, 40 | { 41 | key: 'role', 42 | dataIndex: 'user.userRole.name', 43 | title: '用户角色', 44 | }, 45 | { 46 | key: 'address', 47 | dataIndex: 'address', 48 | title: '地址', 49 | }, 50 | { 51 | key: 'category', 52 | dataIndex: 'category.name', 53 | title: '店铺分类', 54 | filterMultiple: false, 55 | }, 56 | { 57 | key: 'focusNum', 58 | dataIndex: 'focusNum', 59 | title: '关注量', 60 | }, 61 | { 62 | key: 'creditGrade', 63 | dataIndex: 'creditGrade.name', 64 | title: '信誉等级', 65 | }, 66 | { 67 | key: 'createTime', 68 | dataIndex: 'createTime', 69 | title: '创建时间', 70 | filterMultiple: true, 71 | filterDate: 'range', 72 | }, 73 | { 74 | key: 'operate', 75 | dataIndex: 'operate', 76 | title: '操作', 77 | fixed: 'right', 78 | width: 100, 79 | slot: 'operate', 80 | }, 81 | ], 82 | tBody: [], 83 | tPage: { 84 | total: 0, 85 | page: 1, 86 | pageSize: 10 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /src/views/mainContent/historyRecord/deleteUserList/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'name', 12 | dataIndex: 'name', 13 | title: '姓名', 14 | /*filterMultiple: true, 15 | filters: [ 16 | { 17 | value: '1', 18 | text: '用户类型1' 19 | }, 20 | { 21 | value: '2', 22 | text: '用户类型2' 23 | }, 24 | { 25 | value: '3', 26 | text: '用户类型3' 27 | } 28 | ]*/ 29 | }, 30 | { 31 | key: 'deleteReason', 32 | dataIndex: 'deleteReason', 33 | title: '删除原因', 34 | width: 100, 35 | }, 36 | { 37 | key: 'email', 38 | dataIndex: 'email', 39 | title: '邮箱', 40 | }, 41 | { 42 | key: 'address', 43 | dataIndex: 'address', 44 | title: '住址', 45 | }, 46 | { 47 | key: 'phone', 48 | dataIndex: 'phone', 49 | title: '联系电话', 50 | }, 51 | { 52 | key: 'IDCard', 53 | dataIndex: 'IDCard', 54 | title: '身份证号码', 55 | }, 56 | { 57 | key: 'userRole', 58 | dataIndex: 'userRole.name', 59 | title: '角色', 60 | filterMultiple: false, 61 | filters: [] 62 | }, 63 | { 64 | key: 'createTime', 65 | dataIndex: 'createTime', 66 | title: '创建时间', 67 | filterMultiple: true, 68 | filterDate: 'range', 69 | }, 70 | { 71 | key: 'deleteTime', 72 | dataIndex: 'deleteTime', 73 | title: '删除时间', 74 | }, 75 | { 76 | key: 'operate', 77 | dataIndex: 'operate', 78 | title: '操作', 79 | fixed: 'right', 80 | width: 100, 81 | slot: 'operate', 82 | }, 83 | ], 84 | tBody: [], 85 | tPage: { 86 | total: 0, 87 | page: 1, 88 | pageSize: 10 89 | } 90 | }; 91 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/list/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const tableData = { 4 | tHead: [ 5 | { 6 | key: 'id', 7 | title: 'id', 8 | dataIndex: 'id', 9 | }, 10 | { 11 | key: 'name', 12 | dataIndex: 'name', 13 | title: '姓名', 14 | /*filterMultiple: true, 15 | filters: [ 16 | { 17 | value: '1', 18 | text: '用户类型1' 19 | }, 20 | { 21 | value: '2', 22 | text: '用户类型2' 23 | }, 24 | { 25 | value: '3', 26 | text: '用户类型3' 27 | } 28 | ]*/ 29 | }, 30 | { 31 | key: 'password', 32 | dataIndex: 'password', 33 | title: '密码', 34 | }, 35 | { 36 | key: 'email', 37 | dataIndex: 'email', 38 | title: '邮箱', 39 | }, 40 | { 41 | key: 'address', 42 | dataIndex: 'address', 43 | title: '住址', 44 | }, 45 | { 46 | key: 'phone', 47 | dataIndex: 'phone', 48 | title: '联系电话', 49 | }, 50 | { 51 | key: 'IDCard', 52 | dataIndex: 'IDCard', 53 | title: '身份证号码', 54 | }, 55 | { 56 | key: 'userRole', 57 | dataIndex: 'userRole.name', 58 | title: '角色', 59 | filterMultiple: false, 60 | filters: [] 61 | }, 62 | { 63 | key: 'createTime', 64 | dataIndex: 'createTime', 65 | title: '创建时间', 66 | filterMultiple: true, 67 | filterDate: 'range', 68 | }, 69 | { 70 | key: 'isActive', 71 | dataIndex: 'isActive', 72 | title: '激活停用', 73 | fixed: 'right', 74 | slot: 'isActive', 75 | }, 76 | { 77 | key: 'operate', 78 | dataIndex: 'operate', 79 | title: '操作', 80 | fixed: 'right', 81 | width: 100, 82 | slot: 'operate', 83 | }, 84 | ], 85 | tBody: [], 86 | tPage: { 87 | total: 0, 88 | page: 1, 89 | pageSize: 10 90 | } 91 | }; 92 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | 23 | React App 24 | 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/list/listDetailInfo/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const detailInfoData = [ 3 | { 4 | id: 'baseInfo', 5 | title: '基本信息', 6 | data: [ 7 | { 8 | id: 'id', 9 | name: '店铺ID', 10 | value: '', 11 | type: 'input', 12 | jpath: 'id', 13 | }, 14 | { 15 | id: 'storeName', 16 | name: '店铺名称', 17 | value: '', 18 | type: 'input', 19 | jpath: 'storeName', 20 | }, 21 | { 22 | id: 'storeAge', 23 | name: '店铺年限(天)', 24 | value: '', 25 | type: 'input', 26 | jpath: 'storeAge', 27 | }, 28 | { 29 | id: 'user', 30 | name: '所属商家', 31 | value: '', 32 | type: 'input', 33 | jpath: 'user.name', 34 | }, 35 | { 36 | id: 'organizationCode', 37 | name: '组织机构代码', 38 | value: '', 39 | type: 'input', 40 | jpath: 'organizationCode', 41 | }, 42 | { 43 | id: 'address', 44 | name: '店铺地址', 45 | value: '', 46 | type: 'input', 47 | jpath: 'address', 48 | }, 49 | { 50 | id: 'category', 51 | name: '店铺分类', 52 | value: '', 53 | type: 'input', 54 | jpath: 'category.name', 55 | }, 56 | { 57 | id: 'focusNum', 58 | name: '关注量', 59 | value: '', 60 | type: 'input', 61 | jpath: 'focusNum', 62 | }, 63 | { 64 | id: 'creditGrade', 65 | name: '荣誉等级', 66 | value: '', 67 | type: 'input', 68 | jpath: 'creditGrade.name', 69 | }, 70 | { 71 | id: 'createTime', 72 | name: '创建时间', 73 | value: '', 74 | type: 'input', 75 | jpath: 'createTime', 76 | }, 77 | { 78 | id: 'businessLicenseImg', 79 | name: '营业执照', 80 | value: [], 81 | type: 'img', 82 | jpath: 'businessLicenseImg', 83 | }, 84 | ] 85 | } 86 | ]; 87 | -------------------------------------------------------------------------------- /src/components/CDetailInfo/index.scss: -------------------------------------------------------------------------------- 1 | @import "@/assets/css/var.scss"; 2 | 3 | .c-detail-info{ 4 | .c-detail-info-base-item{ 5 | margin-bottom: 20px; 6 | } 7 | } 8 | 9 | 10 | .c-detail-info-title{ 11 | justify-content: space-between; 12 | .c-detail-info-title-left{ 13 | justify-content: start; 14 | font-weight: bold; 15 | font-size: 13px; 16 | height: 40px; 17 | line-height: 40px; 18 | margin-bottom: 10px; 19 | .title-before-icon{ 20 | display: inline-block; 21 | width: 4px; 22 | height: 15px; 23 | background: $main-base-primary-color; 24 | border-radius: 2px; 25 | margin-right: 5px; 26 | } 27 | } 28 | .c-detail-info-title-right{ 29 | 30 | } 31 | } 32 | 33 | 34 | //c-detail-info-item 35 | .c-detail-info-item{ 36 | justify-content: space-between; 37 | align-items: start; 38 | padding: 10px 20px; 39 | .info-col{ 40 | width: 47%; 41 | .info-row{ 42 | justify-content: start; 43 | .info-row-label{ 44 | border: 1px solid #ebedf0; 45 | border-bottom: none; 46 | border-right: none; 47 | width: 100px; 48 | height: 35px; 49 | line-height: 35px; 50 | padding: 0 8px; 51 | font-size: 13px; 52 | font-weight: bold; 53 | } 54 | .info-row-content{ 55 | border: 1px solid #ebedf0; 56 | border-bottom: none; 57 | width: calc(100% - 100px); 58 | height: 35px; 59 | line-height: 35px; 60 | padding: 0 8px; 61 | font-size: 13px; 62 | .none-value{ 63 | color: #999999; 64 | } 65 | } 66 | &:nth-last-of-type(1){ 67 | .info-row-label, .info-row-content{ 68 | border-bottom: 1px solid #ebedf0; 69 | } 70 | } 71 | .img-look{ 72 | color: $main-base-primary-color; 73 | cursor: pointer; 74 | } 75 | } 76 | } 77 | .info-col-one{ 78 | 79 | } 80 | .info-col-two{ 81 | 82 | } 83 | .info-col-null{ 84 | width: 6%; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/CForm/CSelect.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Select, TreeSelect} from 'antd' 4 | import './index.scss' 5 | const { Option} = Select 6 | 7 | class CSelect extends Component{ 8 | 9 | state = { 10 | value: undefined 11 | }; 12 | 13 | changeHandler(value){ 14 | this.setState({ 15 | value: value 16 | }); 17 | this.props.onChange && this.props.onChange(value); 18 | } 19 | 20 | searchHandler(value){ 21 | this.props.onSearch && this.props.onSearch(value); 22 | } 23 | 24 | componentWillReceiveProps(nextProps) { 25 | let defaultValue = !nextProps.value ? undefined : nextProps.value; 26 | this.setState({ 27 | value: defaultValue 28 | }) 29 | } 30 | 31 | componentWillMount(){ 32 | let defaultValue = !this.props.value ? undefined : this.props.value; 33 | this.setState({ 34 | value: this.props.value || defaultValue 35 | }) 36 | } 37 | 38 | render(){ 39 | const {type, options, style, onSearch, onChange, ...props} = this.props; 40 | const SelectDom = type === 'treeSelect' ? TreeSelect : Select; 41 | return ( 42 | this.searchHandler(value)} 47 | onChange={(value) => this.changeHandler(value)}> 48 | { 49 | type === 'select' && options.map((item, index)=>{ 50 | return 51 | }) 52 | } 53 | 54 | ) 55 | } 56 | } 57 | 58 | CSelect.defaultProps = { 59 | type: 'select', 60 | options: [], 61 | style: {}, 62 | }; 63 | 64 | CSelect.propTypes = { 65 | type: PropTypes.string, 66 | options: PropTypes.array, 67 | onChange: PropTypes.func, 68 | onSearch: PropTypes.func, 69 | style: PropTypes.object, 70 | }; 71 | 72 | export default CSelect 73 | -------------------------------------------------------------------------------- /src/components/CForm/CDatePicker.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import PropTypes from 'prop-types' 3 | import _ from 'lodash' 4 | import { DatePicker} from 'antd' 5 | import moment from 'moment' 6 | import locale from 'antd/lib/date-picker/locale/zh_CN' 7 | import './index.scss' 8 | 9 | class CDatePicker extends Component{ 10 | 11 | constructor(props) { 12 | super(props); 13 | this.changeHandler = this.changeHandler.bind(this); 14 | this.valueFormat = this.valueFormat.bind(this); 15 | } 16 | 17 | 18 | state = { 19 | value: null, 20 | dateType: { 21 | 'mouth': 'MonthPicker', 22 | 'range': 'RangePicker', 23 | 'week': 'WeekPicker ' 24 | }, 25 | dateFormat: 'YYYY-MM-DD HH:mm:ss' 26 | }; 27 | 28 | componentWillReceiveProps(nextProps) { 29 | if(nextProps.hasOwnProperty('value')){ 30 | this.valueFormat(nextProps.value); 31 | } 32 | } 33 | 34 | valueFormat(value){ 35 | if(_.isString(value)){ 36 | value = value ? moment(value, this.state.dateFormat) : null; 37 | } 38 | if(_.isArray(value)){ 39 | value = value.length ? [moment(value[0], this.state.dateFormat),moment(value[1], this.state.dateFormat)] : null; 40 | } 41 | this.setState({ 42 | value: value 43 | }) 44 | } 45 | 46 | changeHandler(date, dateString){ 47 | this.valueFormat(dateString); 48 | this.props.onChange && this.props.onChange(dateString); 49 | } 50 | 51 | componentWillMount(){ 52 | this.valueFormat(this.props.value); 53 | } 54 | 55 | render(){ 56 | const {type, value, onChange, className, ...props} = this.props; 57 | const DatePickerDom = this.state.dateType[type] ? DatePicker[this.state.dateType[type]] : DatePicker; 58 | return ( 59 | this.changeHandler(date, dateString)}/> 60 | ) 61 | } 62 | } 63 | 64 | CDatePicker.propTypes = { 65 | onChange: PropTypes.func, 66 | }; 67 | 68 | export default CDatePicker 69 | -------------------------------------------------------------------------------- /src/routers/userManageRouter.js: -------------------------------------------------------------------------------- 1 | 2 | import userManage from '@/views/mainContent/userManage' 3 | import userManageEcharts from '@/views/mainContent/userManage/echarts' 4 | import userManageGrade from '@/views/mainContent/userManage/grade' 5 | 6 | import userManageList from '@/views/mainContent/userManage/list' 7 | import userManageListNew from '@/views/mainContent/userManage/list/listNew' 8 | import userManageListDetail from '@/views/mainContent/userManage/list/listDetailInfo' 9 | 10 | import userManageAdminList from '@/views/mainContent/userManage/adminList' 11 | import userManageAdminListNew from '@/views/mainContent/userManage/adminList/listNew' 12 | import userManageAdminListDetail from '@/views/mainContent/userManage/adminList/listDetailInfo' 13 | 14 | import userManageMemer from '@/views/mainContent/userManage/member' 15 | 16 | export default { 17 | path: '/userManage', 18 | component: userManage, 19 | exact: true, 20 | children: [ 21 | { 22 | path: '/userManage/echarts', 23 | component: userManageEcharts, 24 | exact: true, 25 | }, 26 | { 27 | path: '/userManage/list', 28 | component: userManageList, 29 | exact: true, 30 | }, 31 | { 32 | path: '/userManage/list/new', 33 | component: userManageListNew, 34 | exact: true, 35 | }, 36 | { 37 | path: '/userManage/list/detail', 38 | component: userManageListDetail, 39 | exact: true, 40 | }, 41 | { 42 | path: '/userManage/admin', 43 | component: userManageAdminList, 44 | exact: true, 45 | }, 46 | { 47 | path: '/userManage/admin/new', 48 | component: userManageAdminListNew, 49 | exact: true, 50 | }, 51 | { 52 | path: '/userManage/admin/detail', 53 | component: userManageAdminListDetail, 54 | exact: true, 55 | }, 56 | { 57 | path: '/userManage/grade', 58 | component: userManageGrade, 59 | exact: true, 60 | }, 61 | { 62 | path: '/userManage/member', 63 | component: userManageMemer, 64 | exact: true, 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /src/views/mainContent/personal/percentageEcharts.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CEcharts from '@/components/CEcharts' 3 | import InfoTitle from '@/components/CDetailInfo/detailInfoTitle' 4 | import CBaseComponent from '@/components/CBaseComponent' 5 | // import Echarts from 'echarts' 6 | // import _ from 'lodash' 7 | 8 | @CBaseComponent 9 | class PercentageEcharts extends Component{ 10 | constructor(props) { 11 | super(props); 12 | this.initOptions = this.initOptions.bind(this); 13 | } 14 | 15 | state = { 16 | options: { 17 | backgroundColor: '#1b2735', 18 | title: { 19 | text: 'CPU使用率', 20 | textStyle: { 21 | fontWeight: 'normal', 22 | fontSize: 25, 23 | color: 'rgb(97, 142, 205)' 24 | } 25 | }, 26 | series: [{ 27 | type: 'liquidFill', 28 | radius: '80%', 29 | data: [0.3, 0.3, 0.3, 0.3, 0.3], 30 | backgroundStyle: { 31 | borderWidth: 5, 32 | borderColor: 'rgb(255,0,255,0.9)', 33 | color: 'rgb(255,0,255,0.01)' 34 | }, 35 | label: { 36 | normal: { 37 | formatter: (0.3 * 100).toFixed(2) + '%', 38 | textStyle: { 39 | fontSize: 50 40 | } 41 | } 42 | } 43 | }] 44 | } 45 | } 46 | 47 | initOptions(data){ 48 | // if(data) { 49 | // let options = _.cloneDeep(this.state.options); 50 | // options.series[0].data = data; 51 | // this.setState({ 52 | // options: options 53 | // }) 54 | // } 55 | } 56 | 57 | componentWillReceiveProps(nextProps){ 58 | // this.initOptions(nextProps.data) 59 | } 60 | 61 | componentDidMount(){ 62 | // this.initOptions(this.props.data); 63 | } 64 | 65 | render(){ 66 | return ( 67 |
68 | 69 | {this.props.children} 70 | 71 | 72 |
73 | ) 74 | } 75 | } 76 | 77 | export default PercentageEcharts 78 | -------------------------------------------------------------------------------- /src/routers/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { HashRouter, Route, Switch} from 'react-router-dom'; 3 | 4 | import App from "@/views/App"; 5 | import Login from "@/views/login"; 6 | import MainContent from "@/views/mainContent"; 7 | 8 | 9 | import homeRouter from './homeRouter' 10 | import userManageRouter from './userManageRouter' 11 | import storeManageRouter from './storeManageRouter' 12 | import authManageRouter from './authManageRouter' 13 | import goodsManageRouter from './goodsManageRouter' 14 | import historyRecordRouter from './historyRecordRouter' 15 | import personalRouter from './personalRouter' 16 | 17 | const routers = [ 18 | homeRouter, 19 | userManageRouter, 20 | storeManageRouter, 21 | authManageRouter, 22 | goodsManageRouter, 23 | historyRecordRouter, 24 | personalRouter 25 | ]; 26 | 27 | const renderRoutes = (routers) => { 28 | return routers.map((item, index)=>{ 29 | if(item.children){ 30 | let Com = item.component; 31 | return ( 32 | 33 | {renderRoutes(item.children)} 34 | 35 | ) 36 | }else{ 37 | return ( 38 | 39 | ) 40 | } 41 | }) 42 | }; 43 | /*{item.children && renderRoutes(item.children)})*/ 44 | 45 | 46 | export default class RouteConfig extends Component{ 47 | render(){ 48 | return ( 49 | 50 | 51 | 52 | {/**/} 53 | {/* */} 54 | {/* */} 55 | {/* {renderRoutes(routers)}*/} 56 | {/* */} 57 | {/* */} 58 | {/*}>*/} 59 | {/**/} 60 | 61 | 62 | {renderRoutes(routers)} 63 | 64 | 65 | 66 | 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/list/listDetailInfo/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CDetailInfo from '@/components/CDetailInfo' 3 | import CAvatar from '@/components/CAvatar' 4 | import CTable from '@/components/CTable' 5 | import CBaseComponent from '@/components/CBaseComponent' 6 | import { detailInfoData, detailTableData} from "./data"; 7 | import { detailUserList} from "@/servers/userManageApi"; 8 | import { urlFormat, setPageNewValue} from "@/utils"; 9 | 10 | @CBaseComponent 11 | class UserManageListDetailInfo extends Component{ 12 | constructor(props) { 13 | super(props); 14 | this.getUserDetailData = this.getUserDetailData.bind(this); 15 | } 16 | 17 | 18 | state = { 19 | data: detailInfoData, 20 | columns: detailTableData.tHead, 21 | dataSource: detailTableData.tBody, 22 | avatar: { 23 | img: '', 24 | title: '', 25 | description: '' 26 | } 27 | }; 28 | 29 | getUserDetailData(){ 30 | let id = urlFormat(this.props.history.location.search).query.id; 31 | detailUserList({id}).then(res=>{ 32 | let userInfo = res.data.userInfo; 33 | userInfo.latlong = userInfo.latlong.join(',');//经纬度分割成字符串 34 | let storeList = res.data.storeList; 35 | let data = setPageNewValue(this.state.data, userInfo); 36 | this.setState({ 37 | data: data, 38 | dataSource: storeList, 39 | avatar: { 40 | img: userInfo.avatar && userInfo.avatar.url, 41 | title: userInfo.name, 42 | description: '' 43 | } 44 | }) 45 | }).catch(err=>{ 46 | 47 | }) 48 | } 49 | 50 | componentDidMount(){ 51 | this.getUserDetailData(); 52 | } 53 | 54 | render(){ 55 | return ( 56 | <> 57 | 58 | 59 |
60 | 61 |
62 |
63 | 64 | ) 65 | } 66 | } 67 | 68 | export default UserManageListDetailInfo 69 | -------------------------------------------------------------------------------- /src/components/CSwiper/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types' 3 | // import Swiper from 'swiper' 4 | import Swiper from 'swiper/dist/js/swiper.js' 5 | import 'swiper/dist/css/swiper.min.css' 6 | import './index.scss' 7 | 8 | class CSwiper extends Component{ 9 | 10 | constructor(props) { 11 | super(props); 12 | this.initSwiper = this.initSwiper.bind(this); 13 | } 14 | 15 | 16 | state = { 17 | swiper: null, 18 | options: { 19 | autoplay: { 20 | disableOnInteraction: false, 21 | }, 22 | loop: true, //循环 23 | navigation: { 24 | nextEl: '.swiper-button-next', 25 | prevEl: '.swiper-button-prev', 26 | }, 27 | pagination: { 28 | el: '.swiper-pagination', 29 | clickable :true, 30 | }, 31 | } 32 | }; 33 | 34 | initSwiper(){ 35 | let swiper = new Swiper('.c-swiper-container',this.state.options); 36 | this.setState({ 37 | swiper: swiper 38 | }) 39 | } 40 | 41 | componentWillMount(){ 42 | this.setState({ 43 | options: {...this.state.options, ...this.props.options} 44 | }) 45 | } 46 | 47 | componentDidMount(){ 48 | this.initSwiper(); 49 | } 50 | 51 | render(){ 52 | return ( 53 |
54 |
55 |
56 | { 57 | this.props.data.map((swiperItem, swiperIndex) => { 58 | return
59 | 60 |
61 | }) 62 | } 63 |
64 | 65 | {/*前后切换按钮*/} 66 |
67 |
68 | 69 | {/*分页器*/} 70 |
71 |
72 |
73 | ) 74 | } 75 | } 76 | 77 | CSwiper.defaultProps = { 78 | data: [] 79 | }; 80 | 81 | CSwiper.propTypes = { 82 | data: PropTypes.array, 83 | options: PropTypes.object, 84 | }; 85 | 86 | export default CSwiper 87 | -------------------------------------------------------------------------------- /src/components/CPage/index.js: -------------------------------------------------------------------------------- 1 | 2 | import React, {Component} from 'react' 3 | import { Pagination } from 'antd'; 4 | import PropTypes from 'prop-types' 5 | 6 | import './index.scss' 7 | 8 | class CPage extends Component{ 9 | 10 | state = { 11 | page: 1, 12 | pageSize: 10, 13 | total: 0 14 | } 15 | 16 | componentWillReceiveProps(nextProps) { 17 | this.setState({ 18 | page: nextProps.page || 1, 19 | pageSize: nextProps.pageSize || 10, 20 | total: nextProps.total || 0 21 | }); 22 | } 23 | 24 | onShowSizeChange(current, pageSize){ 25 | this.setState({ 26 | page: current, 27 | pageSize: pageSize 28 | }); 29 | let data = { 30 | type: 'pageSize', 31 | data: { 32 | page: current, 33 | pageSize: pageSize 34 | } 35 | }; 36 | this.props.onPageChange && this.props.onPageChange(data); 37 | } 38 | 39 | onChange(page, pageSize){ 40 | this.setState({ 41 | page: page, 42 | pageSize: pageSize 43 | }); 44 | let data = { 45 | type: 'page', 46 | data: { 47 | page: page, 48 | pageSize: pageSize 49 | } 50 | }; 51 | this.props.onPageChange && this.props.onPageChange(data); 52 | } 53 | 54 | componentWillMount(){ 55 | this.setState({ 56 | page: this.props.page || 1, 57 | pageSize: this.props.pageSize || 10, 58 | total: this.props.total || 0 59 | }); 60 | } 61 | 62 | render(){ 63 | const {page, ...props} = this.props; 64 | return ( 65 | this.onChange(page, pageSize)} 71 | onShowSizeChange={(current, pageSize) => this.onShowSizeChange(current, pageSize)}/> 72 | ) 73 | } 74 | } 75 | 76 | CPage.defaultProps = { 77 | total: 0, 78 | page: 1, 79 | pageSize: 10, 80 | showSizeChanger: true, 81 | showQuickJumper: true, 82 | size: 'small', 83 | showTotal: total => `共 ${total} 条`, 84 | } 85 | 86 | CPage.propTypes = { 87 | total: PropTypes.number, 88 | page: PropTypes.number, 89 | pageSize: PropTypes.number, 90 | } 91 | 92 | 93 | export default CPage 94 | -------------------------------------------------------------------------------- /src/mock/userManage/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import { formatURL} from '../index' 3 | 4 | // 商家用户 5 | import { 6 | deleteUserManage, 7 | getUserManageList, 8 | insertUserManage, 9 | detailUserManage, 10 | editUserManage, 11 | editActiveUser, 12 | getUserManageDeleteList, 13 | resetDeleteUser, 14 | deletePermanentUser} from "./userList"; 15 | 16 | // 管理员用户 17 | import { 18 | deleteUserManageAdmin, 19 | getUserManageAdminList, 20 | insertUserManageAdmin, 21 | detailUserManageAdmin, 22 | editUserManageAdmin, 23 | getUserManageDeleteAdminList, 24 | resetDeleteAdminUser, 25 | deletePermanentAdminUser} from "./adminList"; 26 | 27 | /*获取商家用户数据*/ 28 | Mock.mock(formatURL('/userManage/userList/get'), 'get', getUserManageList); 29 | // 删除商家用户 30 | Mock.mock(formatURL('/userManage/userList/delete'), 'post', deleteUserManage); 31 | // 新建商家用户 32 | Mock.mock(formatURL('/userManage/userList/insert'), 'post', insertUserManage); 33 | // 编辑商家用户 34 | Mock.mock(formatURL('/userManage/userList/edit'), 'post', editUserManage); 35 | // 获取用户详情 36 | Mock.mock(formatURL('/userManage/userList/detail'), 'get', detailUserManage); 37 | // 激活停用 38 | Mock.mock(formatURL('/userManage/userList/active'), 'post', editActiveUser); 39 | /*获取已删除的商家用户数据*/ 40 | Mock.mock(formatURL('/historyRecord/deleteUserList/get'), 'get', getUserManageDeleteList); 41 | // 恢复已删除用户 42 | Mock.mock(formatURL('/historyRecord/deleteUserList/reset'), 'post', resetDeleteUser); 43 | // 永久删除用户 44 | Mock.mock(formatURL('/historyRecord/deleteUserList/delete'), 'post', deletePermanentUser); 45 | 46 | 47 | /*获取管理员用户数据*/ 48 | Mock.mock(formatURL('/userManage/adminList/get'), 'get', getUserManageAdminList); 49 | // 删除管理员用户 50 | Mock.mock(formatURL('/userManage/adminList/delete'), 'post', deleteUserManageAdmin); 51 | // 新建管理员用户 52 | Mock.mock(formatURL('/userManage/adminList/insert'), 'post', insertUserManageAdmin); 53 | // 编辑管理员用户 54 | Mock.mock(formatURL('/userManage/adminList/edit'), 'post', editUserManageAdmin); 55 | // 获取管理员用户详情 56 | Mock.mock(formatURL('/userManage/adminList/detail'), 'get', detailUserManageAdmin); 57 | /*获取已删除的系统用户数据*/ 58 | Mock.mock(formatURL('/historyRecord/deleteAdminUserList/get'), 'get', getUserManageDeleteAdminList); 59 | // 恢复已删除系统用户 60 | Mock.mock(formatURL('/historyRecord/deleteAdminUserList/reset'), 'post', resetDeleteAdminUser); 61 | // 永久删除系统用户 62 | Mock.mock(formatURL('/historyRecord/deleteAdminUserList/delete'), 'post', deletePermanentAdminUser); 63 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/listDetailInfo/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const detailInfoData = [ 3 | { 4 | id: 'baseInfo', 5 | title: '基本信息', 6 | data: [ 7 | { 8 | id: 'id', 9 | name: '商品ID', 10 | value: '', 11 | type: 'input', 12 | jpath: 'id', 13 | }, 14 | { 15 | id: 'name', 16 | name: '商品名称', 17 | value: '', 18 | type: 'input', 19 | jpath: 'name', 20 | }, 21 | { 22 | id: 'storeInfo', 23 | name: '所属店铺', 24 | value: '', 25 | type: 'input', 26 | jpath: 'storeInfo.storeName', 27 | }, 28 | { 29 | id: 'description', 30 | name: '商品描述', 31 | value: '', 32 | type: 'input', 33 | jpath: 'description', 34 | }, 35 | { 36 | id: 'category', 37 | name: '所属分类', 38 | value: '', 39 | type: 'input', 40 | jpath: 'category', 41 | }, 42 | { 43 | id: 'price', 44 | name: '价格', 45 | value: '', 46 | type: 'input', 47 | jpath: 'price', 48 | }, 49 | { 50 | id: 'stockNum', 51 | name: '库存', 52 | value: '', 53 | type: 'input', 54 | jpath: 'stockNum', 55 | }, 56 | { 57 | id: 'tradingTotalNum', 58 | name: '总交易数量', 59 | value: '', 60 | type: 'input', 61 | jpath: 'tradingTotalNum', 62 | }, 63 | { 64 | id: 'tradingMonthNum', 65 | name: '月交易数量', 66 | value: '', 67 | type: 'input', 68 | jpath: 'tradingMonthNum', 69 | }, 70 | { 71 | id: 'tradingDayNum', 72 | name: '日交易数量', 73 | value: '', 74 | type: 'input', 75 | jpath: 'tradingDayNum', 76 | }, 77 | { 78 | id: 'commitGoodRate', 79 | name: '好评率', 80 | value: '', 81 | type: 'input', 82 | jpath: 'commitGoodRate', 83 | }, 84 | { 85 | id: 'createTime', 86 | name: '创建时间', 87 | value: '', 88 | type: 'input', 89 | jpath: 'createTime', 90 | }, 91 | { 92 | id: 'imgs', 93 | name: '商品图片', 94 | value: [], 95 | type: 'img', 96 | jpath: 'imgs', 97 | }, 98 | ] 99 | } 100 | ]; 101 | -------------------------------------------------------------------------------- /src/views/mainContent/home/data.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CButton from "../../../components/CButton"; 3 | 4 | export const tableData = { 5 | tHead: [ 6 | { 7 | key: 'key', 8 | title: 'key', 9 | dataIndex: 'key', 10 | }, 11 | { 12 | key: 'name', 13 | dataIndex: 'name', 14 | title: 'name', 15 | filterMultiple: false, 16 | filters: [ 17 | { 18 | value: '1', 19 | text: '用户类型1' 20 | }, 21 | { 22 | value: '2', 23 | text: '用户类型2' 24 | }, 25 | { 26 | value: '3', 27 | text: '用户类型3' 28 | } 29 | ] 30 | }, 31 | { 32 | key: 'address', 33 | dataIndex: 'address', 34 | title: 'address', 35 | filterMultiple: true, 36 | filters: [ 37 | { 38 | value: '1', 39 | text: '用户类型1' 40 | }, 41 | { 42 | value: '2', 43 | text: '用户类型2' 44 | }, 45 | { 46 | value: '3', 47 | text: '用户类型3' 48 | } 49 | ] 50 | }, 51 | { 52 | key: 'phone', 53 | dataIndex: 'phone', 54 | title: 'phone', 55 | filterMultiple: true, 56 | filters: [ 57 | { 58 | value: '1', 59 | text: '用户类型1' 60 | }, 61 | { 62 | value: '2', 63 | text: '用户类型2' 64 | }, 65 | { 66 | value: '3', 67 | text: '用户类型3' 68 | } 69 | ] 70 | }, 71 | { 72 | key: 'IDCard', 73 | dataIndex: 'IDCard', 74 | title: 'IDCard', 75 | filterMultiple: true, 76 | filters: [ 77 | { 78 | value: '1', 79 | text: '用户类型1' 80 | }, 81 | { 82 | value: '2', 83 | text: '用户类型2' 84 | }, 85 | { 86 | value: '3', 87 | text: '用户类型3' 88 | } 89 | ] 90 | }, 91 | { 92 | key: 'operate', 93 | dataIndex: 'operate', 94 | title: '操作', 95 | width: 60, 96 | render: () => 查看, 97 | } 98 | ], 99 | tBody: [ 100 | { 101 | key: '1', 102 | name: '111', 103 | age: '222', 104 | grade: '333', 105 | checked: true 106 | } 107 | ], 108 | tPage: { 109 | total: 0, 110 | page: 1, 111 | pageSize: 10 112 | } 113 | }; 114 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/CForm/validate.js: -------------------------------------------------------------------------------- 1 | 2 | const validateStatus = { 3 | error: 'error', 4 | success: 'success', 5 | warning: 'warning', 6 | validating: 'validating', 7 | }; 8 | 9 | const baseInfo = { 10 | required: '必填项', 11 | email: '邮箱格式不正确', 12 | card: '身份证号码格式不正确', 13 | phone: '手机号码格式不正确', 14 | maxLength: '最大长度', 15 | minLength: '最小长度', 16 | }; 17 | 18 | const baseReg = { 19 | email: /^([A-Za-z0-9_\-.])+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]{2,8})+$/, 20 | card: /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/, 21 | phone: /^((13|14|15|16|17|18|19)[0-9]{1}\d{8})$/, 22 | }; 23 | 24 | const baseData = { 25 | validate: true, 26 | info: '', 27 | validateStatus: '' 28 | }; 29 | 30 | /*必填项*/ 31 | const required = (value) => { 32 | if(!value || (value instanceof Array && !value.length)){ 33 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: baseInfo.required} 34 | } 35 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 36 | }; 37 | 38 | /*邮箱验证*/ 39 | const email = (value) => { 40 | if(!baseReg.email.test(value)){ 41 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: baseInfo.email} 42 | } 43 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 44 | }; 45 | 46 | /*身份证号验证*/ 47 | const card = (value) => { 48 | if(!baseReg.card.test(value)){ 49 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: baseInfo.card} 50 | } 51 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 52 | }; 53 | 54 | /*手机号码验证*/ 55 | const phone = (value) => { 56 | if(!baseReg.phone.test(value)){ 57 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: baseInfo.phone} 58 | } 59 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 60 | }; 61 | 62 | /*字符最大长度验证*/ 63 | const maxLength = (value, checkArg) => { 64 | if(value.length > Number(checkArg)){ 65 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: `${baseInfo.maxLength}${checkArg}`} 66 | } 67 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 68 | }; 69 | 70 | /*字符最小长度验证*/ 71 | const minLength = (value, checkArg) => { 72 | if(value.length < Number(checkArg)){ 73 | return { ...baseData, validateStatus: validateStatus.error, validate: false, info: `${baseInfo.minLength}${checkArg}`} 74 | } 75 | return { ...baseData, validateStatus: '', validate: true, info: ''}; 76 | }; 77 | 78 | export default { 79 | required, 80 | email, 81 | card, 82 | phone, 83 | maxLength, 84 | minLength, 85 | }; 86 | -------------------------------------------------------------------------------- /src/assets/css/var.scss: -------------------------------------------------------------------------------- 1 | 2 | @import "./themeFn.scss"; 3 | 4 | 5 | 6 | /*BACKGDROUND*/ 7 | $main-background-color: #f1f1f1; 8 | $main-base-color: rgba(0, 150, 136, 1); 9 | $main-base-primary-color: rgba(30, 159, 255, 1); 10 | 11 | /*TEXT COLOR*/ 12 | $text-color-base: #666666; 13 | $text-color-white: #ffffff; 14 | $text-color-label: #333333; 15 | 16 | /*BUTTON COLOR*/ 17 | $button-primary-background-color: rgba(30, 159, 255, 1); 18 | $button-primary-hover-background-color: rgba(30, 159, 255, 0.8); 19 | $button-danger-background-color: rgba(255, 87, 34, 1); 20 | $button-danger-hover-background-color: rgba(255, 87, 34, 0.8); 21 | $button-c-success-background-color: rgba(0, 150, 136, 1); 22 | $button-c-success-hover-background-color: rgba(0, 150, 136, 0.8); 23 | $button-warning-background-color: rgba(255, 128, 82, 1); 24 | $button-warning-hover-background-color: rgba(255, 128, 82, 0.8); 25 | $button-success-background-color: rgba(103, 194, 58, 1); 26 | $button-success-hover-background-color: rgba(103, 194, 58, 0.8); 27 | $button-default-background-color: rgba(255, 255, 255, 1); 28 | $button-default-hover-background-color: rgba(255, 255, 255, 1); 29 | $button-disabled-background-color: rgba(245, 245, 245, 1); 30 | $button-primary-text-color: $text-color-white; 31 | $button-danger-text-color: $text-color-white; 32 | $button-warning-text-color: $text-color-white; 33 | $button-success-text-color: $text-color-white; 34 | $button-c-success-text-color: $text-color-white; 35 | $button-default-text-color: $text-color-base; 36 | $button-disabled-text-color: $text-color-base; 37 | $button-hover-text-color: rgba(30, 159, 255, 1); 38 | $button-border-radius: 2px; 39 | $button-primary-border-color: rgba(30, 159, 255, 1); 40 | $button-danger-border-color: rgba(255, 87, 34, 1); 41 | $button-success-border-color: rgba(103, 194, 58, 1); 42 | $button-c-success-border-color: rgba(0, 150, 136, 1); 43 | $button-warning-border-color: rgba(255, 128, 82, 1); 44 | $button-default-border-color: #d9d9d9; 45 | $button-border-hover-color: rgba(30, 159, 255, 1); 46 | $button-size-small: 28px; 47 | $button-size-default: 30px; 48 | $button-size-larger: 32px; 49 | $button-size-small-font-size: 12px; 50 | $button-size-default-font-size: 12px; 51 | $button-size-larger-font-size: 13px; 52 | 53 | 54 | /*HEAD STYLE*/ 55 | $header-background: $default-theme-header-background-color; 56 | $header-height: 45px; 57 | 58 | /*LEFTNAV STYLE*/ 59 | $left-nav-background-color: $default-theme-left-nav-background-color; 60 | $left-nav-children-background-color: $default-theme-left-nav-children-background-color; 61 | $left-nav-active-background-color: $default-theme-left-nav-active-background-color; 62 | $left-nav-active-border-color: $default-theme-left-nav-active-border-color; 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /config/modules.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const paths = require('./paths'); 6 | const chalk = require('react-dev-utils/chalk'); 7 | 8 | /** 9 | * Get the baseUrl of a compilerOptions object. 10 | * 11 | * @param {Object} options 12 | */ 13 | function getAdditionalModulePaths(options = {}) { 14 | const baseUrl = options.baseUrl; 15 | 16 | // We need to explicitly check for null and undefined (and not a falsy value) because 17 | // TypeScript treats an empty string as `.`. 18 | if (baseUrl == null) { 19 | // If there's no baseUrl set we respect NODE_PATH 20 | // Note that NODE_PATH is deprecated and will be removed 21 | // in the next major release of create-react-app. 22 | 23 | const nodePath = process.env.NODE_PATH || ''; 24 | return nodePath.split(path.delimiter).filter(Boolean); 25 | } 26 | 27 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl); 28 | 29 | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is 30 | // the default behavior. 31 | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') { 32 | return null; 33 | } 34 | 35 | // Allow the user set the `baseUrl` to `appSrc`. 36 | if (path.relative(paths.appSrc, baseUrlResolved) === '') { 37 | return [paths.appSrc]; 38 | } 39 | 40 | // Otherwise, throw an error. 41 | throw new Error( 42 | chalk.red.bold( 43 | "Your project's `baseUrl` can only be set to `src` or `node_modules`." + 44 | ' Create React App does not support other values at this time.' 45 | ) 46 | ); 47 | } 48 | 49 | function getModules() { 50 | // Check if TypeScript is setup 51 | const hasTsConfig = fs.existsSync(paths.appTsConfig); 52 | const hasJsConfig = fs.existsSync(paths.appJsConfig); 53 | 54 | if (hasTsConfig && hasJsConfig) { 55 | throw new Error( 56 | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.' 57 | ); 58 | } 59 | 60 | let config; 61 | 62 | // If there's a tsconfig.json we assume it's a 63 | // TypeScript project and set up the config 64 | // based on tsconfig.json 65 | if (hasTsConfig) { 66 | config = require(paths.appTsConfig); 67 | // Otherwise we'll check if there is jsconfig.json 68 | // for non TS projects. 69 | } else if (hasJsConfig) { 70 | config = require(paths.appJsConfig); 71 | } 72 | 73 | config = config || {}; 74 | const options = config.compilerOptions || {}; 75 | 76 | const additionalModulePaths = getAdditionalModulePaths(options); 77 | 78 | return { 79 | additionalModulePaths: additionalModulePaths, 80 | hasTsConfig, 81 | }; 82 | } 83 | 84 | module.exports = getModules(); 85 | -------------------------------------------------------------------------------- /src/servers/index.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios' 2 | import config from '@/config' 3 | 4 | const axios = Axios.create(); 5 | const CancelToken = Axios.CancelToken; 6 | const baseURL = config.mock ? '/mock' : '/api'; 7 | let cancel_list = []; 8 | 9 | // axios默认配置 10 | axios.defaults.baseURL = baseURL; 11 | axios.defaults.timeout = 180000; //3min 12 | 13 | // axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; 14 | // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; 15 | 16 | 17 | 18 | // 请求拦截器 19 | axios.interceptors.request.use(function (config) { 20 | // 在发送请求之前做些什么 21 | // 删除get参数中为空的参数 22 | if(config.params){ 23 | Object.keys(config.params).forEach(key=>{ 24 | if(typeof config.params[key] == 'number' && !config.params[key].toString()){ 25 | delete config.params[key] 26 | }else if(typeof config.params[key] == 'string' && !config.params[key]){ 27 | delete config.params[key] 28 | } 29 | }) 30 | } 31 | return config; 32 | }, function (error) { 33 | // 对请求错误做些什么 34 | return Promise.reject(error); 35 | }); 36 | 37 | 38 | // 响应拦截器 39 | axios.interceptors.response.use(function (response) { 40 | // 对响应数据做点什么 41 | if (response.status === 200) { 42 | return Promise.resolve(response.data); 43 | } else { 44 | return Promise.reject(response.data); 45 | } 46 | // return response; 47 | }, function (error) { 48 | 49 | // 对响应错误做点什么 50 | // console.log(error.response,'error') 51 | // console.log(error.response.data); 52 | // console.log(error.response.status); 53 | // console.log(error.response.headers); 54 | 55 | return Promise.reject(error && error.response && error.response.data); 56 | }); 57 | 58 | 59 | 60 | 61 | // 该方法会取消所有正在进行的请求 62 | export const ajax_abort_all = () => { 63 | cancel_list.forEach(item=>{ 64 | item(); 65 | }); 66 | cancel_list = []; 67 | }; 68 | 69 | export const ajax_all = (method, url, params, data) => { 70 | return axios({ 71 | method, 72 | url, 73 | params, 74 | data, 75 | cancelToken: new CancelToken(function (cancel) { 76 | cancel_list.push(cancel); 77 | }) 78 | }).then(response=>{ 79 | return Promise.resolve(response) 80 | }).catch(error=>{ 81 | return Promise.reject(error) 82 | }); 83 | }; 84 | 85 | 86 | export const ajax_get = (url, params) => { 87 | return ajax_all('get', url, params); 88 | }; 89 | 90 | export const ajax_post = (url, data) => { 91 | return ajax_all('post', url, {}, data); 92 | }; 93 | 94 | export const ajax_put = (url, data) => { 95 | return ajax_all('put', url, {}, data); 96 | }; 97 | 98 | export const ajax_delete = (url, data) => { 99 | return ajax_all('delete', url, {}, data); 100 | }; 101 | 102 | -------------------------------------------------------------------------------- /src/mock/userManage/schema.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import * as commonData from '../commonData' 3 | import commonSchema from '../commonSchema' 4 | import {randomLongLat} from "../commonUtils"; 5 | 6 | // const Random = Mock.Random; 7 | 8 | /*商家用户列表数据*/ 9 | const busniessList = { 10 | 'list|30-100':[ 11 | { 12 | 'id|+1': 1, 13 | 'name': '@CNAME',//真实用户姓名 14 | 'password': '123456',//登录密码 15 | 'sex|1': commonData.data.sex,//性别 16 | 'IDCard': /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/,//身份证号 17 | 'IDCardPicture|1': commonData.data.images.IDCardPicture,//身份证照片正反面 18 | 'userRole|1': commonData.data.userRole,//用户角色 19 | 'phone': /^1[3456789]\d{9}$/,//手机号 20 | 'avatar|1': commonData.data.images.avatar,//头像 21 | 'email': '@EMAIL',//邮箱 22 | 'address': '@COUNTY(true)',//住址 23 | 'latlong': function () { 24 | return randomLongLat([87.9345703125,118.5644531250], [21.8614987344,42.0329743324]); 25 | },//经纬度 26 | 'storeNum|0-10': 0,//店铺数量 27 | 'isDelete': '@boolean',//是否是删除的用户 28 | 'isActive': '@boolean',//激活停用 29 | 'deleteReason': '已到期',//删除原因 30 | 'createTime': '@datetime',//创建时间 31 | 'deleteTime': '@datetime',//删除时间 32 | } 33 | ] 34 | }; 35 | 36 | /*管理员用户列表数据*/ 37 | const adminList = { 38 | 'list|30-100':[ 39 | { 40 | 'id|+1': 1, 41 | 'name': '@CNAME',//真实用户姓名 42 | 'password': '123456',//登录密码 43 | 'sex|1': commonData.data.sex,//性别 44 | 'userRole|1': commonSchema.adminRoleList,//用户角色 45 | 'phone': /^1[3456789]\d{9}$/,//手机号 46 | 'avatar|1': commonData.data.images.avatar,//头像 47 | 'email': '@EMAIL',//邮箱 48 | 'isDelete': '@boolean',//是否是删除的用户 49 | 'isActive': '@boolean',//激活停用 50 | 'deleteReason': '已离职',//删除原因 51 | 'createTime': '@datetime',//创建时间 52 | 'deleteTime': '@datetime',//删除时间 53 | } 54 | ] 55 | }; 56 | 57 | let userListBusniessAll = Mock.mock(busniessList); 58 | let userListAdminAll = Mock.mock(adminList); 59 | // let userListBusniess = userListBusniessAll.list.filter(item=>{ 60 | // return !item.isDelete 61 | // }); 62 | // let userListAdmin = userListAdminAll.list.filter(item=>{ 63 | // return !item.isDelete 64 | // }); 65 | // let userListBusniessDelete = userListBusniessAll.list.filter(item=>{ 66 | // return item.isDelete 67 | // }); 68 | // let userListAdminDelete = userListAdminAll.list.filter(item=>{ 69 | // return item.isDelete 70 | // }); 71 | 72 | export default { 73 | userListBusniess: userListBusniessAll.list.concat([commonData.data.userList[1]]), 74 | userListAdmin: userListAdminAll.list.concat([commonData.data.userList[0]]), 75 | // userListBusniessDelete: userListBusniessDelete, 76 | // userListAdminDelete: userListAdminDelete, 77 | } 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/components/CTable/filterHead.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 过滤项展示组件 3 | * */ 4 | 5 | import React, {Component} from 'react'; 6 | import PropTypes from 'prop-types' 7 | import _ from 'lodash' 8 | import { Tag } from 'antd'; 9 | 10 | class FilterHead extends Component{ 11 | 12 | 13 | tagClose(data, tag){ 14 | this.props.onTagClose && this.props.onTagClose(data, tag); 15 | } 16 | 17 | flag(data){ 18 | if(_.isArray(data.data)){ 19 | return !!data.data.length 20 | }else if(_.isObject(data.data)){ 21 | return _.isArray(data.data.dateString) ? !!data.data.dateString.length : !!data.data.dateString 22 | } 23 | return false 24 | } 25 | 26 | componentWillReceiveProps(nextProps) { 27 | 28 | } 29 | 30 | render(){ 31 | return ( 32 |
33 | { 34 | !!this.props.data.length && ( 35 | <> 36 |
37 | 38 | 筛选项 39 |
40 |
41 | { 42 | this.props.data.map((item, index)=>{ 43 | return
44 | { 45 | this.flag(item) &&
46 | {item.title} 47 |
48 | { 49 | item.type === 'filter' && item.data.map((tag, tag_index)=>{ 50 | return this.tagClose(item, tag)} key={tag.value}>{tag.text} 51 | }) 52 | } 53 | { 54 | item.type === 'date' && _.isString(item.data.dateString) && this.tagClose(item, item.data.dateString)}>{item.data.dateString} 55 | } 56 | { 57 | item.type === 'date' && _.isArray(item.data.dateString) && this.tagClose(item, item.data.dateString)}>{item.data.dateString[0]}-{item.data.dateString[1]} 58 | } 59 |
60 |
61 | } 62 |
63 | }) 64 | } 65 |
66 | 67 | ) 68 | } 69 |
70 | ) 71 | } 72 | } 73 | 74 | FilterHead.propTypes = { 75 | data: PropTypes.array, 76 | onTagClose: PropTypes.func, 77 | }; 78 | 79 | export default FilterHead 80 | -------------------------------------------------------------------------------- /src/views/mainContent/home/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { connect} from 'react-redux' 3 | import CInput from '@/components/CForm/CInput' 4 | import CBaseComponent from '@/components/CBaseComponent' 5 | import InfoTitle from '@/components/CDetailInfo/detailInfoTitle' 6 | import BaseMap from './baseMap' 7 | import './index.scss' 8 | 9 | import { getStoreAllList} from "@/servers/homeApi"; 10 | 11 | @CBaseComponent 12 | class Home extends Component{ 13 | constructor(props) { 14 | super(props); 15 | this.getStoreListAllData = this.getStoreListAllData.bind(this); 16 | this.searchHandler = this.searchHandler.bind(this); 17 | } 18 | 19 | 20 | state = { 21 | data: null, 22 | searchData: { 23 | value: '',//搜索框筛选 24 | placeholder: '请输入店铺名称' 25 | }, 26 | loading: false, 27 | mapHeight: '300px',//地图高度 28 | }; 29 | 30 | // 获取用户列表数据 31 | getStoreListAllData(){ 32 | let getData = { 33 | search: this.state.searchData.value, 34 | }; 35 | this.setState({ 36 | loading: true 37 | }); 38 | getStoreAllList(getData).then(res=>{ 39 | let data = res.data.list; 40 | this.setState({ 41 | data: data, 42 | loading: false 43 | }); 44 | }) 45 | } 46 | 47 | // 名称筛选 48 | searchHandler(value){ 49 | this.setState({ 50 | searchData: {...this.state.searchData, value: value} 51 | }, () => this.getStoreListAllData()) 52 | } 53 | 54 | // 计算地图高度 55 | computedMapHeight(){ 56 | let screenHeight = this.props.windowInfo && this.props.windowInfo.screenHeight; 57 | let mapHeight = screenHeight - 200; 58 | this.setState({ 59 | mapHeight: mapHeight + 'px' 60 | }) 61 | } 62 | 63 | 64 | 65 | componentWillReceiveProps(nextProps){ 66 | this.computedMapHeight(); 67 | } 68 | 69 | componentWillMount(){ 70 | 71 | } 72 | 73 | 74 | componentDidMount(){ 75 | this.getStoreListAllData(); 76 | this.computedMapHeight(); 77 | } 78 | 79 | render(){ 80 | return ( 81 |
82 | 83 |
84 | 88 |
89 |
90 | 91 |
92 | ) 93 | } 94 | } 95 | 96 | const mapStateToProps = (state) => { 97 | return { 98 | windowInfo: state.Common.windowInfo, 99 | } 100 | }; 101 | 102 | export default connect(mapStateToProps)(Home); 103 | -------------------------------------------------------------------------------- /src/components/CForm/CInput.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Input, InputNumber} from 'antd' 4 | import './index.scss' 5 | 6 | class CInput extends Component{ 7 | 8 | constructor(props) { 9 | super(props); 10 | this.changeHandler = this.changeHandler.bind(this); 11 | } 12 | 13 | componentWillReceiveProps(nextProps) { 14 | this.setState({ 15 | value: nextProps.value 16 | }) 17 | } 18 | 19 | state = { 20 | inputTypeOver: { 21 | 'password':'Password', 22 | 'search':'Search', 23 | 'textarea':'TextArea', 24 | }, 25 | value: '' 26 | } 27 | 28 | changeHandler(e){ 29 | let value = this.props.type === 'number' ? e : e.target.value; 30 | this.setState({ 31 | value: value 32 | }); 33 | this.props.onChange && this.props.onChange(value); 34 | } 35 | 36 | enterHandler(e){ 37 | let value = e.target.value; 38 | this.props.onEnter && this.props.onEnter(value); 39 | } 40 | 41 | searchHandler(value){ 42 | this.props.onEnter && this.props.onEnter(value); 43 | } 44 | 45 | componentWillMount(){ 46 | let defaultValue = this.props.type === 'number' ? undefined : ''; 47 | this.setState({ 48 | value: this.props.value || defaultValue 49 | }) 50 | } 51 | 52 | render(){ 53 | const {type, showNumberStep, className, onChange, onEnter, value, ...props} = this.props; 54 | 55 | const InputDom = this.state.inputTypeOver[type] ? Input[this.state.inputTypeOver[type]] : (type === 'input' && Input); 56 | const onSearch = (value) => this.searchHandler(value); 57 | let propsObj = {}; 58 | if(type === 'search'){ 59 | propsObj = { 60 | onSearch 61 | } 62 | } 63 | return ( 64 | <> 65 | {!!InputDom && this.changeHandler(e)} 70 | onPressEnter={(e) => this.enterHandler(e)}/>} 71 | {type === 'number' 72 | && this.changeHandler(value)} 75 | className={`c-input-number ${className} ${!showNumberStep ? 'no-show-number-step' : ''}`}/>} 76 | 77 | ) 78 | } 79 | } 80 | 81 | CInput.defaultProps = { 82 | type: 'input', 83 | showNumberStep: false,//是否显示number类型的step 84 | value: '' 85 | }; 86 | 87 | CInput.propTypes = { 88 | type: PropTypes.string, 89 | showNumberStep: PropTypes.bool, 90 | value: PropTypes.oneOfType([ 91 | PropTypes.string, 92 | PropTypes.number 93 | ]) 94 | }; 95 | 96 | export default CInput 97 | -------------------------------------------------------------------------------- /src/views/mainContent/storeManage/echarts/newStoreEcharts.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import CEcharts from '@/components/CEcharts' 3 | import InfoTitle from '@/components/CDetailInfo/detailInfoTitle' 4 | import Echarts from 'echarts' 5 | import _ from 'lodash' 6 | 7 | export default class NewStoreEcharts extends Component{ 8 | constructor(props) { 9 | super(props); 10 | this.initOptions = this.initOptions.bind(this); 11 | } 12 | 13 | 14 | state = { 15 | options: { 16 | title: '', 17 | grid: { 18 | left: '5%', 19 | top: '10%', 20 | bottom: '2%', 21 | right: '2%', 22 | containLabel: true, 23 | }, 24 | tooltip: { 25 | show: true, 26 | trigger: 'axis', 27 | }, 28 | xAxis: { 29 | type: 'time', 30 | axisLabel: { 31 | textStyle: { 32 | color: '#666' 33 | } 34 | }, 35 | axisTick: { 36 | show: false 37 | }, 38 | }, 39 | yAxis: { 40 | type: 'value', 41 | name: '数量(个)', 42 | max: 'dataMax', 43 | axisTick: { 44 | show: false 45 | }, 46 | axisLabel: { 47 | textStyle: { 48 | color: '#666' 49 | } 50 | }, 51 | splitLine: { 52 | lineStyle: { 53 | color: '#eee' 54 | } 55 | } 56 | }, 57 | series: [ 58 | { 59 | name: '新增店铺数量统计', 60 | type: 'line', 61 | showSymbol: false, 62 | hoverAnimation: false, 63 | itemStyle: { 64 | normal: { 65 | color: new Echarts.graphic.LinearGradient( 66 | 0, 0, 0, 1, 67 | [ 68 | {offset: 0, color: '#83bff6'}, 69 | {offset: 0.5, color: '#188df0'}, 70 | {offset: 1, color: '#188df0'} 71 | ] 72 | ) 73 | } 74 | }, 75 | data: [] 76 | } 77 | ] 78 | } 79 | } 80 | 81 | initOptions(data){ 82 | if(data) { 83 | let options = _.cloneDeep(this.state.options); 84 | options.series[0].data = data; 85 | this.setState({ 86 | options: options 87 | }) 88 | } 89 | } 90 | 91 | componentWillReceiveProps(nextProps){ 92 | this.initOptions(nextProps.data) 93 | } 94 | 95 | componentDidMount(){ 96 | this.initOptions(this.props.data); 97 | } 98 | 99 | render(){ 100 | return ( 101 |
102 | 103 | {this.props.children} 104 | 105 | 106 |
107 | ) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/adminList/listNew/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const userManageListNewData = [ 4 | { 5 | id: 'baseInfo', 6 | title: '基本信息', 7 | data: [ 8 | { 9 | id: 'name', 10 | name: '姓名', 11 | placeholder: '请输入姓名', 12 | type: 'input', 13 | checkType: 'required', 14 | newDisabled: false, 15 | editDisabled: false, 16 | newShow: true, 17 | editShow: true, 18 | value: '', 19 | options: [], 20 | expand: {}, 21 | jpath: 'name' 22 | }, 23 | { 24 | id: 'password', 25 | name: '密码', 26 | placeholder: '请输入用户密码', 27 | type: 'input', 28 | checkType: 'required', 29 | newDisabled: false, 30 | editDisabled: false, 31 | newShow: true, 32 | editShow: true, 33 | value: '', 34 | options: [], 35 | expand: {}, 36 | jpath: 'password' 37 | }, 38 | { 39 | id: 'sex', 40 | name: '性别', 41 | placeholder: '', 42 | type: 'radio', 43 | checkType: 'required', 44 | newDisabled: false, 45 | editDisabled: false, 46 | newShow: true, 47 | editShow: true, 48 | value: '1', 49 | options: [ 50 | { 51 | value: '1', 52 | name: '男' 53 | }, 54 | { 55 | value: '0', 56 | name: '女' 57 | } 58 | ], 59 | expand: {}, 60 | jpath: 'sex.id' 61 | }, 62 | { 63 | id: 'userRole', 64 | name: '用户角色', 65 | placeholder: '请选择用户角色', 66 | type: 'select', 67 | checkType: 'required', 68 | newDisabled: false, 69 | editDisabled: false, 70 | newShow: true, 71 | editShow: true, 72 | value: '', 73 | options: [], 74 | expand: {}, 75 | jpath: 'userRole.id' 76 | }, 77 | { 78 | id: 'phone', 79 | name: '手机号码', 80 | placeholder: '请输入手机号码', 81 | type: 'number', 82 | checkType: 'required|phone', 83 | newDisabled: false, 84 | editDisabled: false, 85 | newShow: true, 86 | editShow: true, 87 | value: '', 88 | options: [], 89 | expand: {}, 90 | jpath: 'phone' 91 | }, 92 | { 93 | id: 'email', 94 | name: '邮箱', 95 | placeholder: '请输入邮箱', 96 | type: 'input', 97 | checkType: 'required|email', 98 | newDisabled: false, 99 | editDisabled: false, 100 | newShow: true, 101 | editShow: true, 102 | value: '', 103 | options: [], 104 | expand: {}, 105 | jpath: 'email' 106 | }, 107 | ] 108 | } 109 | ]; 110 | -------------------------------------------------------------------------------- /src/views/mainContent/userManage/list/listDetailInfo/data.js: -------------------------------------------------------------------------------- 1 | 2 | export const detailInfoData = [ 3 | { 4 | id: 'baseInfo', 5 | title: '基本信息', 6 | data: [ 7 | { 8 | id: 'id', 9 | name: '用户ID', 10 | value: '', 11 | type: 'input', 12 | jpath: 'id', 13 | }, 14 | { 15 | id: 'name', 16 | name: '姓名', 17 | value: '', 18 | type: 'input', 19 | jpath: 'name', 20 | }, 21 | { 22 | id: 'password', 23 | name: '密码', 24 | value: '', 25 | type: 'input', 26 | jpath: 'password', 27 | }, 28 | { 29 | id: 'phone', 30 | name: '手机号', 31 | value: '', 32 | type: 'input', 33 | jpath: 'phone', 34 | }, 35 | { 36 | id: 'IDCard', 37 | name: '身份证号', 38 | value: '', 39 | type: 'input', 40 | jpath: 'IDCard', 41 | }, 42 | { 43 | id: 'sex', 44 | name: '性别', 45 | value: '', 46 | type: 'input', 47 | jpath: 'sex.name', 48 | }, 49 | { 50 | id: 'userRole', 51 | name: '用户角色', 52 | value: '', 53 | type: 'input', 54 | jpath: 'userRole.name', 55 | }, 56 | { 57 | id: 'email', 58 | name: '邮箱', 59 | value: '', 60 | type: 'input', 61 | jpath: 'email', 62 | }, 63 | { 64 | id: 'address', 65 | name: '地址', 66 | value: '', 67 | type: 'input', 68 | jpath: 'address', 69 | }, 70 | { 71 | id: 'latlong', 72 | name: '经纬度', 73 | value: '', 74 | type: 'input', 75 | jpath: 'latlong', 76 | }, 77 | { 78 | id: 'storeNum', 79 | name: '店铺数量', 80 | value: '', 81 | type: 'input', 82 | jpath: 'storeNum', 83 | }, 84 | { 85 | id: 'createTime', 86 | name: '创建时间', 87 | value: '', 88 | type: 'input', 89 | jpath: 'createTime', 90 | }, 91 | { 92 | id: 'IDCardPictrue', 93 | name: '身份证号照片', 94 | value: [], 95 | type: 'img', 96 | jpath: 'IDCardPicture', 97 | } 98 | ] 99 | }, 100 | { 101 | id: 'storeInfo', 102 | title: '店铺信息', 103 | slot: 'storeInfo', 104 | data: [] 105 | } 106 | ]; 107 | 108 | 109 | export const detailTableData = { 110 | tHead: [ 111 | { 112 | key: 'id', 113 | title: '店铺ID', 114 | dataIndex: 'id', 115 | }, 116 | { 117 | key: 'storeName', 118 | dataIndex: 'storeName', 119 | title: '店铺名称', 120 | } 121 | ], 122 | tBody: [], 123 | tPage: { 124 | total: 0, 125 | page: 1, 126 | pageSize: 10 127 | } 128 | }; 129 | -------------------------------------------------------------------------------- /src/views/App.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import { withRouter} from 'react-router-dom' 3 | // import { ajax_abort_all} from "@/servers"; 4 | import { setUserInfo} from "../redux/common/action"; 5 | import { connect} from 'react-redux' 6 | import { bindActionCreators} from 'redux' 7 | import { compose} from 'redux' 8 | import './App.scss' 9 | import Header from './header' 10 | import LeftNav from './leftNav' 11 | import { getStorage, setStorage} from "@/utils"; 12 | import { LocaleProvider, ConfigProvider} from 'antd' 13 | import zhCN from 'antd/es/locale-provider/zh_CN'; 14 | import moment from 'moment' 15 | import 'moment/locale/zh-cn'; 16 | moment.locale('zh-cn'); 17 | 18 | 19 | 20 | 21 | class App extends Component{ 22 | 23 | state = { 24 | theme: null,//主题 25 | }; 26 | 27 | // 在全局监听数据变化 28 | watchRouterChange(){ 29 | this.props.history.listen((location)=>{ 30 | this.userIsLogin(location); 31 | console.log('watchRouterChange'); 32 | // ajax_abort_all();//路由变化时取消axios请求 33 | }) 34 | } 35 | 36 | userIsLogin(location){ 37 | // 判断用户是否登录,如果没有登录直接跳到login页面 38 | let userInfo = getStorage('userInfo'); 39 | if(!userInfo && location.pathname !== '/login'){ 40 | this.props.history.push({ 41 | pathname: '/login' 42 | }); 43 | } 44 | this.props.setUserInfo(userInfo); 45 | } 46 | 47 | // // 切换主题文件 48 | setThemeFile(currentTheme){ 49 | if(!getStorage('theme')){ 50 | setStorage('theme', currentTheme); 51 | } 52 | this.setState({ 53 | theme: getStorage('theme') 54 | }); 55 | } 56 | 57 | componentWillReceiveProps(nextProps){ 58 | this.setThemeFile(nextProps.currentTheme); 59 | } 60 | 61 | componentDidMount(){ 62 | console.log('====33') 63 | this.watchRouterChange(); 64 | this.userIsLogin(this.props.history.location); 65 | this.setThemeFile(this.props.currentTheme); 66 | } 67 | 68 | render(){ 69 | return ( 70 | 71 |
72 |
73 | 74 |
75 | 76 | 77 |
78 | {this.props.children} 79 |
80 |
81 |
82 |
83 | ) 84 | } 85 | } 86 | 87 | 88 | const mapStateToProps = (state) => { 89 | return { 90 | userInfo: state.Common.userInfo, 91 | currentTheme: state.Common.currentTheme 92 | } 93 | }; 94 | 95 | const mapDispatchToProps = (dispatch) => { 96 | return { 97 | setUserInfo: bindActionCreators(setUserInfo, dispatch), 98 | } 99 | }; 100 | 101 | export default compose(withRouter, connect(mapStateToProps, mapDispatchToProps))(App); 102 | -------------------------------------------------------------------------------- /src/mock/statistics/userApiList.js: -------------------------------------------------------------------------------- 1 | 2 | import { urlFormat, formatDate} from "@/utils"; 3 | import { mockConfig} from '../index' 4 | // import _ from 'lodash' 5 | import { storeManageStoreList} from "../createMockData"; 6 | // import * as commonData from '../commonData' 7 | 8 | /*统计店铺根据店铺分类*/ 9 | export const getStatisticsStoreByCategory = (opts) => { 10 | let data = { 11 | list: [] 12 | }; 13 | let obj = {}; 14 | storeManageStoreList.forEach(item=>{ 15 | if(!obj[item.category.id]){ 16 | obj[item.category.id] = { 17 | name: item.category.name, 18 | num: 1, 19 | } 20 | }else{ 21 | obj[item.category.id]['num']++ 22 | } 23 | }); 24 | Object.keys(obj).forEach(key=>{ 25 | data.list.push({ 26 | id: key, 27 | name: obj[key].name, 28 | num: obj[key].num 29 | }) 30 | }); 31 | return {...mockConfig.baseMock, data: data} 32 | }; 33 | 34 | /*新增店铺数量统计*/ 35 | export const getStatisticsNewStore = (opts) => { 36 | let startTime = urlFormat(opts.url, 'startTime'); 37 | let endTime = urlFormat(opts.url, 'endTime'); 38 | let data = { 39 | list: [] 40 | }; 41 | let obj = {}; 42 | storeManageStoreList.forEach(item=>{ 43 | let createTime = formatDate(item.createTime, 'YYYY-MM-DD'); 44 | if(startTime && endTime){ 45 | if(createTime >= startTime && createTime <= endTime){ 46 | if(!obj[createTime]){ 47 | obj[createTime] = 1; 48 | }else{ 49 | obj[createTime]++ 50 | } 51 | } 52 | }else{ 53 | if(!obj[createTime]){ 54 | obj[createTime] = 1; 55 | }else{ 56 | obj[createTime]++ 57 | } 58 | } 59 | }); 60 | let arr = []; 61 | Object.keys(obj).forEach(key=>{ 62 | arr.push({ 63 | dateTime: key, 64 | num: obj[key] 65 | }) 66 | }); 67 | data.list = arr.sort(function (a, b) { 68 | return new Date(a.dateTime) - new Date(b.dateTime) 69 | }); 70 | return {...mockConfig.baseMock, data: data} 71 | }; 72 | 73 | /*店铺排行榜(信誉、售后、星级)*/ 74 | export const getStatisticsStoreRank = (opts) => { 75 | let data = {}; 76 | // 信誉排行(由小到大) 77 | storeManageStoreList.sort((a, b)=>{ 78 | return a.creditGrade.id - b.creditGrade.id 79 | }); 80 | // 返回信誉前十的店铺 81 | let creditGradeTop10 = storeManageStoreList.slice(0,10); 82 | // 售后排行(由大到小) 83 | storeManageStoreList.sort((a, b)=>{ 84 | return b.serviceScore - a.serviceScore 85 | }); 86 | // 返回售后前十的店铺 87 | let serviceScoreTop10 = storeManageStoreList.slice(0,10); 88 | // 星级排行(由大到小) 89 | storeManageStoreList.sort((a, b)=>{ 90 | return b.rate - a.rate 91 | }); 92 | // 返回星级前十的店铺 93 | let rateTop10 = storeManageStoreList.slice(0,10); 94 | 95 | data = { 96 | creditGradeTop10, 97 | serviceScoreTop10, 98 | rateTop10 99 | }; 100 | return {...mockConfig.baseMock, data: data} 101 | }; 102 | -------------------------------------------------------------------------------- /src/mock/statistics/storeApiList.js: -------------------------------------------------------------------------------- 1 | 2 | import { urlFormat, formatDate} from "@/utils"; 3 | import { mockConfig} from '../index' 4 | // import _ from 'lodash' 5 | import { storeManageStoreList} from "../createMockData"; 6 | // import * as commonData from '../commonData' 7 | 8 | /*统计店铺根据店铺分类*/ 9 | export const getStatisticsStoreByCategory = (opts) => { 10 | let data = { 11 | list: [] 12 | }; 13 | let obj = {}; 14 | storeManageStoreList.forEach(item=>{ 15 | if(!obj[item.category.id]){ 16 | obj[item.category.id] = { 17 | name: item.category.name, 18 | num: 1, 19 | } 20 | }else{ 21 | obj[item.category.id]['num']++ 22 | } 23 | }); 24 | Object.keys(obj).forEach(key=>{ 25 | data.list.push({ 26 | id: key, 27 | name: obj[key].name, 28 | num: obj[key].num 29 | }) 30 | }); 31 | return {...mockConfig.baseMock, data: data} 32 | }; 33 | 34 | /*新增店铺数量统计*/ 35 | export const getStatisticsNewStore = (opts) => { 36 | let startTime = urlFormat(opts.url, 'startTime'); 37 | let endTime = urlFormat(opts.url, 'endTime'); 38 | let data = { 39 | list: [] 40 | }; 41 | let obj = {}; 42 | storeManageStoreList.forEach(item=>{ 43 | let createTime = formatDate(item.createTime, 'YYYY-MM-DD'); 44 | if(startTime && endTime){ 45 | if(createTime >= startTime && createTime <= endTime){ 46 | if(!obj[createTime]){ 47 | obj[createTime] = 1; 48 | }else{ 49 | obj[createTime]++ 50 | } 51 | } 52 | }else{ 53 | if(!obj[createTime]){ 54 | obj[createTime] = 1; 55 | }else{ 56 | obj[createTime]++ 57 | } 58 | } 59 | }); 60 | let arr = []; 61 | Object.keys(obj).forEach(key=>{ 62 | arr.push({ 63 | dateTime: key, 64 | num: obj[key] 65 | }) 66 | }); 67 | data.list = arr.sort(function (a, b) { 68 | return new Date(a.dateTime) - new Date(b.dateTime) 69 | }); 70 | return {...mockConfig.baseMock, data: data} 71 | }; 72 | 73 | /*店铺排行榜(信誉、售后、星级)*/ 74 | export const getStatisticsStoreRank = (opts) => { 75 | let data = {}; 76 | // 信誉排行(由小到大) 77 | storeManageStoreList.sort((a, b)=>{ 78 | return a.creditGrade.id - b.creditGrade.id 79 | }); 80 | // 返回信誉前十的店铺 81 | let creditGradeTop10 = storeManageStoreList.slice(0,10); 82 | // 售后排行(由大到小) 83 | storeManageStoreList.sort((a, b)=>{ 84 | return b.serviceScore - a.serviceScore 85 | }); 86 | // 返回售后前十的店铺 87 | let serviceScoreTop10 = storeManageStoreList.slice(0,10); 88 | // 星级排行(由大到小) 89 | storeManageStoreList.sort((a, b)=>{ 90 | return b.rate - a.rate 91 | }); 92 | // 返回星级前十的店铺 93 | let rateTop10 = storeManageStoreList.slice(0,10); 94 | 95 | data = { 96 | creditGradeTop10, 97 | serviceScoreTop10, 98 | rateTop10 99 | }; 100 | return {...mockConfig.baseMock, data: data} 101 | }; 102 | -------------------------------------------------------------------------------- /src/views/mainContent/goodsManage/goodsList/listNew/data.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const goodsManageListNewData = [ 4 | { 5 | id: 'baseInfo', 6 | title: '基本信息', 7 | data: [ 8 | { 9 | id: 'name', 10 | name: '商品名称', 11 | placeholder: '请输入商品名称', 12 | type: 'input', 13 | checkType: 'required|maxLength:30', 14 | newDisabled: false, 15 | editDisabled: false, 16 | newShow: true, 17 | editShow: true, 18 | value: '', 19 | options: [], 20 | expand: {}, 21 | jpath: 'name' 22 | }, 23 | { 24 | id: 'storeInfo', 25 | name: '所属商铺', 26 | placeholder: '请选择所属商铺', 27 | type: 'select', 28 | checkType: 'required', 29 | newDisabled: false, 30 | editDisabled: false, 31 | newShow: true, 32 | editShow: true, 33 | value: '', 34 | options: [], 35 | expand: { 36 | showSearch: true,//可以搜索 37 | filterOption: false,//不触发options过滤,做手动远程过滤 38 | defaultActiveFirstOption: false,//默认不选中options第一个,防止不选中失去焦点时的闪现问题 39 | }, 40 | jpath: 'storeInfo.id' 41 | }, 42 | { 43 | id: 'price', 44 | name: '商品价格', 45 | placeholder: '请输入商品价格', 46 | type: 'number', 47 | checkType: 'required', 48 | newDisabled: false, 49 | editDisabled: false, 50 | newShow: true, 51 | editShow: true, 52 | value: '', 53 | options: [], 54 | expand: {}, 55 | jpath: 'price' 56 | }, 57 | { 58 | id: 'description', 59 | name: '商品描述', 60 | placeholder: '请输入商品描述', 61 | type: 'textarea', 62 | checkType: 'required', 63 | newDisabled: false, 64 | editDisabled: false, 65 | newShow: true, 66 | editShow: true, 67 | value: '', 68 | options: [], 69 | expand: { 70 | autoSize: {minRows: 3, maxRows: 6} 71 | }, 72 | jpath: 'description' 73 | }, 74 | { 75 | id: 'stockNum', 76 | name: '库存量', 77 | placeholder: '请输入库存量', 78 | type: 'number', 79 | checkType: 'required', 80 | newDisabled: false, 81 | editDisabled: false, 82 | newShow: true, 83 | editShow: true, 84 | value: '', 85 | options: [], 86 | expand: {}, 87 | jpath: 'stockNum' 88 | }, 89 | { 90 | id: 'imgs', 91 | name: '商品图片', 92 | placeholder: '', 93 | type: 'img', 94 | checkType: 'required', 95 | newDisabled: false, 96 | editDisabled: false, 97 | newShow: true, 98 | editShow: true, 99 | value: [], 100 | options: [], 101 | expand: { 102 | limit: 5 103 | }, 104 | jpath: 'imgs' 105 | } 106 | ] 107 | } 108 | ]; 109 | -------------------------------------------------------------------------------- /src/views/mainContent/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component} from 'react' 2 | import { connect} from 'react-redux' 3 | import { bindActionCreators} from 'redux' 4 | import { Card} from 'antd' 5 | import CBreadcrumb from '@/components/CBreadcrumb' 6 | import CButton from '@/components/CButton' 7 | import CScroll from '@/components/CScroll' 8 | import { setReload, setWindowInfo} from "@/redux/common/action"; 9 | import './index.scss' 10 | 11 | class MainContent extends Component{ 12 | 13 | constructor(props) { 14 | super(props); 15 | this.reload = this.reload.bind(this); 16 | this.listenWindowInfo = this.listenWindowInfo.bind(this); 17 | } 18 | 19 | 20 | // static getDerivedStateFromProps(){ 21 | // 22 | // } 23 | 24 | reload(){ 25 | this.props.setReload(true); 26 | } 27 | 28 | // 监听window高宽变化 29 | listenWindowInfo(){ 30 | let self = this; 31 | window.addEventListener('resize', function (e) { 32 | let height = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 33 | let width = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 34 | let mainContentHeight = document.getElementById('mainContent').offsetHeight; 35 | let mainContentWidth = document.getElementById('mainContent').offsetWidth; 36 | let value = { 37 | ...self.props.windowInfo, 38 | screenHeight: height, 39 | screenWidth: width, 40 | mainContentHeight, 41 | mainContentWidth}; 42 | self.props.setWindowInfo && self.props.setWindowInfo(value); 43 | }) 44 | } 45 | 46 | componentWillMount(){ 47 | 48 | } 49 | 50 | componentDidMount(){ 51 | this.listenWindowInfo(); 52 | } 53 | 54 | componentDidUpdate(){ 55 | 56 | } 57 | 58 | render(){ 59 | return ( 60 |
61 | 62 |
63 |
64 | 65 | 66 | 67 |
68 |
69 | 70 | {this.props.children} 71 | 72 |
73 |
74 |
75 |
76 | ) 77 | } 78 | } 79 | 80 | const mapStateToProps = (state) => { 81 | return { 82 | breadcrumbData: state.Common.breadcrumbData, 83 | windowInfo: state.Common.windowInfo, 84 | reload: state.Common.reload, 85 | } 86 | }; 87 | 88 | const mapDispatchToProps = (dispatch) => { 89 | return { 90 | setReload: bindActionCreators(setReload, dispatch), 91 | setWindowInfo: bindActionCreators(setWindowInfo, dispatch), 92 | } 93 | }; 94 | 95 | export default connect(mapStateToProps, mapDispatchToProps)(MainContent); 96 | -------------------------------------------------------------------------------- /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/facebook/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(inputPath, needsSlash) { 15 | const hasSlash = inputPath.endsWith('/'); 16 | if (hasSlash && !needsSlash) { 17 | return inputPath.substr(0, inputPath.length - 1); 18 | } else if (!hasSlash && needsSlash) { 19 | return `${inputPath}/`; 20 | } else { 21 | return inputPath; 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