2019-10-09课件管理功能部分注意事项

2019-10-10  本文已影响0人  菩灵
POST发送的newValue:
{
  coursewareFileName: "PDF测试文件4.pdf"
  coursewareFileUid: "rc-upload-1570667615043-8"
  coursewareName: "哈法"
  coursewareSourceUrl: "http://www.yuntsoft.com:7389/group1/M00/01/94/rBDZEl2efb6AAvQuAACwHeXRbq0429.pdf"
  coursewareType: 0
}
GET得到的后端数据response.records[i]:
{
  coursewareFileName: null
  coursewareFileUid: null
  coursewareId: 64
  coursewareName: "噶"
  coursewareSourceUrl:         "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
  coursewareType: 0
  coursewareTypeName: "文件"
  createUserId: null
  createUserName: "市场监管"
  dele: 0
  edit: null
  gmtCreate: "2019-10-09 15:07:12"
}
1、@connect与model建立连接
// 引入dva中的connect函数
import { connect } from 'dva';
@connect(({ courseware, loading }) => ({
  courseware,
  loading,
}))
2、在业务处理中发送dispatch请求,注意请求的是命名空间下的update方法
  /**
   * 更新
   * @param params
   */
  handleUpdate = params => {
    const { dispatch } = this.props;
    console.log('调用主页面更新方法')
    dispatch({
      type: 'courseware/update',
      payload: params,
      callback: this.handleUpdateCall,
    });
  };
3、model中的update是一个异步generator函数,注意请求了一个updateCourseware的函数
    /**
     * 更新模板
     * @param payload
     * @param callback
     * @param call
     * @param put
     * @returns {IterableIterator<*>}
     */ *update({ payload, callback }, { call }) {
      const response = yield call(updateCourseware, payload);
      if (response.resultCode === 0) {
        notification.success({ message: '更新成功!' });
      } else {
        notification.error({ message: '更新失败!', description: response.resultMsg });
      }
      if (callback && typeof callback === 'function') {
        callback(response);
      }
    },
4、在model的文件开头从services中引入updateCourseware
import {
  queryCoursewareList,
  addCourseware,
  deleteCourseware,
  updateCourseware
} from '../services/courseware'
5、在services文件中暴露出异步请求方法
export async function updateCourseware(params) {
  return request(`${config.domain}/courseware`, {
    method: 'PUT',
    body: params,
  });
}

至此,一个完整的请求动作可以正常进行
注意主页面的dispatch动作命名空间下的异步方法名要和model一致,model执行请求的函数名要和service文件一致,model文件必须引入service文件暴露的函数。
只要任何一个步骤不对,轻则无法发送请求,重则dispatch(...).then is not a function
13、为防止Radio单选框值改变,文件类型不变导致错误提交的bug,需要在handleRadioClick函数中将state中的fileList和全局的fileIds置空
14、日期选择框

import moment from 'moment'; // 引入时间处理模块
import { DatePicker } from 'antd'
const { RangePicker } = DatePicker;

                <RangePicker
                  style={{ width: '80%' }}
                  ranges={{
                    "今天":[moment(),moment()]
                  }}
                  disabledDate={(current) => {
                    console.log(current)
                    return current && current < moment().subtract(1, "days")
                  }}
                  showTime={{
                    hideDisabledOptions: true,
                    defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('11:59:59', 'HH:mm:ss')],
                  }}
                />
disableDate属性禁用日期:
handleData(time){
        if(!time){
            return false
        }else{
        // 大于当前日期不能选 time > moment()
        // 小于当前日期不能选 time < moment().subtract(1, "days")
        // 只能选前7后7 time < moment().subtract(7, "days") || time > moment().add(7, 'd')
            return time < moment().subtract(7, "days") || time > moment().add(7, 'd')
        }
    }
 
<RangePicker  disabledDate={this.handleData}/>

15、点击增加一行的改写


image.png

或者:


image.png

