当前位置: 首页 > news >正文

表单的前端数据流向

在CRM项目中,会涉及很多张表单。每张表单的前端代码都会放在一个单独的文件夹中。这个文件夹下包含三个文件,分别是:

  1. index.js(以下称为 index):负责组件的渲染和交互逻辑。
  2. model.js(以下称为 model):负责状态管理和业务逻辑。
  3. service.js(以下称为 service):负责接口的定义和调用。
数据流向
  • index 调用 model 的方法。
  • model 的方法中会调用 service 的接口。
  • service 文件定义了与表单相关的所有接口。
状态管理的设计

在项目中,状态变量可以存在于 index 和 model 中,但状态变量的归属并不是固定的,而是根据具体的需求来决定。状态变量的类型可以分为以下两种:

  1. 控制组件展示的状态变量
    用于控制组件的隐藏、显示等 UI 状态。

  2. 控制数据展示的状态变量
    用于存储表单的输入值、接口返回的数据等业务状态。

状态变量的使用和更新
  1. 状态变量的使用

    • index 可以使用自己的状态变量(通过 this.state.状态变量)或 model 的状态变量(通过 this.props.状态变量)。
    • model 的状态变量可以通过 index 的 props 获取,但 model 不直接使用 index 的状态变量。
  2. 状态变量的更新

    • index 的状态变量通过 this.setState({状态变量: 值}) 更新。
    • model 的状态变量可以通过 index 或 model 自身调用 actions.业务对象名字.updateState({状态变量: 值}) 的方式更新。
交互逻辑

在表单页面中,每次用户点击或触发交互时,会调用对应的方法。这些方法的执行逻辑如下:

  1. 调用接口获取数据(通过 service)。
  2. 根据接口返回的数据更新状态变量(通过 actions.updateState 方法)。
  3. 状态变量的改变会触发组件的重新渲染,从而实现组件的展示或数据的更新。

举个例子,当我点击“分配”按钮中的分配负责人的时候,前端代码的逻辑是这样的:

1. index.js 文件

在 index.js 文件中,主要处理用户交互逻辑。以下是 Buttons 组件的定义和事件绑定:

<Buttons
    buttonTpl={listBtnsTpl} // 按钮模板
    onClick={this.listBtnsClick} // 点击事件处理函数
/>
  • Buttons 组件:一个通用按钮组件,通过 buttonTpl 属性传入按钮配置模板,通过 onClick 属性绑定点击事件处理函数。
  • listBtnsClick 方法:处理按钮点击事件,根据不同的按钮类型执行不同的逻辑。

以下是 listBtnsClick 方法的代码:

listBtnsClick(clickBtn, belongBtn) {
    const clickedKey = _.get(clickBtn, "key"); // 获取点击按钮的 key
    const belongBtnKey = _.get(belongBtn, "key"); // 获取所属按钮的 key

    if (belongBtnKey === "add") {
        // 新增操作
        let obj = belongBtn.comp.filter(item => item.key == clickBtn.key);
        obj = obj ? obj[0] : {};

        _this.onClickNew({
            custChanTypeName: obj.name,
            custChanTypeId: obj.key
        });
    } else if (clickedKey === "add") {
        // 特殊新增操作
        if (clickBtn?.comp?.length === 1) {
            _this.onClickNew({
                custChanTypeName: _.get(clickBtn, "comp[0].name", ""),
                custChanTypeId: _.get(clickBtn, "comp[0].key", "")
            });
        }
    } else if (belongBtnKey === "distribute") {
        // 分配操作
        if (!_this.state.selectedRowKeys.length) {
            Warning("请选择客户"); // 如果没有选择客户,弹出警告
            return;
        }
        let assignObj = belongBtn.comp.filter(item => item.key == clickBtn.key);
        _this.showAssign(assignObj[0].key); // 调用分配方法
    } else if (belongBtnKey === "recycle") {
        // 回收操作
        if (!_this.state.selectedRowKeys.length) {
            Warning("请选择客户"); // 如果没有选择客户,弹出警告
            return;
        }
        let assignObj = belongBtn.comp.filter(item => item.key == clickBtn.key);
        _this.showAssign(assignObj[0].key); // 调用回收方法
    }
}
  • 逻辑说明
    • 根据 belongBtnKey 和 clickedKey 判断按钮的类型,执行不同的操作。
    • 分支逻辑包括新增、分配、回收等功能。
    • 调用对应的方法(如 onClickNew 或 showAssign)完成具体操作。

在 listBtnsClick 方法中,当按钮类型为 "分配" 或 "回收" 时,会调用 showAssign 方法。以下是 showAssign 方法的代码:

