最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】剧本编写系统中优化全部剧本列表页

工作和技术 crifan 832浏览 0评论
现有的剧本编写系统中,全部剧本列表页,是可以正常显示全部的剧本的列表的:
但是显示的数据不对,应该改为:超级用户权限的,所有的用户的剧本的列表。
并且,支持从别处传入的参数去过滤,比如点击某个用户:
传入了:author_id
虽然显示列出了对应数据
但是作者的下拉框中,不是所有的成员
以及不支持传入:
group的id:
http://localhost:8000/#/script/all-script-list?group_id=6
某个用户的是否已发布:
http://localhost:8000/#/script/all-script-list?author_id=4c271812-d36e-4585-a1af-bd7ea6c6d449&publish_status=1
http://localhost:8000/#/script/all-script-list?author_id=4c271812-d36e-4585-a1af-bd7ea6c6d449&publish_status=0
现在去优化,支持这些操作。
期间,为了能获取当前所有用户的列表,而且所有的用户,都应属属于某个script的funciton group的,所以找了找代码,发现可以借用已有的functionGroup/fetch去获取到所有的group的列表
但是每个group中,没有包含members,所以打算去加上members,所以先去解决:
【已解决】Django中序列化一个模型对象中的另外子对象的数组
此时即可得到带members的script的function group了。
然后就可以去过滤得到所有的组员了
所以此处页面上还要添加剧本组和剧本成员列表:
【已解决】全部剧本列表中添加剧本组和组成员列表
其中涉及到,先去给返回的script的数据中,加上能有当前已加入的剧本组的信息:
【已解决】Django的Serializer中如何序列化Script中的Author的Function Group
和:
【已解决】js中判断变量类型是否是字符串还是int
然后再去想办法支持前端传递的各种参数
  • 传入group_id时,返回整个script的group的members的剧本列表
  • 传入author_id时,返回单个用户的剧本列表
    • 传入group_id+author_id时,自己确保author是属于此group的,所以忽略group_id,等价于:只传入author_id
然后先去解决:
【已解决】Django中如何查询一个对象包含于一个列表内均可
然后就可以继续优化代码了。
【已解决】Reactjs警告:[eslint] Expected ‘this’ to be used by class method (class-methods-use-this)
然后再去优化,参数传递进来后,要选择对应的选项:
现在是缺少了审核状态:
然后再去:
【已解决】reactjs中setState如何更新设置dict对象中某个key键的值
【总结】
然后现在可以用代码:
import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
import {
  Row,
  Col,
  Card,
  Form,
  Input,
  Button,
  Divider,
  Popconfirm,
  Tooltip,
  Select,
} from 'antd';
import { routerRedux } from 'dva/router';
import SimpleTable from 'components/SimpleTable';
import PageHeaderLayout from '../../layouts/PageHeaderLayout';
import styles from '../List/TableList.less';

import { scriptWordExportUrl } from '../../services/api';
import { getEncodedToken } from '../../utils/token';
import { isEmptyObj } from '../../utils/utils';

const queryString = require('query-string');

const FormItem = Form.Item;
const { Option } = Select;

@connect(({ script, topic, user, functionGroup, loading }) => ({
// @connect(({ script, topic, user, functionGroup }) => ({
    script,
  topic,
  currentUser: user.currentUser,
  functionGroup,
  loading: loading.models.script,
}))
@Form.create()
export default class GroupOwnerScriptList extends PureComponent {
  state = {
    formValues: {},
    currentPage: 1,
    pageSize: 20,
    first_level_topic: [],
    // second_level_topic: [],
    groupMemberList: [],
  };

  componentWillMount() {
    console.log(`GroupOwnerScriptList componentWillMount`)

    this.fetchUser = this.fetchUser.bind(this)
    this.updateGroupMemberList = this.updateGroupMemberList.bind(this)
    this.updateFormFieldAndState = this.updateFormFieldAndState.bind(this)

    console.log(`this.props=`, this.props)
    const { currentUser} = this.props;
    console.log(`currentUser=`, currentUser)

    this.fetchTopicList()

    const queryParamDict = this.generateQueryParamDict()
    this.updateGroupOwnerScriptList(queryParamDict)
  }