16、modal以及Table上的属性,如果是布尔值,需要用{}而不是用"",比如bordered={false}

17、当无法通过表单双向绑定验证数据的时候可以用if判断代替,用notifaction.warning提示

      if(fieldsValue.templateName === undefined || fieldsValue.templateName === null || fieldsValue.templateName === ""){
        notification.warning({
          message: "模板名称不能为空",
        });
        return;
      }

18、在<Row>标签的包裹下,用<Col>标签将<FormItem>包裹起来即可实现一行显示,响应式属性: md: 8, lg: 24, xl: 48 ,sm:24(响应式栅格有24份)

19、多重判断:initialValue:deptCanteenSelectList && deptCanteenSelectList.length > 0 ? deptCanteenSelectList[0].deptId : undefined使用逻辑运算符+三元表达式

                当前审核状态:
                {auditStateNum === '0' || auditStateNum === null
                  ? '待提交'
                  : auditStateNum === '1'
                  ? '待审核'
                  : auditStateNum === '2'
                  ? '已通过'
                  : auditStateNum === '3'
                  ? '未通过'
                  : '-'}

如果前两项条件都为真才返回第三项:

{(auditStateNum === '0' || auditStateNum === null || auditStateNum === '3') && getUserInfo('perms').includes('cookbook:add') && (
     <Button type="primary" onClick={this.handleOnClick}>
    提交审核
    </Button>
)}

多重逻辑运算符,flag最后取到一个布尔值
const flag = highRiskFood[index] !== undefined && highRiskFood[index].length > 0

20、整行删除技巧:

    // 行删除
    const {foodList} = this.state;
    const index = foodList.findIndex(item => row.key === item.key);
    foodList.splice(index,1);

21、新增培训--->培训内容部分思路:Table中的数据保存到state中,点击保存的时候进行校验,如果菜单太长可以notification.info整个界面提示

    form.validateFields((err,fieldsValue) => {
        if (err) return;
        if(foodList.length ===0){
          notification.warning({
            message: "菜谱目录不能为空",
          });
          return;
        }
        handleAdd(this.handleAddData(foodList,fieldsValue,nowAddData));
      },
    );

提交的时候可以对不需要的数据直接使用delete方法:

    foodList.forEach(item =>{
      const food = {...item};
      food.dishId = fieldsValue[`dishId${item.key}`].substring(fieldsValue[`dishId${item.key}`].indexOf('id:')+3); // 菜品id
      food.employeeId = fieldsValue[`employeeId${item.key}`].substring(fieldsValue[`employeeId${item.key}`].indexOf('id:')+3); // 负责厨师id
      delete food.dishName;
      dishFoodDTOList.push(food);
    });

点击添加课件按需弹出相应模态框,通过子组件传值保存到父组件的courseList中,父组件校验courseList不需要form方法,可以直接校验
子组件向父组件传值,需要父组件先传递一个方法过去,子组件触发方法将值作为参数传入,父组件调用该方法将值保存到自己state中,比如子组件handleSubmit直接调用this.handleAddCourseware,到父组件中接收传入的值this.setState

当新建课件完成之后,新建可见被课件名称取代,可以考虑使用components 覆盖默认的 table 元素

针对Radio.Group组件,form.getFileDecorator方法定义的名称不允许相同,否则radio的值会互相影响大

新增课程Table区域的DataSource生成主要依靠新增课程这个按钮的add事件,在事件每点击一次DataSource

删除按钮针对的也是dataSource上的操作,每点击一下删除一行

22、总结:新增一个模态框组件的完整流程

    /**
     * 定义传递给子组件的对象
     * */
    const createByWareHandle = {
      handleAdd: this.handleCreateByWare,
      handleModalVisible: () => {
        this.setState({ createByWareVisible: false });
      },
    };

