经过差不都三个多月的实践,本人对自己的React代码编程的规范有了进一步的加深了解

,在vue上有开源的文章和规范作为指导,在React方向上这方面少得可怜,因此本人结合自己在工作上的终结 摸索出这样的一套合理的符合代码编写风格的React_PC指南,注意由于我们使用的阿里家同款的所有技术栈,于是这里有些东西是我们比选的比如说

一、代码测层面的规范

1. 代码的布局如下

  1. // MyComponent
  2. import React, { useState, useRef,useEffect, useCallback, useContext } from 'react'
  3. /**
  4. * Preset
  5. */
  6. const MyComponent = () => {
  7. /**
  8. * state
  9. */
  10. /**
  11. * method
  12. */
  13. /**
  14. * effct
  15. */
  16. /**
  17. * componentsConfig
  18. */
  19. /**
  20. * render
  21. */
  22. return(
  23. <>
  24. <h1>BMlaoli-coding....</h1>
  25. </>
  26. )
  27. }
  28. export default MyComponent

2. 依赖包的美观程度

  1. import { PageHeaderWrapper } from '@ant-design/pro-layout';
  2. import config from '@/utils/config';
  3. import ProTable from '@ant-design/pro-table';
  4. import { useRequest } from 'ahooks';
  5. import { Card, Input, Select, Tag, Popconfirm, Button } from 'antd';
  6. import { page, deleteArrange } from '@/services/service';
  7. import React, { useEffect, useRef, useState } from 'react';
  8. //以上的代码显得有些混乱。不过也是不要紧的
  9. /**
  10. * 资产回收站Table表格
  11. */
  12. import React, { useState, useRef, useEffect, useCallback, useContext } from 'react';
  13. import { Card, Button, message, Row, Col, Select, Form, Cascader, Space, Popconfirm, Alert, Input, } from 'antd';
  14. import { getHeader, deleteAsset, page, getTags } from '@/pages/Dashboard/services/assetDetail';
  15. import { getNamespace } from '@/pages/discovery/Setting/services/discoveryJob';
  16. import { PageHeaderWrapper } from '@ant-design/pro-layout';
  17. import { getAssetModel } from '@/services/assetModel';
  18. import ProTable from '@ant-design/pro-table';
  19. import { PlusOutlined } from '@ant-design/icons';
  20. import { operate } from '@/services/recycle';
  21. import config from '@/utils/config';
  22. import { useRequest } from 'ahooks';
  23. import { Link } from 'umi';
  24. import DrawerHH from '../Drawer';
  25. import moment from 'moment'
  26. const { Option, OptGroup } = Select;
  27. //以上的代码需要非常注意的一点我一定要提醒你,如果包之间有明确的依赖关系,那你就不能这样做,会凉凉的
  28. //但是我们依然不推荐使用如上的格式,因为它会造成一些非必要的问题,如果你不是和我一样有强迫症 这个import导包的地方是非必要的,这样就差不多了

3. 注意事项