  componentDidMount() {
    console.log(`GroupOwnerScriptList componentDidMount`)
    const { currentUser} = this.props;
    console.log(`currentUser=`, currentUser)

    if(isEmptyObj(this.props.currentUser)) {
      this.fetchUser(this.updateGroupMemberList)
    } else {
      this.updateGroupMemberList()
    }
  }

  onSecondOptionChange(topicList, value) {
    const { form } = this.props;
    form.setFieldsValue({
      second_level_topic: value || '',
    });

    // this.setState({
    //   second_level_topic: value || '',
    // });
  }

  fetchUser(callback=undefined){
    console.log("fetchUser: callback=", callback)

    this.props.dispatch({
      type: 'user/fetchCurrent',
    }).then( () => {
      if (callback){
        callback()
      }
    })
  }

  updateFormFieldAndState(){
    console.log("updateFormFieldAndState: this", this)

    const queryParamDict = this.generateQueryParamDict()
    console.log("queryParamDict=", queryParamDict)

    if (queryParamDict.author_id) {
      this.props.form.setFieldsValue({
        author_id: queryParamDict.author_id,
      });
    }

    if (queryParamDict.publish_status){
      this.props.form.setFieldsValue({
        publish_status: queryParamDict.publish_status,
      })
    }
    console.log(`updated form getFieldsValue=`, this.props.form.getFieldsValue())

    const curFormValues = this.state.formValues
    console.log(`curFormValues=`, curFormValues)
    if (queryParamDict.publish_status) {
      curFormValues.publish_status = queryParamDict.publish_status
    }

    if (queryParamDict.author_id) {
      curFormValues.author_id = queryParamDict.author_id
    }
    console.log(`updated curFormValues=`, curFormValues)

    this.setState({
      formValues: curFormValues,
    })
  }

  updateGroupMemberList(){
    console.log("updateGroupMemberList: this", this)
    const { currentUser} = this.props;
    console.log(`currentUser=`, currentUser)

    let curFunctionGroup = {}
    if (currentUser &&
        currentUser.functionGroup &&
        currentUser.functionGroup.scriptGroup &&
        currentUser.functionGroup.scriptGroup.joinedGroup) {
        curFunctionGroup = currentUser.functionGroup.scriptGroup.joinedGroup
        console.log(`curFunctionGroup=`, curFunctionGroup)
        const curGroupMemberList = curFunctionGroup.members
        console.log(`curGroupMemberList=`, curGroupMemberList)
        this.setState({
          groupMemberList: curGroupMemberList,
        })

        this.updateFormFieldAndState()
    }

    // if (curFunctionGroup) {
    //   const functionGroupID = curFunctionGroup.id;
    //   if (functionGroupID) {
    //     this.props.dispatch({
    //       type: 'functionGroup/fetchFunctionGroupAndMembers',
    //       payload: functionGroupID,
    //     }).then((respGroupAndMembers) => {
    //       console.log(`fetchFunctionGroupAndMembers response`)
    //       console.log(`respGroupAndMembers=`, respGroupAndMembers)
    //       console.log(`this.props=`, this.props)
    //       const { functionGroup: { functionGroup, members } } = this.props;
    //       // const { functionGroup, members } = this.props;
    //       console.log(`functionGroup=`, functionGroup)
    //       console.log(`members=`, members)

    //       if (members) {
    //         const membersList = members.results
    //         console.log(`membersList=`, membersList)

    //         console.log(`before setFieldsValue authorId=`, authorId)

    //         const { form } = this.props;
    //         form.setFieldsValue({
    //           author_id: authorId || "",
    //         });

    //         const { formValues } = this.state;
    //         console.log(`formValues=`, formValues)
    //         const newFormValues = {
    //           author_id: authorId || "",
    //           ...formValues,
    //         };
    //         console.log(`newFormValues=`, newFormValues)
    //         this.setState({
    //           formValues: newFormValues,
    //         });

    //         this.setState({
    //           groupMemberList: membersList || [],
    //         });
    //       }
    //     });
    //   }
    // }
  }