7、主页面组件创建之后(和render平级)定义处理子组件的方法:

  /**
   * 根据现有课件增加
   * @param params
   */
  handleCreateByWare = params => {
    const { dispatch } = this.props;
    dispatch({
      type: 'courseware/add',
      payload: params,
      callback: this.handleCreateByWareCall,
    });
  };

  /**
   * 根据现有课件增加之后的回调函数
   * @param res
   */
  handleCreateByWareCall = res => {
    if (res.resultCode === 0) {
      const { dispatch } = this.props;
      const { formValues,nowSelectCanteen } = this.state;
      dispatch({
        type: 'cookBookConfig/fetchCookBookList',
        payload: { ...formValues,deptId:nowSelectCanteen },
        callback: this.handleCookBookListCallBack,
      });
      this.setState({ createVisible: false });
    }
  };

8、子组件开始书写,首先头部引入modal组件import { Modal } from 'antd'

9、在主页面给控制子组件可视的元素绑定事件

  /**
   * 点击按需添加课件
   * */
  addCoureWare = () => {
    const { trainType, createByWareVisible, createBySelfVisible } = this.state
    if(trainType === 0){ // 从现有课件添加
      this.setState({
        createByWareVisible:true,
      })
    }else{
      this.setState({
        createBySelfVisible:true,
      })
    }
  }

10、子组件制作页面

    <Modal
      width={800}
      maskClosable={false}
      // destroyOnClose
      title="添加课件"
      visible={modalVisible}
      onCancel={() => handleModalVisible()}
      // footer={footerButton}
    >
      写点内容
    </Modal>

11、子组件render函数中从父组件接收所需属性和方法

    const {
      modalVisible,
      handleModalVisible,
      form,
    } = this.props;

12、注意:modal上面的onOK和onCancel属性接收的是一个回调函数,必须加括号表示执行了,否则只传入一个方法是不会自动执行的

        onCancel={() => handleModalVisible()}
        onOk={() => this.okHandle()}

13、上传课件增加培训数据流程:

    const courseObj = {
      key : indexNum, // 每一门课程的key
      courseName : "", // 每一门课程的名称
      coursewareName : "", // 课程对应的课件名称啊
      coursewareId : "" // 课程对应的课件的Id
    };

2、每次点击删除的时候传入row,根据row.key找到所在对象的index值,splice掉整个对象

    const index = courseList.findIndex(item => row.key === item.key);
    courseList.splice(index,1);

3、对特定项点击添加课件的时候,传入row,根据row得到当前项的key值,key需要将后台传回来的coursewareName和coursewareId以及当前页面的courseName组合在一起生成当前想的courseObj,并且替换掉courseList光有key的那一项,splice(index,Obj),只要用map方法遍历courseList数组,找到item.key === current.key的一项,进行相应项的改写即可

4、获取课程名称部分,通过form.getFileDecorator绑定courseName$(record.key),在handleSubmit的时候通过foreach遍历赋值

5、提交校验
自定义校验:

绑定的时候规则置空
              {form.getFieldDecorator('content', {})(
                <BraftEditor
                  controls={controls}
                  extendControls={extendControls}
                  onChange={this.handleChange}
                  style={{ border: '1px solid #bfbfbf' }}
                />
            )}
校验的时候取值做判断
      if (fieldsValue.content.isEmpty()) {
        message.error('资讯内容不能为空');
        return;
      }
      if (tags.length === 0) {
        message.error('标签不能为空');
        return;
      }
      if (fieldsValue.newsTitle.length > 30) {
        message.error('资讯标题过长,30字符以内');
        return;
      }

6、添加培训学员部分可参考:检测管理——样品管理——采样食堂
使用treeSelect标签,值需要用递归获取,

7、 时间数据的传递:不能把moment对象直接POST,而是要先格式化
trainStartTime:values.trainTime[0].format('YYYY-MM-DD HH:mm:ss'), // .d trainEndTime:values.trainTime[1].format('YYYY-MM-DD HH:mm:ss'), // .d

上一篇下一篇

猜你喜欢

热点阅读