请注意给你的代码加上注释,我发现好多的朋友都必须会加注释,当一个项目组中有很多人共同完成很多的代码的时候,这样维护的成本是不可想象的 如果有重大bug或者有人离职了,那么它的代码将会无人看懂,逻辑的堆叠将会是不可开交的

  1. // 获取标签
  2. const { run: getTageList } = useRequest(getTags, {
  3. onSuccess: (result) => {
  4. if (result && result.success) {
  5. setTagList(result.data);
  6. getColumns({ tableName: location.query.tableName });
  7. }
  8. },
  9. });
  10. /**
  11. * componentsConfig
  12. */
  13. // 用户自定义的检索项 标签
  14. const TagtSearch = (_, p) => {
  15. return (
  16. <Select mode="multiple" placeholder="请选择标签" showArrow
  17. {...p}
  18. >
  19. { tagList.map((item) => (
  20. <OptGroup label={item.name} key={item.id}>
  21. {(item.tags ? item.tags : []).map((items) => (
  22. <Option value={items.name} key={items.id}>
  23. {items.name}
  24. </Option>
  25. ))}
  26. </OptGroup>
  27. ))}
  28. </Select>
  29. )
  30. }
  31. // 网络域
  32. const NamespaceSearch = (_, p) => {
  33. return (
  34. <Select placeholder="请选择网络域" {...p}>
  35. { namespace.map(item => (
  36. <Option key={item.id} value={item.name}>{item.name}</Option>
  37. ))}
  38. </Select>
  39. )
  40. }
  41. /**
  42. * method
  43. */
  44. /** 注意,这样的代码仅仅适用于,复杂的子程序注释,不要四处滥用
  45. * 描述
  46. * 动态啊的获取表头
  47. * @author lishizeng
  48. * @date 2020-10-10
  49. * @param {Array} data 获取的数据
  50. * @returns {any}
  51. */
  52. const dynamicSetColums = (value) => {
  53. let data = value.map((item) => {
  54. let valueType = 'text';
  55. if (item.propertyType === 'DATETIME') {
  56. valueType = 'dateTime';
  57. } else if (item.propertyType === 'DATE') {
  58. valueType = 'date';
  59. } else if (item.propertyType === 'TIME') {
  60. valueType = 'time';
  61. }
  62. const basicColumns = {
  63. hideInSearch: !InCulde.includes(item.name),
  64. title: item.name,
  65. dataIndex: item.propertyName,
  66. width: 200,
  67. ellipsis: true,
  68. sorter: tru
  69. ......
  70. // 你可以非常清晰的看到我的代码的注释,有些代码的注释比较复杂,@什么什么的,但是有的代码看起来比较的简单,只有 // 那么问题来了,我什么时候 *全注释什么时候用
  71. //呢,我认为如果全部都是/*@*/那么 代码虽然很ok,但是这个和我们的开发效率是不符的
  72. ,因此什么时候用/*@*/什么时候用//,我们还是看情况来配置是比价合适的
  73. ----> 目前我个人比较推崇的规范是:
  74. 1. 一切以简单为主 //
  75. 2. 如果是组件的东西 可以使用 /**/
  76. 3. 如果是代码复杂的地方,可以
  77. /**
  78. * 描述
  79. * 动态啊的获取表头
  80. * @author lishizeng
  81. * @date 2020-10-10
  82. * @param {Array} data 获取的数据
  83. * @returns {any}
  84. */
  85. 4. 原则,如果你编写注释的时间,耗费了你代码的时间,那么你应该考虑一下了,这样的代码注释是不是太有必要?

4. 一个不规范的代码&&一个编码风格良好的代码

以下的代码维护和可阅读性简直😭

  • 质量不是很好的代码示例 ```jsx import React, { useState, useRef, useEffect, useCallback, useContext, createRef } from ‘react’ import { Form, Drawer, Button, Input, Collapse, Row, Col, message, Select, Checkbox, Radio, Tree, Tabs, Space, DatePicker, Spin, Popover } from ‘antd’ import config from ‘@/utils/config’; import { CloseOutlined, MinusCircleOutlined, PlusOutlined } from ‘@ant-design/icons’ import { createCheckTaks, getTackById, getServieceScenes, getConfigByServieceScenes, getAssetLoctionByServieceScenes } from ‘../../service’ import TaskType from ‘./TaskType’ import TreeConfig from ‘./Tree’ import { useRequest } from ‘ahooks’ import { history, useModel } from ‘umi’; import Execution from ‘./ExecutionType’ import moment from ‘moment’ const { Panel } = Collapse; const { TabPane } = Tabs; import _ from ‘lodash’

/**

  • 预置方法 / const InspectionMode = ({ actionRef, visable, setVsiable, itemValue, setItemValue, formDefalutValues, setFormDefalutValues }) => { /*

    • 初始化数据 */ const [form] = Form.useForm(); const [propsTreeData, setPropsTreeData] = useState([]) const [treeDefaultDataChangeValue] = useState(‘VMWARE’) const { initialState } = useModel(‘@@initialState’);

    const [servieceScenesList, setServieceScenesList] = useState([])

    const [servieceScenesIdType, setServieceScenesIdType] = useState(null) const [servieceScenesId, setServieceScenesId] = useState(0) const [assetObjcet, setAssetObjcet] = useState([]) /**

    • 方法 */ const close = () => { setItemValue(Object.assign([], [])) form.resetFields(); setVsiable(false) setFormDefalutValues(null) };

    const { run: initServieceScenes, } = useRequest(getServieceScenes, { manual: true, onSuccess: (result, params) => { if (result && result.success) {

    1. setServieceScenesList(_.filter(result.data, (v) => v.name !== '自定义'))

    } }, });

    const { run: initConfigByServieceScenes, } = useRequest(getConfigByServieceScenes, { manual: true, onSuccess: (result, params) => { if (result && result.success) {

    1. if (servieceScenesIdType) {
    2. initAssetLoctionByServieceScenes(servieceScenesId)
    3. }

    } }, });

    const { run: initAssetLoctionByServieceScenes, } = useRequest(getAssetLoctionByServieceScenes, { manual: true, onSuccess: (result, params) => { if (result && result.success) {

    1. setAssetObjcet(result.data)

    } }, });

    // 选择场景 const servieceScenesChange = (value, b, c) => { setServieceScenesIdType(b.typeS) setServieceScenesId(value) }

    useEffect(() => { // if(itemValue.length>0){ // } // // setServieceScenesIdType(() => { // // if (itemValue.assetIdList === 0) { // // return 1 // // } else { // // return 0 // // } // // })

    if (servieceScenesId) { initConfigByServieceScenes(servieceScenesId) } }, [servieceScenesId])

    const onSubmit = () => { if (propsTreeData.length == 0) { message.error(‘请至少选择一个检查项!’) return } form .validateFields() .then(async (values) => {

    1. // console.log(values);
    2. let FormObject = {
    3. id: values.id ? values.id : undefined,
    4. name: values.name,
    5. taskType: values.ip ? 2 : 1,
    6. performStatus: values.performStatus,
    7. performTimeSource: values.performStatus == 1 ?
    8. moment(values.performTimeSourceE).format('YYYY-MM-DD hh:mm:ss') :
    9. values.performTimeSource,
    10. description: values.description || '',
    11. userId: values.userId,
    12. userName: values.userName,
    13. configIdList: propsTreeData,
    14. serviceVersionId: values.serviceVersionId || 1,
    15. adviceObjectList: !values.ip ? null : [{
    16. ip: values.ip,
    17. user: values.user,
    18. password: values.password
    19. }],
    20. assetIdList: values.assetIdList
    21. }
    22. console.log(FormObject, '+++>');
    23. const { success } = await createCheckTaks(FormObject)
    24. if (success) {
    25. message.success('设置成功')
    26. }
    27. actionRef.current.reload()
    28. form.resetFields();
    29. setItemValue(Object.assign([], []))
    30. setFormDefalutValues(null)
    31. setVsiable(false)

    }) .catch((info) => {

    1. console.log(info);

    }); }

    const handleChange = (value) => { }

    const initItemValue = async (value) => { try { const { data } = await getTackById(value) setFormDefalutValues(data) } catch (error) { message.error(error) } }

    // 级联检查项 const callback = () => { }

    /**

    • 生命周期 */ useEffect(() => { initServieceScenes() }, [itemValue])

    /**

    • 组件配置 */ // 指定任务执行时间,展开项组件 // Drawer页脚 const DrawerFooter = () => { return (
      ) }

/**

  • 视图 */ return ( <> } destroyOnClose={true} width={800} footer={DrawerFooter()} >

    { }} size=”large” layout=”horizontal” > prevValues.serviceVersionId !== currentValues.serviceVersionId} > {({ getFieldValue }) => { return getFieldValue(‘serviceVersionId’) ? ( <> { servieceScenesIdType ? ( ) : ( <> </> ) } </> ) : null; }}

    </> ) }

export default InspectionMode

  1. > _**上述代码的诟病:**
  2. > 1. 整体的规范布局凌乱,比如state没有写在一起
  3. > 1. 组件没有很好的分离,过多的if else 嵌套和判断,让你头昏脑涨
  4. - [x] 质量还不错的代码示例
  5. ```jsx
  6. /**
  7. * 资产回收站Table表格
  8. */
  9. import React, { useState, useRef, useEffect, useCallback, useContext } from 'react';
  10. import { Card, Button, message, Row, Col, Select, Form, Cascader, Space, Popconfirm, Alert, Input, PageHeader } from 'antd';
  11. import { getHeader, deleteAsset, page, getTags } from '@/pages/Dashboard/services/assetDetail';
  12. import { getNamespace } from '@/pages/discovery/Setting/services/discoveryJob';
  13. import { PageHeaderWrapper } from '@ant-design/pro-layout';
  14. import { getAssetModel } from '@/services/assetModel';
  15. import ProTable from '@ant-design/pro-table';
  16. import { PlusOutlined } from '@ant-design/icons';
  17. import { operate } from '@/services/recycle';
  18. import config from '@/utils/config';
  19. import { useRequest } from 'ahooks';
  20. import { Link, history } from 'umi';
  21. import DrawerHH from '../Drawer';
  22. import moment from 'moment'
  23. const { Option, OptGroup } = Select;
  24. /**
  25. * Preset
  26. */
  27. const layout = {
  28. labelCol: { span: 6 },
  29. wrapperCol: { span: 18 },
  30. };
  31. let x = 200;
  32. let InCulde = ['资产编号', '资产名称', '网络域'];
  33. const RecycleDetail = ({ location }) => {
  34. /**
  35. * state
  36. */
  37. const actionRef = useRef(null);
  38. const [size, setSize] = useState('middle');
  39. const [tableNames, setTableNames] = useState(location.query.tableName);
  40. const [columns, setColumns] = useState([]);
  41. const [basicProps, setBasicProps] = useState({ drawerVisible: false });
  42. const [namespace, setNamespace] = useState([]);
  43. const [tagList, setTagList] = useState([]);
  44. const [otheSearch, setOtheSearch] = useState({
  45. sorter: null,
  46. sortOrder: null,
  47. tableName: location?.query?.tableName,
  48. del: 1,
  49. state: 0,
  50. })
  51. // 获取名称列表
  52. const { run: getNameSpaceList } = useRequest(getNamespace, {
  53. onSuccess: (result) => {
  54. if (result && result.success) {
  55. setNamespace(result.data);
  56. }
  57. },
  58. });
  59. // 获取标签
  60. const { run: getTageList } = useRequest(getTags, {
  61. onSuccess: (result) => {
  62. if (result && result.success) {
  63. setTagList(result.data);
  64. getColumns({ tableName: location.query.tableName });
  65. }
  66. },
  67. });
  68. /**
  69. * componentsConfig
  70. */
  71. // 用户自定义的检索项 标签
  72. const TagtSearch = (_, p) => {
  73. return (
  74. <Select mode="multiple" placeholder="请选择标签" showArrow
  75. {...p}
  76. >
  77. { tagList.map((item) => (
  78. <OptGroup label={item.name} key={item.id}>
  79. {(item.tags ? item.tags : []).map((items) => (
  80. <Option value={items.name} key={items.id}>
  81. {items.name}
  82. </Option>
  83. ))}
  84. </OptGroup>
  85. ))}
  86. </Select>
  87. )
  88. }
  89. // 网络域
  90. const NamespaceSearch = (_, p) => {
  91. return (
  92. <Select placeholder="请选择网络域" {...p}>
  93. { namespace.map(item => (
  94. <Option key={item.id} value={item.name}>{item.name}</Option>
  95. ))}
  96. </Select>
  97. )
  98. }
  99. /**
  100. *
  101. * renderFormItem: TimeLimit,
  102. formItemProps: {
  103. label: "选择时间",
  104. },
  105. */
  106. /**
  107. * method
  108. */
  109. /**
  110. * 描述
  111. * 动态啊的获取表头
  112. * @author lishizeng
  113. * @date 2020-10-10
  114. * @param {Array} data 获取的数据
  115. * @returns {any}
  116. */
  117. const dynamicSetColums = (value) => {
  118. let data = value.map((item) => {
  119. // 目前的方案是 先全部排序,然后给定几个范围去掉排序,排序的信息来源一定是表头数据
  120. let sorter = false;
  121. let valueType = 'text';
  122. if (item.propertyType === 'DATETIME') {
  123. valueType = 'dateTime';
  124. sorter = true;
  125. } else if (item.propertyType === 'DATE') {
  126. valueType = 'date';
  127. sorter = true;
  128. } else if (item.propertyType === 'TIME') {
  129. valueType = 'time';
  130. sorter = true;
  131. } else if (item.propertyType === 'INT') {
  132. sorter = true;
  133. }
  134. const basicColumns = {
  135. hideInSearch: !InCulde.includes(item.name),
  136. title: item.name,
  137. dataIndex: item.propertyName,
  138. width: 200,
  139. ellipsis: true,
  140. sorter,
  141. valueType,
  142. renderFormItem: (_, p, form) => {
  143. if (item.name === '网络域') {
  144. return NamespaceSearch(_, p)
  145. }
  146. if (_.valueType === 'text') {
  147. return <Input placeholder={`请输入${p.label}`} {...p} />;
  148. } else {
  149. return p.defaultRender(_);
  150. }
  151. },
  152. render: (_, record) => {
  153. if (record[item.propertyName]) {
  154. if (item.propertyType === 'DATETIME') {
  155. return (<Tooltip title={moment(record[item.propertyName]).format('YYYY-MM-DD HH:mm:ss')}>{moment(record[item.propertyName]).format('YYYY-MM-DD HH:mm:ss')}</Tooltip>)
  156. } else if (item.propertyType === 'DATE') {
  157. return (<Tooltip title={moment(record[item.propertyName]).format('YYYY-MM-DD')}>{moment(record[item.propertyName]).format('YYYY-MM-DD')}</Tooltip>)
  158. } else if (item.propertyType === 'TIME') {
  159. return (<Tooltip title={moment(record[item.propertyName]).format('HH:mm:ss')}>{moment(record[item.propertyName]).format('HH:mm:ss')}</Tooltip>)
  160. } else {
  161. return _
  162. }
  163. } else {
  164. return '-';
  165. }
  166. },
  167. };
  168. // x += 200;
  169. return basicColumns;
  170. });
  171. data.push({
  172. title: '标签',
  173. dataIndex: 'tag',
  174. width: 200,
  175. renderFormItem: (_, p, form) => {
  176. return TagtSearch(_, p)
  177. }
  178. })
  179. data.push({
  180. title: '操作',
  181. dataIndex: 'id',
  182. width: 200,
  183. hidden: false,
  184. default: true,
  185. sorter: false,
  186. valueType: 'option',
  187. fixed: 'right',
  188. render: (text, obj) => {
  189. return [
  190. <a
  191. key="1"
  192. style={{ marginRight: 5 }}
  193. onClick={() =>
  194. openDetail({
  195. id: obj._id,
  196. tableName: tableNames,
  197. ciTypeId: obj.ciTypeId,
  198. name: obj.name,
  199. })
  200. }
  201. >
  202. 详情
  203. </a>,
  204. <a key="2" >
  205. <Popconfirm
  206. title="您确认要恢复吗?"
  207. onConfirm={() => operateRun({ id: obj._id, ciTypeId: obj.ciTypeId, type: '0' })}
  208. okText="是"
  209. cancelText="否"
  210. >
  211. 恢复
  212. </Popconfirm>
  213. </a>,
  214. <a key="3" >
  215. <Popconfirm
  216. title="您确认要清空吗?"
  217. onConfirm={() => operateRun({ id: obj._id, ciTypeId: obj.ciTypeId, type: '1' })}
  218. okText="是"
  219. cancelText="否"
  220. >
  221. 清空
  222. </Popconfirm>
  223. </a>,
  224. ];
  225. },
  226. });
  227. setColumns(data);
  228. }
  229. // 获取动态表头
  230. const { run: getColumns, loading } = useRequest(getHeader, {
  231. manual: true,
  232. onSuccess: (result) => {
  233. if (result && result.success) {
  234. dynamicSetColums(result.data)
  235. } else {
  236. message.error(result.message || '网络请求错误', 5);
  237. }
  238. },
  239. });
  240. // 打开详情
  241. const { run: operateRun } = useRequest(operate, {
  242. manual: true,
  243. onSuccess: (result) => {
  244. if (result && result.success) {
  245. message.success(result.codeMessage);
  246. actionRef.current.reload();
  247. }
  248. },
  249. });
  250. // 表格的数据加载方法
  251. const loadData = async (params) => {
  252. const response = await page(params);
  253. return {
  254. success: response.success,
  255. ...response.data.list
  256. };
  257. };
  258. const onTableChange = (p, f, s) => {
  259. setOtheSearch((oldData) => {
  260. return {
  261. ...oldData,
  262. ...{
  263. sorter: s.field || '',
  264. sortOrder: s.order || ''
  265. }
  266. }
  267. })
  268. };
  269. const drawerProps = {
  270. ...basicProps,
  271. onClose: () => {
  272. setBasicProps({
  273. drawerVisible: false,
  274. id: undefined,
  275. tableName: undefined,
  276. });
  277. },
  278. };
  279. const openDetail = (data) => {
  280. setBasicProps({
  281. ...data,
  282. drawerVisible: true,
  283. });
  284. };
  285. /**
  286. * effct
  287. */
  288. useEffect(() => {
  289. if (location.query.tableName) {
  290. setOtheSearch((oldData) => {
  291. return { ...oldData, ...{ tableName: location.query.tableName } }
  292. })
  293. getNameSpaceList();
  294. getTageList();
  295. }
  296. }, [location.query.tableName]);
  297. /**
  298. * render
  299. */
  300. return (
  301. <PageHeaderWrapper
  302. onBack={() => history.push({ pathname: '/recycle' })}
  303. title='资产回收站'
  304. >
  305. <Card loading={loading}>
  306. <ProTable
  307. search={{
  308. labelWidth: 0,
  309. optionRender: (a, b) => {
  310. return [<Button key='id' type='primary' onClick={() => b.form.submit()} > 查询 </Button>, <Button key='id' onClick={() => {
  311. b.form.resetFields(); b.form.submit();
  312. // setUseList({
  313. // userIdList: ''
  314. // })
  315. }}> 重置 </Button>]
  316. }
  317. }}
  318. beforeSearchSubmit={(T) => {
  319. if (T.tag && T.tag.length > 0) {
  320. T.tag = T.tag.join(',')
  321. }
  322. return T
  323. }}
  324. onReset={() => {
  325. setOtheSearch(
  326. (oldData) => {
  327. oldData.namespace = ''
  328. oldData.tags = ''
  329. return oldData
  330. }
  331. )
  332. }}
  333. size={size}
  334. onSizeChange={(size) => {
  335. setSize(size);
  336. }}
  337. columns={columns}
  338. actionRef={actionRef}
  339. request={(params) => loadData(params)}
  340. params={{
  341. ...otheSearch
  342. }}
  343. rowKey="_id"
  344. onChange={(p, f, s) => onTableChange(p, f, s)}
  345. pagination={config.paginationDisplay}
  346. scroll={{ x: x, y: 450 }}
  347. />
  348. </Card>
  349. <DrawerHH {...drawerProps} />
  350. </PageHeaderWrapper>
  351. )
  352. }
  353. export default RecycleDetail

5. 不要在request请求文件中,搞这些花里胡哨的东西

反面教材

  1. import http from '@/utils/request'
  2. import qs from 'qs'
  3. import moment from 'moment'
  4. // 模拟接口
  5. const getInsepectionStatic = async () => {
  6. return http.get('/api/itcc-ops-provider/taskRecord/statisticalPresetType')
  7. }
  8. const queryInsepectionTable = async (value) => {
  9. let parms = {
  10. name: value.name && value.name || '',
  11. userIdList: value.userIdList ? value.userIdList : '',
  12. startTimeStr: value.startTimeStr || '',
  13. endTimeStr: value.endTimeStr || '',
  14. sorter: value.sorter,
  15. sortOrder: value.sortOrder,
  16. current: value.current,
  17. pageSize: value.pageSize
  18. }
  19. return http.get(`/api/itcc-ops-provider/task/page?${qs.stringify(parms)}`)
  20. }
  21. // ---------------------------分割线
  22. // 获取角色下面的所有用户(按名称升序)
  23. const getDefaultUser = async (parmas) => {
  24. return http.get(`/api/tcms-auth-provider/user/getByRoleId?roleId=${parmas}`)
  25. }
  26. // 预设类型 (环境 )下拉框
  27. const getDefaultCheckType = async () => {
  28. // return http.get('/api/itcc-ops-provider/serverVersions/list')
  29. return http.get('/api/itcc-ops-provider/procedureLayout/support/environment')
  30. }
  31. // 检查项预设对应自己定义的就是VMWARE
  32. const getDefaultCheckItem = async (value) => {
  33. return http.get(`/api/itcc-ops-provider/adviceConfig/tree/${value || 1}`)
  34. }
  35. // 新增巡检任务&编辑
  36. const createCheckTaks = async (value) => {
  37. return http.post(`/api/itcc-ops-provider/task/saveOrUpdate`, { data: value })
  38. }
  39. // 获取健康评估分类列表(默认页)
  40. const getScanResultList = (parmas) => {
  41. return http.get(`/api/itcc-ops-provider/scanResult/getScanResultList?${qs.stringify(parmas)}`)
  42. }
  43. // 健康评估表格分页列表
  44. const getScanResultListForTable = (parmas) => {
  45. function toLowerLine (str) {
  46. var temp = str.replace(/[A-Z]/g, function (match) {
  47. return "_" + match.toLowerCase();
  48. });
  49. if (temp.slice(0, 1) === '_') { //如果首字母是大写,执行replace时会多一个_,这里需要去掉
  50. temp = temp.slice(1);
  51. }
  52. return temp;
  53. }
  54. parmas.module = !parmas.module ? null : parmas.module
  55. let finallyDate = Object.assign(
  56. {
  57. taskId: null,
  58. performCount: null,
  59. name: parmas.name || null,
  60. priority: null,
  61. module: null,
  62. serviceVersionId: null,
  63. type: null,
  64. sorter: null,
  65. sortOrder: null,
  66. current: null,
  67. pageSize: null,
  68. }, parmas)
  69. finallyDate.sorter = toLowerLine(finallyDate.sorter)
  70. return http.get(`/api/itcc-ops-provider/scanResult/page?${qs.stringify(finallyDate)}`)
  71. }
  72. // 导出
  73. const getScanResultListTabledDownload = (parmas) => {
  74. let finallyDate = Object.assign(
  75. {
  76. taskId: null,
  77. performCount: null,
  78. name: parmas.refName || null,
  79. priority: null,
  80. module: null,
  81. serviceVersionId: null,
  82. type: null,
  83. sorter: null,
  84. sortOrder: null,
  85. }, parmas)
  86. return http.get(`/api/itcc-ops-provider/scanResult/download/list?${qs.stringify(finallyDate)}`)
  87. }

正确的做法

  1. /*** 某网络域下的网络列表 */
  2. // 获取ip域下的网络列表
  3. const getIPall = async (params: any) => {
  4. return request.get(`/api/itcc-cmdb-provider/network/page?${qs.stringify(params)}`)
  5. }
  6. // 创建和编辑
  7. const createEdite = async (params: any) => {
  8. return request.post('/api/itcc-cmdb-provider/network/saveOrUpdate', { data: params })
  9. }
  10. // 删除
  11. const deleteIp = async (params: any) => {
  12. return request.delete(`/api/itcc-cmdb-provider/network/delete?id=${params}`)
  13. }
  14. // 网段管理
  15. const createShortMange = async (params: any) => {
  16. return request.post(`/api/itcc-cmdb-provider/network/ipManagement`, { data: params })
  17. }
  18. /** 网络段映射的管理 */
  19. // 根据id获取网络段
  20. const initNetwordShort = async (params: any) => {
  21. return request.get(`/api/itcc-cmdb-provider/network/get?id=${params}`)
  22. }
  23. // 保留OCCUPY 使用USE 释放FREE
  24. const createNetworkRelation = async (params: any) => {
  25. return request.post(`/api/itcc-cmdb-provider/ip/releaseOrRetain`, { data: params })
  26. }
  27. /**
  28. * 网络关联选择
  29. */
  30. // 获取默认的可选中器
  31. const defaultNetwork = async () => {
  32. return request.get('/api/itcc-cmdb-provider/network/associatedNetWork')
  33. }
  34. // 创建关联关系
  35. const buildNetworkRelations = async (params: any) => {
  36. console.log('create====>', params);
  37. return request.post('/api/itcc-cmdb-provider/poolVswitch/saveOrUpdate', { data: params })
  38. }
  39. // 选中网络的关联关系
  40. const getNetworkRelations = async (params: any) => {
  41. return request.get(`/api/itcc-cmdb-provider/network/selectPool?id=${params}`)
  42. }
  43. export {
  44. defaultNetwork, buildNetworkRelations, getNetworkRelations,
  45. initNetwordShort, createNetworkRelation,
  46. getIPall, createEdite, deleteIp, createShortMange,
  47. getList, del, save, page,
  48. networkSave, networkDel, validation,
  49. }

6. 变量名我就不多说了,详见(谷歌公司文档规范:https://google.github.io/styleguide/jsguide.html

  1. 原则就是 见名知意,长点没关系

    7. 缩进统一使用两个table

8.有关于到底是不是后面加上分号 ;

js中没有强制使用 ;要求,在现代的的框架中,包括前端三驾马车,都会经过bable转义自己写的js代码。因此我认为从这一点出发 ;号是非必要的 在很多优秀的库中,;号也是没有强制要求的 image.png 下面的这段代码分别来自框架内部源代码 image.png image.png

总结:我认为在这件事情的探讨过度,无疑是浪费时间的东西!!,

二、代码构建模式上的说明

1.IDE的快捷键的学习

  • IDE的快捷键的学习
  • 打开终端 ( ctrl + ` ) 终端新开( ctrl + shift + 5 ), 终端内部切换( alt + 上下左右 ) , 切换终端组()
  • 指定工作目录 新建终端 ( ctrl + shift + ` )
  • 分屏和切换屏: 新开一个分屏( ctrl + \ ),切换分屏( ctrl + up 或者 down ),关闭某一个分屏 ( ctrl + w ) ,屏内组切换( ctrl + k 之后 ctrl + up或者down )
  • 打开指定文件( ctrl + shift + p ),切换到工作树
  • 浏览的操作。依然还是需要鼠标的

2.有关于打包的问题

  • 有关于打包的问题
  • 打包更新下午的时候一次,晚上的时候一次
  • 任务点击的时候也是,中午一次,晚上一次,只有这样才能通知哪些已经确认人去确认,注意啊。你确认过的任务一定是先发包再点击完成!

3.Modal和draw构建方式(各种弹出层的处理)

  • 由于modal和draw这两个东西和当前的页面组件的通信和依赖比较的严重,不好也不是很适合解耦出去,因此,现行我认为比较好的构建方式如下
  • 核心代码
    1. const props = {
    2. visible,
    3. loading,
    4. obj,
    5. onCancel: () => {
    6. setVisible(false);
    7. setObj(false);
    8. },
    9. onSubmit: (values: any) => {
    10. saveData(values);
    11. },
    12. };
  1. // NetworkDomain 网络规划
  2. import React, { useState, useRef } from 'react'
  3. import { useRequest } from 'ahooks';
  4. import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table';
  5. import { PageHeaderWrapper } from '@ant-design/pro-layout';
  6. import config from '@/utils/config';
  7. import { Button, Space, message, Popconfirm, Card, } from 'antd';
  8. import { page, networkSave, networkDel } from './service';
  9. import AddModal from './AddModal';
  10. import { SizeType } from 'antd/lib/config-provider/SizeContext';
  11. import { Link } from 'umi';
  12. /**
  13. * Preset
  14. */
  15. const NetworkDomain: React.FC<any> = () => {
  16. /**
  17. * state
  18. */
  19. const actionRef = useRef<ActionType>();
  20. const [size, setSize] = useState<SizeType>('middle');
  21. const [sorter, setSorter] = useState<any>('');
  22. const [sortOrder, setSortOrder] = useState<any>('');
  23. const [visible, setVisible] = useState<boolean>(false);
  24. const [obj, setObj] = useState<boolean>(false);
  25. /**
  26. * method
  27. */
  28. const onTableChange = (p: any, f: any, s: any) => {
  29. setSorter(s.field || '');
  30. setSortOrder(s.order || '');
  31. };
  32. const { run: delData } = useRequest(networkDel, {
  33. manual: true,
  34. onSuccess: (result) => {
  35. if (result.success) {
  36. actionRef.current?.reset()
  37. actionRef.current?.reload()
  38. }
  39. },
  40. });
  41. const { run: saveData, loading } = useRequest(networkSave, {
  42. manual: true,
  43. onSuccess: (result, params) => {
  44. actionRef?.current?.reload();
  45. if (result.success) {
  46. result.data && message.success(result.codeMessage);
  47. setVisible(false);
  48. setObj(false);
  49. }
  50. },
  51. });
  52. const loadData = async (params: any) => {
  53. const response = await page(params);
  54. return {
  55. success: response.success,
  56. ...response.data,
  57. };
  58. };
  59. const handleEdit = (obj: any) => {
  60. setObj(obj);
  61. setVisible(true);
  62. };
  63. const handleDel = (id: any) => {
  64. delData(id);
  65. };
  66. const props = {
  67. visible,
  68. loading,
  69. obj,
  70. onCancel: () => {
  71. setVisible(false);
  72. setObj(false);
  73. },
  74. onSubmit: (values: any) => {
  75. saveData(values);
  76. },
  77. };
  78. /**
  79. * effct
  80. */
  81. /**
  82. * componentsConfig
  83. */
  84. const header = (
  85. <Space>
  86. <Button
  87. size={size}
  88. type="primary"
  89. onClick={() => {
  90. setVisible(true);
  91. }}
  92. >
  93. 新增
  94. </Button>
  95. </Space>
  96. );
  97. const columns: ProColumns<any>[] = [
  98. {
  99. title: '名称',
  100. key: 'name',
  101. dataIndex: 'name',
  102. render: (_, dom) => {
  103. return <Link
  104. to={{
  105. pathname: '/networkDomain/networkShort',
  106. state: {
  107. areaId: dom.id,
  108. name: dom.name,
  109. description: dom.description
  110. },
  111. }}
  112. >{_}</Link>
  113. }
  114. },
  115. {
  116. title: '描述',
  117. dataIndex: 'description',
  118. ellipsis: true,
  119. },
  120. {
  121. title: '操作',
  122. valueType: 'option',
  123. dataIndex: 'id',
  124. width: 200,
  125. fixed: 'right',
  126. render: (text: any, record: any) => (
  127. <>
  128. <Space>
  129. {/* <Tag color={config.editColor}> */}
  130. <a onClick={() => handleEdit(record)}>编辑</a>
  131. {/* </Tag> */}
  132. {/* <Tag color={config.deleteColor}> */}
  133. <a>
  134. <Popconfirm
  135. title="您确认要删除该全局属性么?"
  136. onConfirm={() => handleDel(record.id)}
  137. okText="是"
  138. cancelText="否"
  139. >
  140. 删除
  141. </Popconfirm>
  142. </a>
  143. {/* </Tag> */}
  144. </Space>
  145. </>
  146. ),
  147. },
  148. ];
  149. /**
  150. * render
  151. */
  152. return (
  153. <PageHeaderWrapper title="网络域规划">
  154. <Card >
  155. <div style={{ minHeight: 650 }}>
  156. <ProTable
  157. actionRef={actionRef}
  158. columns={columns}
  159. request={(params) => loadData(params)}
  160. params={{ sorter, sortOrder }}
  161. size={size}
  162. rowKey="id"
  163. headerTitle={header}
  164. // rowSelection={{}}
  165. search={false}
  166. tableAlertRender={() => false}
  167. onSizeChange={(size) => setSize(size)}
  168. onChange={(p, f, s) => onTableChange(p, f, s)}
  169. pagination={config.paginationDisplay}
  170. scroll={{ x: 1250, y: 450 }}
  171. toolBarRender={(action, { selectedRows }) => []}
  172. />
  173. <AddModal {...props} />
  174. </div>
  175. </Card>
  176. </PageHeaderWrapper>
  177. )
  178. }
  179. export default NetworkDomain
  180. // AddModal 网络域新增编辑的弹出层
  181. import React, { useState, useRef, useEffect, useCallback, useContext } from 'react'
  182. import config from '@/utils/config';
  183. import { Form, Input, Modal } from 'antd';
  184. import { validation } from './service'
  185. /**
  186. * Preset
  187. */
  188. const { TextArea } = Input;
  189. const AddModal: React.FC<any> = ({ obj = {}, visible, onCancel, onSubmit, loading }) => {
  190. /**
  191. * state
  192. */
  193. const [form] = Form.useForm();
  194. /**
  195. * method
  196. */
  197. const onOk = () => {
  198. form
  199. .validateFields()
  200. .then((values) => {
  201. const data = { ...values }
  202. if (obj.id) {
  203. data.id = obj.id
  204. }
  205. onSubmit({ ...data });
  206. })
  207. .catch((info) => {
  208. console.log('Validate Failed:', info);
  209. });
  210. };
  211. const close = () => {
  212. clear();
  213. onCancel();
  214. };
  215. const clear = () => {
  216. form.resetFields();
  217. };
  218. const validationName = (rule, value, callback) => {
  219. try {
  220. let data = {}
  221. if (obj && obj.id) {
  222. data.id = obj.id
  223. }
  224. data.name = value
  225. validation(data).then((res) => {
  226. if (res && res.data && res.success) {
  227. callback();
  228. } else {
  229. callback('网络域已存在');
  230. }
  231. })
  232. data = null
  233. } catch (err) {
  234. callback(err);
  235. }
  236. }
  237. /**
  238. * effct
  239. */
  240. useEffect(() => {
  241. if (visible) {
  242. form.setFieldsValue({
  243. ...obj,
  244. });
  245. }
  246. }, [visible]);
  247. /**
  248. * componentsConfig
  249. */
  250. /**
  251. * render
  252. */
  253. return (
  254. <>
  255. <Modal
  256. visible={visible}
  257. title={`${obj.id ? '编辑网络域' : '新增网络域'}`}
  258. onCancel={() => close()}
  259. confirmLoading={loading}
  260. afterClose={() => clear()}
  261. width={700}
  262. okText="提交"
  263. cancelText="取消"
  264. onOk={() => onOk()}
  265. >
  266. <Form form={form} layout="horizontal" name="networkForm">
  267. <Form.Item
  268. {...config.modalFormItemLayout}
  269. label="网络域"
  270. name="name"
  271. rules={[
  272. {
  273. required: true,
  274. message: '请输入网络域名称',
  275. },
  276. { validator: validationName },
  277. ]}
  278. >
  279. <Input placeholder="请输入网络域名称" />
  280. </Form.Item>
  281. <Form.Item
  282. label="描述"
  283. {...config.modalFormItemLayout}
  284. name="description">
  285. <TextArea />
  286. </Form.Item>
  287. </Form>
  288. </Modal>
  289. </>
  290. )
  291. }
  292. export default AddModal

4. 文件夹层次的构建方案和命名方案

个人推荐的做法
page下仅仅是放页面用来组装组件,而不应该存放各种各样的组件的具体实现,component里了解一下,component里才是放置具体组件的所在位置
image.png

5.如何只tabl中构建一些独立且又各自有状态的组件?

我们先来看看,你如何完成如下的效果

很明显,要想实现这样的效果你必须让没一个row数据都搞定独立的加载一个组件出来,这个时候,性能和效果就要做取舍了