  fetchTopicList(){
    // topic select 取所有的 topic
    const params = {
      page_size: 1000,
    }

    this.props.dispatch({
      type: 'topic/fetch',
      payload: params,
    })
  }

  updateGroupOwnerScriptList(queryParamDict = {}){
    console.log("updateGroupOwnerScriptList: queryParamDict=", queryParamDict)
    const { dispatch } = this.props

    dispatch({
      type: 'script/fetchGroupOnwerScripts',
      payload: queryParamDict,
    });
  }


  generateQueryParamDict(){
    const searchStr = this.props.location.search
    console.log(`generateQueryParamDict: searchStr=`, searchStr)
    const parsedQueryString = queryString.parse(searchStr);
    console.log(`parsedQueryString=`, parsedQueryString)
    return parsedQueryString
  }


  handleFirstOptionChange(topicList, value) {
    const { form } = this.props;
    form.setFieldsValue({
      topic: value,
      second_level_topic:  '', // when first topic change, clear second topic
    });

    this.setState({
      first_level_topic: topicList[value],
      // second_level_topic: '', // when first topic change, clear second topic
    });
  }

  handleEdit = (record) => {
    const { dispatch } = this.props;
    dispatch(routerRedux.push({
      pathname: '/script/script-edit',
      search: `?script_id=${record.id}`,
    }));
  };

  handleReview = (record) => {
    const { dispatch } = this.props;
    dispatch(routerRedux.push({
      pathname: '/script/script-review',
      search: `?script_id=${record.id}`,
    }));
  };

  handleHistories = (record) => {
    const { dispatch } = this.props;
    dispatch(routerRedux.push({
      pathname: '/script/script-histories',
      search: `?script_id=${record.id}`,
    }));
  };

  handleExport = (record) => {
    const { dispatch } = this.props;
    dispatch({
      type: 'script/scriptWordExport',
      payload: record.id,
    });
  };

  handleDeleteScript(scriptID) {
    const { dispatch } = this.props;
    dispatch({
      type: 'script/deleteScript',
      payload: scriptID,
    }).then(() => {
      dispatch({
        type: 'script/fetchGroupOnwerScripts',
      });
    });
  };


  handleDetail = (record) => {
    const { dispatch } = this.props;
    dispatch(routerRedux.push({
      pathname: '/script/script-detail',
      search: `?script_id=${record.id}`,
    }));
  };

  handleSearch = e => {
    e.preventDefault();

    const { dispatch, form } = this.props;

    form.validateFields((err, fieldsValue) => {
      console.log(`err=`, err, `fieldsValue=`, fieldsValue)

      if (err) return;

      const values = {
        ...fieldsValue,
      };
      console.log(`values=`, values)

      this.setState({
        formValues: values,
      });

      // console.log(`formValues=`, this.state.formValues)

      dispatch({
        type: 'script/fetchGroupOnwerScripts',
        payload: values,
      });
    });
  };

  handleFormReset = () => {
    const { form, dispatch } = this.props;
    form.resetFields();
    this.setState({
      formValues: {},
    });
    dispatch({
      type: 'script/fetchGroupOnwerScripts',
      payload: {},
    });
  };


  handleStandardTableChange = (pagination) => {
    console.log(`handleStandardTableChange: pagination=`, pagination)

    const { dispatch } = this.props;
    const { formValues } = this.state;
    console.log(`formValues=`, formValues)

    this.setState({
      currentPage: pagination.current,
      pageSize: pagination.pageSize,
    });

    const params = {
      page: pagination.current,
      page_size: pagination.pageSize,
      ...formValues,
    };
    console.log(`params=`, params)

    dispatch({
      type: 'script/fetchGroupOnwerScripts',
      payload: params,
    });
  };

