背景:PC端的CRM系统第一阶段已经开发完毕.使用技术为:JS + AntDesignPro.现在开始开发企业微信.需要使用的技术为:TS + AntDesignMobile.因为公司之前有人开发过企业微信版,所以直接拉的别人搭好的架子.
开发之前,反复浏览TS的官网,AntDesignMobile的官网.
1:项目目录:
与AntDesignPro目录是差不多的.简单说下.开发代码还是在src下面的pages里面.assets里面放的一般都是图标.components里面都是自己封装的组件.layouts里面是鉴权.interceptors.ts文件里面是获取token的地方.umirc.ts里面是连接后端服务器地址的.开发服务器,测试服务器,生产服务器等.
2:开发首页页面:
目录结构:
上代码:
services层:
import axios from 'axios';
/**
* 首页列表
*/
export async function listHome(data : any) {
return axios.post(`/${process.env.APIPREFIX}/ticket/listHome`, data);
}
model层:
import * as services from './service';
export default {
namespace: 'home',
effects: {
// 首页列表
*listHome({ data, callback} : any, { put, call }: any) {
const datas = yield call(services.listHome, data);
yield put({
type: 'save',
payload:{listHome : datas.data} ,
});
if (datas.code === '0000') {
callback && callback(datas.data);
}
},
},
reducers: {
save(state : any, { payload } : any) {
return {
...state,
...payload,
};
},
}
}
index.tsx:
/**
* title: '昆药CRM'
*/
import React from 'react';
import { List } from 'antd-mobile';
import router from 'umi/router';
import styles from './index.less';
import { connect } from 'dva';
import IconBlock from './components/IconBlock';
import { Flex } from 'antd-mobile';
const Item = List.Item;
const Brief = Item.Brief;
const namespace = 'home';
const mapStateToProps = (state: any) => {
const states = state[namespace];
return {
...states,
};
};
const mapDispatchToProps = (dispatch: any) => ({
// 首页列表
listHome(data: any, callback: any) {
dispatch({
type: `${namespace}/listHome`,
data,
callback,
});
},
});
class Home extends React.Component {
constructor(props: any) {
super(props);
this.state = {
menu: [],
order: {
groupTitle: '订单相关查询',
menuList: [],
}, // 订单类
invoiceFinancial: {
groupTitle: '回款相关查询',
menuList: [],
}, // 发票财务类
masterData: {
groupTitle: '主数据查询',
menuList: [],
}, // 主数据类
};
}
componentDidMount() {
this.getList();
}
// 获取首页图标
getList = () => {
const { listHome }: any = this.props;
listHome({}, (res: any) => {
res.menus &&
res.menus.map((val: any) => {
val.children.map((value: any) => {
if (value.menuName === '订单类') {
const { order }: any = this.state;
this.setState(
{
order: {
...order,
menuList: value.children,
},
},
() => {
const { order }: any = this.state;
this.setState({ menu: [order] });
},
);
}
if (value.menuName === '发票财务类') {
const { invoiceFinancial }: any = this.state;
this.setState(
{
invoiceFinancial: {
...invoiceFinancial,
menuList: value.children,
},
},
() => {
const { menu, invoiceFinancial }: any = this.state;
this.setState({ menu: [invoiceFinancial, ...menu] });
},
);
}
if (value.menuName === '主数据类') {
const { masterData }: any = this.state;
this.setState(
{
masterData: {
...masterData,
menuList: value.children,
},
},
() => {
const { menu, masterData }: any = this.state;
this.setState({ menu: [masterData, ...menu] });
},
);
}
});
});
});
};
// 跳转
jump = (path: any) => {
const { menuList, dispatch }: any = this.props;
let key: any = '';
let menuList1 = menuList.menuData.menuList;
let query = (arr: any, index: number) => {
if (arr.path === path) {
key = index && index;
} else if (arr.children.length > 0) {
arr.children.map((i: any) => {
query(i, index);
});
}
};
menuList1.map((item: any, index: number) => {
query(item, index);
});
dispatch &&
dispatch({
type: 'global/changeLayoutCollapsed',
payload: false,
});
localStorage.setItem('menuNav', key.toString());
router.push({
pathname: path,
});
};
render() {
const { menu }: any = this.state;
return (
<div style={{marginBottom:50}}>
<img src={require('../../assets/icons/banner.png')} style={{width:'100%',marginBottom:20}}/>
{menu &&
menu.map((value: any) => (
<div key={value.groupTitle}>
<span className={styles.section_title}>{value.groupTitle}</span>
<Flex wrap="wrap">
{value.menuList.map((item: any, index: number) => (
<IconBlock
key={index}
titleName={item.menuName}
iconPath={item.icon}
method={() => this.jump(item.url)}
/>
))}
</Flex>
</div>
))}
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
components-IconBlock.tsx:
import React from 'react';
import styles from './style.less';
interface IconBlockProps {
titleName: string,
iconPath: string,
method: (e: React.MouseEvent) => void;
}
const IconBlock: React.FC<IconBlockProps> = ({ titleName, iconPath, method }) => {
return (
<div className={styles.blockWrapper} onClick={method}>
<div className={styles.icon}>
<img src={iconPath}/>
</div>
<div className={styles.title}>{titleName}</div>
</div>
)
}
export default IconBlock;
3:实现效果:
头部:
底部:
4:说下遇到的BUG:
1:注入model层的时候,一直报错:
.
实在是第一次用ts.真不会写..这个类型整死我了... 搞了几个小时...
换了好几种写法.. 最后才解决了...解决方法:把connect放在页面底部.export default connect(mapStateToProps, mapDispatchToProps)(Home);
2:ESlint 真的很严格.. 提交代码的时候.一直给我报错.. 一向急躁的我到处看ts写法问题... 最后发现... 是我的标签前面多打了个空格... 我真的要被自己气死了....
3:页面样式问题.AntDesignMobile和AntDesignPro的组件还是有很多不一样的.比如AntDesignPro有的Row和Col,Text等等都没有了.. 这个写起来真的好不习惯..AntDesignMobile有Flex布局.但是这个API用起来和原生的区别真的不大.....
写代码几个小时后就容易疲劳.然后列表循环展示图标的时候.把Flex标签放循环里面了.样式就可想而知.一塌糊涂.. 这么浅显的BUG我竟然还是创造出来了... 写出来.警告自己.以后不可再犯.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。