showAssign(key) {
    let assNum = key.match(/\d+/) ? key.match(/\d+/)[0] - 1 : 0; // 提取数字并减一
    let dispatchCustomer = this.state.selectedRowKeys; // 获取选中的客户

    if (!dispatchCustomer.length) {
        Warning("请选择客户"); // 如果没有选中客户,弹出警告
        return;
    }

    let param = { customerId: dispatchCustomer[0].id }; // 构造请求参数
    actions.customerhome.dispatchResponsiblesByCustomerId(param).then(resultData => {
        // 调用 model 中的方法,获取数据
        console.log(JSON.stringify(resultData, null, 2) + " resultData2222");

        // 遍历返回数据,新增字段
        const updatedDispatchList = resultData.map(item => ({
            ...item,
            personId: item.staffUserId,
            personName: item.staffUserName,
            personCode: item.staffUserCode
        }));

        // 去重逻辑:只保留 personId 唯一的对象
        const uniqueDispatchList = updatedDispatchList.reduce((acc, current) => {
            if (!acc.find(item => item.personId === current.personId)) {
                acc.push(current);
            }
            return acc;
        }, []);

        console.log(JSON.stringify(updatedDispatchList, null, 2) + " updatedDispatchList");

        // 更新组件状态
        this.setState({
            dispatchList: uniqueDispatchList // 更新 dispatchList
        });

        // 更新 model 状态
        actions.customerhome.updateState({
            assignVisiable: true,
            clickAssign: key,
            dispatchRange: assNum
        });
    });
}
  • 逻辑说明
    • 提取 key 中的数字,用于计算分配范围。
    • 获取选中的客户 ID,构造请求参数 param
    • 调用 model 文件中的方法 dispatchResponsiblesByCustomerId 发起接口请求。
    • 对接口返回的数据进行处理:
      • 新增字段(如 personIdpersonName)。
      • 去重处理,确保 personId 唯一。
    • 更新组件的 state 和 model 的状态。

2. model.js 文件

在 model.js 文件中,封装了具体的业务逻辑。以下是 dispatchResponsiblesByCustomerId 方法的代码:

async dispatchResponsiblesByCustomerId(param) {
    let result = await api.dispatchResponsiblesByCustomerId(param); // 调用接口
    if (result && result.data) {
        var resultData = result.data; // 提取数据
        return resultData; // 返回处理后的数据
    }
}
  • 逻辑说明
    • 使用 async/await 处理异步请求。
    • 调用 service.js 文件中的 dispatchResponsiblesByCustomerId 方法发起接口请求。
    • 提取接口返回的数据并返回给调用方。

3. service.js 文件

在 service.js 文件中,定义了接口调用的具体实现。以下是 dispatchResponsiblesByCustomerId 方法的代码:

/**
 * 客户分配中,根据客户ID找到客户对应的负责人的信息
 * @param {*} params
 */
export const dispatchResponsiblesByCustomerId = param => {
    return requestSec(URL.DISTRIBUTE_RESPONSIBLE_URL, {
        method: "get",
        param
    });
};
  • 逻辑说明
    • 使用 requestSec 方法发起 HTTP 请求。
    • 请求方法为 GET,参数为 param
    • 返回后端接口的数据。

相关文章:

  • MATLAB之数据分析图系列:从二维到三维(直接套用)
  • 测试团队UI自动化实施方案
  • 【轻松学C:编程小白的大冒险】— 12.2 瑞士军刀出鞘:switch-case 的多分支江湖
  • 有序数组的归并算法思路
  • 如何实现局域网内无痛访问Jupyter Notebook?
  • Linux中常用服务器监测命令(性能测试监控服务器实用指令)
  • oracle数据泵操作
  • 从零实现Json-Rpc框架】- 项目实现 - 服务端registrydiscovery实现
  • Spring boot 中QPS(Queries Per Second)与 TPS(Transactions Per Second)详细对比
  • struct 中在c++ 和c中用法区别
  • Hue:一个大数据查询工具
  • MSTP多域生成树
  • SpringBoot 7 种实现 HTTP 调用的方式
  • 阶段项目:Windows 服务器的组建与管理
  • java设计模式之桥接模式(重生之我在地府当孟婆)
  • 2025年SQL2API平台推荐:QuickAPI、dbapi 和 Magic API 介绍与对比
  • Kubernetes 入门篇之Master节点部署与安装
  • 基于modbusTcp连接Modbus Slave本地模拟服务通讯(C#编写ModbusTcp类库)(一)
  • VMware Workstation Pro下载链接
  • 【图像去噪】论文复现:灵感源自MAE!进一步解决BSN的局限性,破坏真实噪声的空间相关性!AMSNet的Pytorch源码复现,跑通源码,原理详解!
  • 罕见沙尘再度入川,官方:沙尘传输高度达到平流层,远超以往
  • 洲际酒店:今年第一季度全球酒店平均客房收入同比增长3.3%
  • 东莞“超级”音乐节五一出圈背后:文旅热力何以澎湃经济脉动
  • 两部门部署中小学幼儿园教师招聘工作:吸纳更多高校毕业生从教
  • OpenAI任命了一位新CEO
  • 毗邻三市人均GDP全部超过20万元,苏锡常是怎样做到的?