  renderSimpleForm() {
    const { getFieldDecorator } = this.props.form;

    const topicList = this.props.topic.topics;

    const firstLevelOptions = Object.keys(topicList).map(first => <Option key={first}>{first}</Option>);
    const secondLevelOptions = this.state.first_level_topic.map(second => <Option key={second}>{second}</Option>);

    const authorOptions = this.state.groupMemberList.map(eachAuthor => <Option key={eachAuthor.id}>{eachAuthor.username}</Option>);

    const selectFormItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 7 },
      },
      wrapperCol: {
        xs: { span: 36 },
        sm: { span: 18 },
        md: { span: 16 },
      },
    };

    return (
      <Form onSubmit={this.handleSearch} layout="inline">
        <Row gutter={{ md: 8, lg: 24, xl: 48 }}>

          <Col md={6} sm={18}>
            <FormItem label="作者">
              {getFieldDecorator('author_id')(
                // <Select placeholder="请选择" style={{ width: '100%' }}>
                <Select
                  showSearch
                  optionFilterProp="children"
                  filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
                  style={{ width: '100%' }}
                  placeholder="作者"
                >
                  {authorOptions}
                </Select>
              )}
            </FormItem>
          </Col>

          <Col md={8} sm={18}>
            <FormItem label="Place/Title">
              {getFieldDecorator('search')(<Input placeholder="Place/Title" />)}
            </FormItem>
          </Col>

          <Col md={6} sm={18}>
            <FormItem label="审核状态">
              {getFieldDecorator('publish_status')(
                <Select placeholder="请选择" style={{ width: '100%' }}>
                  <Option value="">全部</Option>
                  <Option value="0">未通过</Option>
                  <Option value="1">已通过</Option>
                </Select>
              )}
            </FormItem>
          </Col>

          <Col md={12} sm={18}>
            <FormItem {...selectFormItemLayout} label="Topic" style={{ marginBottom: 5 }} >
              {getFieldDecorator('topic', {
                rules: [{ required: false, message: '请选择Topic'}],
              })(
                <Select
                  showSearch
                  optionFilterProp="children"
                  filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
                  style={{ width: '46%' }}
                  onChange={this.handleFirstOptionChange.bind(this, topicList)}
                  placeholder="一级Topic"
                >
                  {firstLevelOptions}
                </Select>
              )}
              <span style={{ marginLeft: 5 }} className="ant-form-text"> - </span>
              {getFieldDecorator('second_level_topic', {
                rules: [{ required: false, message: '请选择Topic'}],
              })(
                <Select
                  showSearch
                  optionFilterProp="children"
                  filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
                  style={{ width: '46%' }}
                  onChange={this.onSecondOptionChange.bind(this, topicList)}
                  placeholder="二级Topic"
                >
                  {secondLevelOptions}
                </Select>
              )}
            </FormItem>
          </Col>

          <Col md={12} sm={18}>
            <span className={styles.submitButtons}>
              <Button type="primary" htmlType="submit">
                查询
              </Button>
              <Button style={{ marginLeft: 8 }} onClick={this.handleFormReset}>
                重置
              </Button>
            </span>
          </Col>
        </Row>
      </Form>
    );
  }


  render() {
    const { script: { groupOwnerScripts }, loading } = this.props;
    const { currentPage, pageSize } = this.state;

    console.log("groupOwnerScripts=", groupOwnerScripts)

    const columns = [
      {
        title: '序号',
        dataIndex: 'no',
        rowKey: 'no',
        fixed: 'left',
        render(text, record, index) {
          const no = (currentPage - 1) * pageSize
          return no + index + 1;
        },
      },
      {
        title: '作者',
        dataIndex: 'author',
        rowKey: 'author',
      },
      {
        title: 'Place',
        dataIndex: 'place',
        rowKey: 'place',
        width: 80,
      },
      {
        title: 'Title',
        dataIndex: 'title',
        rowKey: 'title',
        width: 120,
      },
      {
        title: '一级Topic',
        dataIndex: 'topic',
        rowKey: 'topic',
        width: 100,
      },
      {
        title: '二级Topic',
        dataIndex: 'second_level_topic',
        rowKey: 'second_level_topic',
        width: 100,
      },
      {
        title: 'Age',
        dataIndex: 'age',
        rowKey: 'age',
        width: 60,
        render(text, record) {
          const age = `${record.age_start}-${record.age_end}`
          return age;
        },
      },
      {
        title: '对话轮数',
        dataIndex: 'dialog_count',
        rowKey: 'dialog_count',
        width: 60,
      },
      {
        title: '编辑状态',
        dataIndex: 'edit_status',
        rowKey: 'edit_status',
        width: 60,
      },
      {
        title: '发布状态',
        dataIndex: 'publish_status',
        rowKey: 'publish_status',
        width: 60,
      },
      {
        title: 'Version',
        dataIndex: 'version',
        rowKey: 'version',
      },
      {
        title: '批注人',
        dataIndex: 'review.reviewer',
        rowKey: 'reviewer',
      },
      {
        title: '批注内容',
        dataIndex: 'review.remark',
        rowKey: 'remark',
        render: (text) => {
          let textSlice = '';
          if (text) {
            textSlice = text.slice(0, 10);
          }
          return (
            <Tooltip title={text}>
              <span>{textSlice}</span>
            </Tooltip>
          );
        },
      },
      {
        title: '批注结果',
        dataIndex: 'review.result',
        rowKey: 'result',
      },
      {
        title: '创建时间',
        dataIndex: 'created_at',
        rowKey: 'created_at',
      },
      {
        title: '更新时间',
        dataIndex: 'updated_at',
        rowKey: 'updated_at',
      },
      {
        title: '操作',
        dataIndex: 'operate',
        rowKey: 'operate',
        fixed: 'right',
        width: 180,
        render: (text, record) => {
          const encodedJwtToken = getEncodedToken()
          const exportScritpUrl = scriptWordExportUrl(record.id, encodedJwtToken)
          return (
            <Fragment>
              <a href="javascript:;" onClick={() => this.handleDetail(record)} >查看</a>
              <Divider type="vertical" />
              <a href="javascript:;" onClick={() => this.handleEdit(record)} >编辑</a>
              <Divider type="vertical" />
              <a href="javascript:;" onClick={() => this.handleReview(record)} >审核</a>
              <Divider type="vertical" />
              <a href="javascript:;" onClick={() => this.handleHistories(record)} >所有版本</a>
              <Divider type="vertical" />
              <a href={exportScritpUrl} >导出</a>
              <Divider type="vertical" />
              <Popconfirm title="是否删除次剧本?" onConfirm={() => this.handleDeleteScript(record.id)} >
                <a>删除</a>
              </Popconfirm>
            </Fragment>
          )
        },
      },
    ];

    return (
      <PageHeaderLayout title="组员剧本列表">
        <Card bordered={false}>
          <div className={styles.tableList}>
            <div className={styles.tableListForm}>{this.renderSimpleForm()}</div>
            <SimpleTable
              loading={loading}
              data={groupOwnerScripts}
              columns={columns}
              scroll={{ x: 1800 }}
              rowKey={'id'}
              onChange={this.handleStandardTableChange}
            />
          </div>
        </Card>
      </PageHeaderLayout>
    );
  }
}
可以实现:
从统计页面,点击后,可以把相关参数都传递过来,且表格中列表选项可以选择对应值,且可以将相关参数传递到后台返回对应数据:
http://localhost:8000/#/script/all-script-list?group_id=5&author_id=44c3de7f-a0e4-4a62-8f64-720044ad6d03&publish_status=0
内部过程涉及到:
获取到组的列表和组员的列表
前端均可选择了:
以及审核状态:
注:
后续再去优化:组员剧本列表
其中涉及到:
【已解决】Antd Pro中警告:Warning: Each record in table should have a unique `key` prop,or set `rowKey` to an unique primary key

转载请注明:在路上 » 【已解决】剧本编写系统中优化全部剧本列表页

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
80 queries in 0.201 seconds, using 22.21MB memory