首页

Conflux 开发教程 | 使用 IDE 在 Conflux 开发 DApp 的实战操作指南

前端达人

Conflux DApp 开发教程

对本教程有任何疑问或建议可以在 GitHub 给我们留言。

简介

Conflux DApp 开发教程将使用 Conflux Studio 在 Oceanus 网络下开发一个简单的代币应用 Coin。
在这里插入图片描述

通过这个开发教程,你将会学习到如何进行 Conflux 智能合约的编写、调用,配置智能合约的代付以及如何使用 Web 前端项目与智能合约进行交互,从而实现一个包含前端和智能合约的完整的 DApp。

在阅读教程中遇到任何问题,欢迎在 Issues 中向我们反馈。

准备工作

安装 IDE

请在 GitHub 下载页面下载 Conflux Studio。目前 Conflux Studio 支持 macOS 和 Linux 系统,请根据系统下载对应的版本。

正确安装 Conflux Studio 并初次启动后,Conflux Studio 将显示欢迎页面,根据提示完成 Docker, Conflux Node 以及 Conflux Truffle 的下载、安装及启动。
在这里插入图片描述

创建钱包

完成所有的安装步骤后,首先需要创建钥匙对来完成后续的合约部署以及调用。

在 Conflux Studio 的任意界面,点击应用左下⻆的钥匙图标,打开密钥管理器。点击 Create 按钮打开新钥匙对弹窗,输入钥匙对的名字并点击 Save 按钮。完成后将在密钥管理器中看到刚刚生成的钥匙对的地址。钥匙对由私钥和公钥组成,公钥在智能合约中也常被称作地址。

导出私钥可以通过点击每个地址后面的眼睛按钮打开查看私钥弹窗,弹窗显示地址以及私钥。后续教程中会需要通过管理器导出私钥。
在这里插入图片描述

为了顺利完成教程,首先需要创建三个钥匙对:

  • minter_key 用于 Coin 合约部署时的签名,是这个教程中最常使用的钥匙对
  • receiver_key 用于 Coin 合约接收转账,将在后文中介绍转账时用到
  • sponsor_key 用于 Coin 合约代付功能,将在后文中介绍代付功能时用到

连接 Conflux 网络

教程将在 Oceanus 网络进行合约的部署以及合约的调用。点击顶部 Network 标签的倒三角打开下拉菜单,点击选择 Oceanus 网络进行切换。

切换完成后,可以在主页面中看到当前网络为 oceanus。页面左边包括了当前网络的节点 URLChain IDTPS 信息,页面右边包含了当前网络区块的信息。
在这里插入图片描述

申请测试 CFX

点击顶部 Explorer 标签打开区块浏览器,并在地址栏粘贴钥匙对地址,可以在左边看到当前地址的 CFX 余额信息。
在这里插入图片描述

在区块链的世界中,大家通常将申请测试 Token 的方式称为 faucet,目前在 Oceanus 网络下每次 faucet 申请到的 Token 为 100 CFX。

获取 CFX 的方式有两种方式:

  • 输入地址后点击地址栏右边的水龙头按钮,Conflux Studio 将为地址自动申请 CFX
  • 你也可以直接在浏览器中输入 https://wallet.confluxscan.io/faucet/dev/ask?address={address} 来申请 CFX
    在这里插入图片描述

使用上述方法在 Conflux Studio 中为 minter_key 和 sponsor_key 申请 CFX Token。完成申请后,这两个账户上的余额将会从 0 CFX 更新为 100 CFX。

目前余额信息为:

  • minter_key 余额 100 CFX
  • receiver_key 余额 0 CFX
  • sponsor_key 余额 100 CFX

智能合约

创建项目

点击顶部左边的 Project 标签切换至项目列表页面,点击页面中的 New 按钮打开项目创建窗口,输入项目的名称并选择 coin 模版,点击 Create Project 完成项目的创建。
在这里插入图片描述

合约代码

Coin 合约是一个简单的代币合约,其中:

  • 通过 mint 方法可以增发代币数量
  • 通过 send 方法可以将一定数量的代币转账给别的用户,同时会在事件中记录下这笔转账的信息
  • 通过 balanceOf 方法可以查询到指定账户地址的代币余额
  • 通过 add_privilege 方法可以为合约添加代付白名单
  • 通过 remove_privilege 方法可以为合约移除代付白名单
    在这里插入图片描述

Conflux 智能合约使用 Solidity 语言进行开发,打开目录下的 contracts/Coin.sol 文件,这个是本项目的核心代码:

// 指定了 Solidity 的版本,通过 Pragmas(https://solidity.readthedocs.io/en/latest/layout-of-source-files.html#pragmas) 告诉编译器本代码可以兼容的版本为 0.5.0 到 0.7.0
pragma solidity >=0.5.0 <0.7.0;

// 导入 SponsorWhitelistControl 合约
import "./SponsorWhitelistControl.sol";

// 定义 Coin 的合约
contract Coin {
    // 定义了两个 State Variables(https://solidity.readthedocs.io/en/latest/structure-of-a-contract.html#state-variables)
    address public minter;
    mapping (address => uint) private balances;

    // 使用 SponsorWhitelistControl 合约连接系统合约
    SponsorWhitelistControl constant private SPONSOR = SponsorWhitelistControl(address(0x0888000000000000000000000000000000000001));

    // 定义了 `Sent` 的事件,定义了 from / to / amount 列
    event Sent(address from, address to, uint amount);

    // Coin 合约的 constructor ,在 constructor 中指定了 minter 的地址
    constructor() public {
        // msg.sender 为部署合约时签名的账户地址,将这个地址赋值给 minter
        minter = msg.sender;
    }

    // 定义 mint 方法,通过此方法来增发代币
    function mint(address receiver, uint amount) public {
        require(msg.sender == minter);
        require(amount < 1e60);
        balances[receiver] += amount;
    }

    // 定义 send 方法,通过此方法可以给别的账户转账代币
    function send(address receiver, uint amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance.");
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        // 通过 emit 触发 Sent 事件,记录这笔转账的信息
        emit Sent(msg.sender, receiver, amount);
    }

    // 定义 balanceOf 方法,这是个 view 类型的方法,用于查询账户余额
    function balanceOf(address tokenOwner) public view returns(uint balance){
      return balances[tokenOwner];
    }

    // 定义了 add_privilege 方法,调用系统合约 add_privilege 方法添加地址到代付白名单
    function add_privilege(address account) public payable {
        address[] memory a = new address[](1);
        a[0] = account;
        SPONSOR.add_privilege(a);
    }

    // 定义了 remove_privilege 方法,调用系统合约 remove_privilege 从合约代付白名单中移除地址
    function remove_privilege(address account) public payable {
        address[] memory a = new address[](1);
        a[0] = account;
        SPONSOR.remove_privilege(a);
    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

编译及部署合约

点击工具栏的 Build 按钮进行合约的编译,编译的结果将会保存在 build/Coin.json 文件中。
在这里插入图片描述
在部署合约前,首先需要确认在 Explorer 中选择合约部署所使用的地址,Conflux Studio 会使用这个地址将部署合约这笔交易进行签名(选择的方法为在 Explorer 的地址栏中输入地址)。在合约代码的 constructor 中,minter 被赋值为 msg.sender,这个 msg.sender 就是 Explorer 所选择的地址。

在此我们选择 minter_key 作为部署合约的签名者。
在这里插入图片描述
点击工具栏的部署按钮进行部署,部署完成后,部署结果会在 deploys 的 JSON 文件中,在这个文件中可以在 contractCreated 中找到当前合约部署的地址,后文中使用 contract_addr 来代表这个合约地址。
在这里插入图片描述

调用合约

点击顶部的 Contract 标签切换至合约页面,在地址栏输入 contract_addr 地址并加载合约。
在这里插入图片描述

合约页面由三个部分组成:

  • 左边为合约调用区域
  • 中间为合约数据查询区域
  • 右边为事件查询区域

合约调用及查询

增发代币

点击合约调用的下拉菜单中选择 mint 方法,在下方的参数区域分别填入以下信息:

  • receiver 接收代币的地址。填入 minter_key 地址
  • amount 发行的代币总数。填入整数 1000
  • Value 选填项,具体可查看 Value 详解。填 0 或者不填
  • Signer 这笔交易的签名地址,如果没有开通代付功能,交易手续费将在这个账户地址中扣除,在合约代码中通过 msg.sender 获取到这个地址。填入 minter_key 地址

填写完成后点击执行按钮,Conflux Studio 将自动构造交易并推送到网络中。成功执行后可以在下方 Result 中看到这笔成功的交易。
在这里插入图片描述

查询代币余额

点击查询区域的下拉菜单并且选择 balanceOf 方法,这是在代码中定义的查询方法。在下方的 tokenOwner 填入 minter_key 地址并点击执行,就可以在下方的 Result 中看到 minter_key 账户的 Coin 代币的余额信息为 1000。使用同样方法可以查询到 receiver_key 账户的代币余额为 0。
在这里插入图片描述

转账代币

在合约调用区域选择 send 方法,在 Parameters 中分别填入:

  • receiver 收款人地址。填入 receiver_key 地址
  • amount 转账的代币数量。填入整数 200
  • Signer 这笔交易的签名地址,代币转出的数量将会在这个账户中扣除。填入 minter_key 地址,

点击执行完成转账,再次查询代币余额可以看到 minter_key 账户只剩下 800 代币,而 receiver_key 账户则从 0 变成了 200 代币。在这里插入图片描述

Value 参数

Conflux 智能合约的每个调用的方法都可以带上 Value 参数,这是一个可选的参数。如果带上了这个值,智能合约出了在执行这个方法的逻辑外,还会额外转 Value 中指定数量的 CFX token 到 receiver 账户,转账金额为 Value 中所填的值。有些智能合约的方法需要这个参数才可以完成调用,但是在 Coin 合约不需要这个参数。

后文中的代付功能将会使用到 Value 参数。

查询事件

在事件区域选择 Sent 并点击执行,下方的 Event Logs 可以看到转账的记录。Sent 事件的列都是由代码中的 Sent 事件的参数来定义的(其中 epoch 为事件发生的时间,这个为系统默认列)。在代码中定义了 Sent 方法的参数为 from, to 和 amount,分别对应了这笔转账的发起者地址,接受者地址以及转账的数量。
在这里插入图片描述

代付功能

Conflux Studio 支持 Conflux 系统合约提供的代付功能

通过系统合约可以为别的合约设置代付功能,系统合约提供给了四个方法:

  • add_privilege 添加合约代付白名单,在代付白名单中的地址调用该合约的方法时不需要付手续费,费用由代付账户支付。其中添加特殊地址 0x0000000000000000000000000000000000000000 代表为所有调用该合约的地址代付费用
  • remove_privilege 移除合约代付白名单
  • set_sponsor_for_collateral 设置合约储存费 (collateral for storage) 的代付账户及代付金额
  • set_sponsor_for_gas 设置合约手续费 (gas fee) 的代付账户、代付金额及每笔交易代付金额上限

启用一个合约的代付需要设置代付的账户、代付金额的及代付白名单。教程将会使用 Conflux Studio 通过系统合约设置代付账户及代付金额,通过 Coin 合约添加代付白名单。设置完成后,minter_key 账户调用 Coin 合约的方法时将不会被扣除手续费,手续费由 sponsor_key 账户代付。

设置代付账户及代付金额

在 Conflux Studio 中访问系统合约地址 0x0888000000000000000000000000000000000001,在合约调用区域能看到前文中提及的四个设置代付的方法。
在这里插入图片描述

选择 set_sponsor_for_collateral 方法,该方法有三个参数:

  • contract_addr 设置代付的合约地址。填入 contract_addr
  • Value 设置代付金额。填入整数 40
  • Signer 代付账户地址。填入 sponsor_key 地址
    在这里插入图片描述
    填好以上参数并执行运行,系统合约将为 Coin 合约设置好储存费代付账户,此时 sponsor_key 账户将会被扣除 40 CFX。

选择 set_sponsor_for_gas 方法,该方法有四个参数:

  • contract_addr 设置代付的合约地址。填入 contract_addr
  • upper_bound 设置每笔交易代付的上限。填入 1000000000000
  • Value 设置代付金额。填入整数 40
  • Signer 代付账户地址。填入 sponsor_key 地址
    在这里插入图片描述
    填好以上参数并再次执行运行,系统合约将为 Coin 合约设置好手续费代付账户,此时 sponsor_key 账户将会再次被扣除 40 CFX。

完成这两个方法的调用后 Coin 合约代付账户便设置好了,sponsor_key 账户将为 Coin 合约的手续费和储存费各提供为 40 CFX Token 的代付服务。由于目前代付白名单中并没有账户地址,因此还需要添加白名单地址才能完成代付设置。

添加代付白名单

在 Coin 合约中集成了设置代付白名单的方法,通过调用此方法可以添加或删除代付白名单。

在 Conflux Studio 中访问 contract_addr 合约,选择 add_privilege 方法:

  • account 添加白名单的地址。填入 minter_key 地址
  • Value 不填
  • Signer 这笔交易的签名地址。填入 minter_key 地址

运行后就成功设置了代付白名单了,至此 Coin 合约的代付功能设置好了。

代付测试

在进行代付测试前,先查询并记录下 minter_key 账户的 CFX 余额。例如本教程中,minter_key 的初始余额为 97.6210937497093952 CFX。

回到 Coin 合约调用页面,再次调用 mint 方法并使用 minter_key 地址增发代币 1000,完成代币增发后再次查询 minter_key 的余额,仍然为 97.6210937497093952 CFX。

可以看到增发代币的这笔交易,原本应该由 minter_key 账户支付的手续费,变成了由 sponsor_key 账户支付。

前端项目

前端项目源码可以前往 Conflux 前端

预备

下载项目并安装依赖

  • 下载前端项目:git clone https://github.com/ObsidianLabs/conflux-frontend-react
  • 使用 npm install 或者 yarn 进行项目依赖安装

Conflux Portal 的安装及配置

Conflux Portal 是由 Conflux 提供的浏览器插件,目前提供了 Chrome 及 Firefox 的支持,用户可以使用 Conflux Portal 进行私钥的管理以及交易签名。

前往 Conflux Portal GitHub 下载安装。项目的源代码在 GitHub 中可以找到。

在这里需要将 Conflux Studio 中生成的地址导入到 Conflux Portal 中。完成插件安装后,在 Conflux Portal 的页面中选择 Import,将 Conflux Studio 中的 minter_key 的私钥(在创建钱包章节中介绍了如何将私钥导出)粘贴到输入框中,点击 Import 按钮完成私钥导入。
在这里插入图片描述

运行前端项目

在运行项目之前,需要修改一些默认的环境变量。

前面的教程中部署合约后会生成一个 contractCreated,这个值便是部署在网络中智能合约的地址。打开项目根目录并找到 .env 文件,这个文件提供了项目的环境变量,将 REACT_APP_CONFLUX_COIN_ADDRESS 的值修改为 contract_addr

使用 yarn start 启动前端项目,开发服务器运行起来后会在浏览器中打开前端页面(如果没有打开,请在浏览器中访问 http://localhost:3000)。

项目运行起来后,页面将显示四个卡片信息,分别为

  • 左上角 Conflux 网络信息模块
  • 右上角 Conflux Portal 模块
  • 左下角 Coin 合约模块
  • 右下角 SponsorWhitelistControl 合约模块
    在这里插入图片描述

连接 Conflux Portal

点击右上角组件中的 Connect to Conflux Portal 按钮,Conflux Portal 页面将被打开,输入密码和选择账户后完成连接。连接成功后,将会在按钮下看到当前连接的账户地址以及账户中的 CFX 余额。
在这里插入图片描述

运行 Coin 合约代币增发和代币转账操作

左下角的组件为 Coin 合约组件,可以通过这个组件调用代币增发和代币转账功能。

  • 代币增发:选择 mint 方法并在 receiver 中填入增发地址 minter_key 地址和在 amount 中填入增发代币的数量 100,点击 Push Transaction,在弹出的 ConfluxPortal Notification 窗口中点击 Confirm 按钮来确认交易。

  • 代币转账:选择 send 方法并在 receiver 中填入收款人地址 receiver_key 地址和在 amount 中转账代币的数量 20,点击 Push Transaction,在弹出的 ConfluxPortal Notification 窗口中点击 Confirm 按钮来确认交易。
    在这里插入图片描述

查看 Coin 合约中的余额

选择 balanceOf 方法并在 tokenOwner 输入框中填入查询的地址,点击 Query Data 按钮可以查询到账户的余额。
在这里插入图片描述

查看 Sent 事件

选择 Sent 事件并点击 Query Data 可以查询到转账操作所触发的转账事件的记录。
在这里插入图片描述

前端项目解析

项目使用 React 进行开发。主要由三大部分组成:视图组件、js-conflux-sdk 以及 Conflux Portal。

项目根目录下的 .env 环境变量,在这里定义了两个环境变量,分别为

  • REACT_APP_CONFLUX_NODE_RPC:Conflux 的网络节点地址,目前默认为 Oceanus 网络的地址
  • REACT_APP_CONFLUX_COIN_ADDRESS:已部署的 Coin 智能合约地址

视图组件

视图组件在项目的 src/components 中,其中 App.js 为页面的主入口,负责页面的排列及合约信息的读取。
在这里插入图片描述

ConfluxNetwork.js

负责渲染 Conflux 网络信息,Node URL 的值为 .env 环境变量文件下的 REACT_APP_CONFLUX_NODE_RPC 设置的值(默认为 Oceanus 网络)。

ConfluxPortal.js

负责渲染 Conflux Portal 的连接信息,并提供了连接 Conflux Portal 的交互按钮。

  • connectConfluxPortal 调用 Conflux Portal 的 enable 方法启用 conflux (conflux portal 实例由浏览器插件注入到 windows.portal 中),完成 enable 后调用 getAccount 方法获取到 Portal 中的账户。
  • refreshBalance 调用 Conflux SDK 的 getBalance 方法来更新账户余额信息
  • renderPortalButton 根据当前不同的状态,渲染连接 Portal 的按钮
ConfluxContract.js

负责渲染 Conflux 合约信息,本项目中提供了 Coin 和 SponsorWhitelistControl 两个合约。

ConfluxContract.js 由三个组件组成,分别为:

  • ConfluxContract 负责根据传入的合约 abi 来渲染合约的信息,包括合约地址、合约方法和事件,合约提交的交互逻辑及显示执行后的结果
  • ContractMethods 负责渲染合约 abi 中的方法和事件的表单及相对应的按钮
  • ConfluxForm 负责根据方法或事件的 abi 来渲染输入表单

lib

lib 在项目的 src/lib 中,这里的文件主要是为视图提供包括连接网络、构造交易、获取账户、读取合约等服务。
在这里插入图片描述

conflux.js

conflux.js 是 js-conflux-sdk 的封装。js-conflux-sdk 是由 Conflux 提供的 JavaScript SDK,本前端项目使用 SDK 来连接 Conflux 网络,和合约进行交互以及构造合约中的实例。

conflux-portal.js

conflux-portal.js 是 Conflux Portal 的封装,本前端项目通过调用浏览器插件来完成交易的签名。调用 Conflux Portal 提供的 enable 方法可以启动项目和 Conflux Portal 的连接(需要提前检查浏览器是否正确安装插件,在 constructor 中通过检查 window.conflux 是否为空来判断)。conflux-portal.js 提供了获取账户 getAccount 和发送交易 sendTransaction 两个主要的方法。

abi

lib/abi 文件夹下提供了两个 json 文件,分别为 Coin.json 和 SponsorWhitelistControl.json,这两个文件是构造合约所需要使用的 abi 文件。

总结

在本开发教程中,我们学习了如何使用 Conflux Studio 来完成一个完整的 Coin DApp 开发,其中包括了:

  • 使用钥匙对管理器创建账户及导出账户私钥
  • 切换 Oceanus 网络,查看网络信息
  • 账户申请 CFX Token
  • 创建、编译并部署项目
  • 解析 Coin 合约代码,学习如何编写合约的读写方法及事件
  • 使用合约浏览器调用 Coin 合约的代币增发、转账、查询余额及查询事件
  • 设置并使用智能合约的代付功能
  • 将私钥导入 Conflux Portal 并连接前端项目
  • 在前端项目中调用 Coin 合约的代币增发、转账、查询余额及查询事件
  • 解析前端项目代码,学习如何通过 Conflux Portal 和 Conflux JavaScript SDK 连接网络并实现交易

关于 Conflux Bounty

Conflux 基金会为了鼓励用户参与生态建设,提供了 Conflux Bounty 赏金平台。通过完成 Bounty 赏金平台发布的各项任务,参与者可以获得 FC (Fans Token) 作为奖励。

FC 的价值

FC,全称 Fans Coin,是由 Conflux 基金会与社区成员共同研发的生态代币,用于记录和感谢对 Conflux 生态建设做出贡献的社区成员。FC 目前在 Oceanus 上运行,Conflux 基金会承诺,在主网上线后,锁定和未锁定的 FC 都可以与主网 CFX 进行 1:1 承兑,以此保障所有社区成员的劳动成果都可以获得奖励。
在这里插入图片描述

FC 赏金分配方案会展示在赏金任务详情页中,包括最高奖金数量、奖金分配人数、奖金数量分布、排行名次确定方式等信息。账号余额中的赏金奖励可以随时申请提现至 Conflux 钱包。Conflux 团队会对所有的提现申请进行审核。

对于已经通过的提现申请,Conflux 团队会在每周二中午 12 点(如遇节假日,往后顺延至下一个工作日)进行提币操作。完成提币操作后,您的 Conflux 钱包将会收到您提现的赏金奖励。

Bounty 的价值

Conflux Bounty (https://bounty.conflux-chain.org) 的宗旨是为每一个通证找到价值。Bounty 分为几个板块:技术、品牌、社群、资源、其他等。

  • 技术板块:分为产品、SDK、教程、开发、测试等;主要是奖励社区的一些技术资源贡献者。
  • 品牌板块:分为文案、设计、视频、媒体、推广等;主要是奖励在各大网络平台分享 Conflux 的各种最新动态,扩大 Conflux 的生态影响力的活跃贡献者;
  • 社群板块:分为活动、推广等;主要是奖励举办各种 Conflux 相关线上线下活动,帮助解答社群问题,活跃日常气氛等。
  • 资源板块:分为政务、商务、人力等;主要是奖励为生态中引进企业资源,扩建Conflux 生态等。
  • 其他板块:分为周边、采购等;主要是奖励一些其他的零散任务。

关于 Obsidian Labs

黑曜石实验室(Obsidian Labs) 是全球最大的区块链开发工具(IDE)提供商,也是 Conflux Studio 的开发团队,致力于为区块链开发者提供必备的工具及服务,帮助链上应用生态快速发展。目前,除了 Conflux Studio 外,Obsidian Labs 还为 EOS、Nervos、Substrate、Alogorand 等明星项目提供了专属的 IDE 和框架工具。






蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
原文链接:https://blog.csdn.net/weixin_45029854/article/details/107638406
作者:Sam @黑曜石实验室
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

智能合约 web3.js ABI Address三者的关系

前端达人

web3.js是以太坊提供的一个Javascript库,它封装了以太坊的JSON RPC API,提供了一系列与区块链交互的Javascript对象和函数,包括查看网络状态,查看本地账户、查看交易和区块、发送交易、编译/部署智能合约、调用智能合约等,其中最重要的就是与智能合约交互的API。

下面就介绍如何使用web3.js提供的接口调用智能合约。

系统和软件


  1. Ubuntu 16.04 64
  2. nodejs 6.10.0
  3. npm 3.10.10

示例合约

本文以下面的MetaCoin合约为例,说明在应用中使用web3.js操作智能合约的方法。


  1. // 本文中用到的MetaCoin合约
  2. pragma solidity ^0.4.2;
  3. contract MetaCoin {
  4. mapping (address => uint) balances;
  5. event Transfer(address indexed _from, address indexed _to, uint256 _value);
  6. function MetaCoin() {
  7. balances[tx.origin] = 10000;
  8. }
  9. function sendCoin(address receiver, uint amount) returns(bool sufficient) {
  10. if (balances[msg.sender] < amount) return false;
  11. balances[msg.sender] -= amount;
  12. balances[receiver] += amount;
  13. Transfer(msg.sender, receiver, amount);
  14. return true;
  15. }
  16. function getBalance(address addr) returns(uint) {
  17. return balances[addr];
  18. }
  19. }

这个合约有三个函数:

MetaCoin:构造函数,在合约被部署到区块链时执行 
getBalance:返回某账户的余额,它只读数据,不会修改数据 
sendCoin:向另一个账户发送指定数量的MetaCoin,它会改变状态变量balances 
启动一个以太坊节点,将上面的合约部署到区块链中,并记录下合约的地址,可以通过truffle部署,具体参考这篇文章。 接下来就可以按照下面的步骤在项目中通过web3.js来使用这个合约。

添加web3到项目中

首先新建一个Nodejs项目并初始化:


  1. $ mkdir web3test && cd web3test
  2. $ npm init

会提示输入项目信息,全部默认即可。 
接下来下载web3.js到项目中:

$ npm install web3 --save 
  • 1
  • 2

以上命令会将web3.js下载到web3test/node_modules目录下,其中–save参数会web3.js添加到package.json配置文件中。

创建web3对象

要使用web3.js与区块链交互,需要先创建web3对象,然后连接到以太坊节点。 在web3test目录下新建index.js文件,在其中输入以下代码:


  1. var Web3 = require("web3");
  2. // 创建web3对象
  3. var web3 = new Web3();
  4. // 连接到以太坊节点
  5. web3.setProvider(new Web3.providers.HttpProvider("http://localhost:8545"));

获取已部署的合约实例

要使用智能合约,必须先从区块链中获取到合约实例,获取合约实例需要合约的ABI和合约的地址:


  1. // 合约ABI
  2. var abi = [{"constant":false,"inputs":[{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"}],"name":"sendCoin","outputs":[{"name":"sufficient","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"}];
  3. // 合约地址
  4. var address = "0xb2cdd356e58280906ce53e1665697b50f88aac56";
  5. // 通过ABI和地址获取已部署的合约对象
  6. var metacoin = web3.eth.contract(abi).at(address);

metacoin就是获取到的合约对象实例,此时metacoin对象中就包含了与合约函数同名的Javascript函数,之后就可以通过metacoin对象来调用合约中的函数了。

调用合约函数

MetaCoin合约中有两个函数:getBalance和sendCoin,可以通过metacoin对象直接调用这两个函数。

首先来看getBalance,由于getBalance函数只是从区块链中读数据,而不修改数据,因此我们通过在getBalance后面加上.call()的方式调用:


  1. var account_one = web3.eth.accounts[0];
  2. var account_one_balance = metacoin.getBalance.call(account_one);
  3. console.log("account one balance: ", account_one_balance.toNumber());

这里:

在getBalance后加上.call()来显式指明用call的方式调用 
通过call的方式调用可以得到getBalance函数的返回值 
通过call的方式调用的函数只在节点本地虚拟机中执行,不会产生交易,不会花费费用,不会修改数据 
下面来看sendCoin函数,由于sendCoin要修改合约内部的数据,所以要使sendCoin生效,必须要向区块链发送交易,可以在sendCoin后面加上.sendTransaction()来指明这是一笔交易:


  1. var account_one = web3.eth.accounts[0];
  2. var account_two = web3.eth.accounts[1];
  3. // 提交交易到区块链,会立即返回交易hash,但是交易要等到被矿工收录到区块中后才生效
  4. var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, {from:account_one});
  5. console.log(txhash);

这里:

在sendCoin函数后加上.sendTransaction()指明要向区块链发送交易 
合约代码中sendCoin函数只有两个参数,而在web3中通过.sendTransaction()调用合约函数的时候需要增加最后一个参数,它是一个javascript对象,里面可以指定from/value/gas等属性,上面的例子用from来指定交易的发送者 
上面的调用语句执行后,会向区块链提交一笔交易,这笔交易的发送者是account_one,接收者是metacoin的地址,交易的作用是以account_two和100作为参数执行合约的sendCoin函数 
函数会立即返回交易的hash,表明交易已经提交到区块链,但是并不知道交易何时处理完成,交易要等到被旷工收录到区块中后才会生效 
监听合约事件

当通过.sendTransaction()调用合约的时候,交易会被提交到区块链进行处理,这个处理需要一定的时间,如果需要等交易完成之后再执行其他操作,就必须要知道交易何时完成,那么如何知道交易何时完成呢?可以通过监听合约事件来实现。

在合约中可以定义事件,事件可以带有参数,在合约函数内部完成某些操作时,可以触发事件,向外界传达一些信息。例如,在MetaCoin合约中定义了一个事件叫做Transfer,表示一个转账的事件,它带有三个参数:交易的发送者、接受者、转账数量。在sendCoin函数中,转账成功后就会触发Transfer事件,将对应的参数传给该事件,这样外部监听到事件后,可以取出事件的参数来获得交易发送者、接收者、数量。同时事件中还带有其他信息,比如交易hash等。

在web3中使用事件,要首先获取事件对象,然后监听事件,如果事件发生,就会在回调函数中获取到事件信息:


  1. // 获取事件对象
  2. var myEvent = metacoin.Transfer();
  3. // 监听事件,监听到事件后会执行回调函数
  4. myEvent.watch(function(err, result) {
  5. if (!err) {
  6. console.log(result);
  7. } else {
  8. console.log(err);
  9. }
  10. myEvent.stopWatching();
  11. });
  12. // 输出:
  13. { address: '0xb2cdd356e58280906ce53e1665697b50f88aac56',
  14. blockNumber: 651,
  15. transactionIndex: 0,
  16. transactionHash: '0xcc71bc2824cc84d1ee831c46189e3a80cf0af05697ba0370693aa97390c8067b',
  17. blockHash: '0x1d53f04206f3926d0f311b1230a9dd0b0c5aadac35b169a6a609e384ab130c6f',
  18. logIndex: 0,
  19. removed: false,
  20. event: 'Transfer',
  21. args:
  22. { _from: '0x68b73956d704007514e9257813bdc58cdf3c969a',
  23. _to: '0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e',
  24. _value: { [String: '100'] s: 1, e: 2, c: [Object] } } }


从输出可以看出,获取到的事件信息包括事件的参数、事件名、区块号、交易hash等。

通过检测事件中的transactionHash与调用合约函数返回的交易hash是否一致,可以判定某一笔交易是否已完成:


  1. var account_one = web3.eth.accounts[0];
  2. var account_two = web3.eth.accounts[1];
  3. var account_one_balance = metacoin.getBalance.call(account_one);
  4. console.log("account one balance:", account_one_balance.toNumber());
  5. var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, { from: account_one });
  6. var myEvent = metacoin.Transfer();
  7. myEvent.watch(function (err, result) {
  8. if (!err) {
  9. if (result.transactionHash == txhash) {
  10. var account_one_balance = metacoin.getBalance.call(account_one);
  11. console.log("account one balance after sendCoin:", account_one_balance.toNumber());
  12. }
  13. } else {
  14. console.log(err);
  15. }
  16. myEvent.stopWatching();
  17. });
  18. // 输出:
  19. account one balance: 7000
  20. account one balance after sendCoin: 6900


watch中的回调函数如果被执行,说明事件已被触发,也就是说某笔交易已经处理完,检查交易hash是否一致,可以判定产生这个事件的交易是否是自己发送的交易,如果是,就可以进行其他操作,比如查询最新的余额


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


async function

前端达人

这篇文章多看几遍加深理解

async function 声明定义了一个异步函数,它返回一个AsyncFunction对象。异步函数 是指通过 事件循环(event loop) 异步执行的函数,通过返回一个隐式的 Promise 作为其结果。使用异步函数的代码的语法和结构更像使用标准同步功能。(The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.

语法

async function name([param[, param[, ... param]]]) { statements } 
  • 1

参数

  • name:函数名称
  • param:要传递给函数的参数。
  • statements:函数体语句。

返回值:返回一个promise对象,将返回异步函数返回的值(如果异步函数是resolved则返回resolved的值;如果抛出异常,则rejected从异步函数中抛出的异常)。(A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.)

异步函数可以包含await表达式,该表达式暂停异步函数的执行 并等待 Promise的执行结果返回,结果返回后就恢复异步函数的执行。

await 关键字只在异步函数(async functions)内有效。如果在异步函数外使用它,会抛出语法错误。
当异步函数暂停时,它调用的函数仍会继续执行。

举例一:

function resolveAfter5Seconds() { return new Promise(resolve => { setTimeout(() => { resolve('resolved'); }, 5000); }); } async function asyncCall() { console.log('calling'); let result = await resolveAfter5Seconds(); console.log(result); // 5s之后输出结果 } asyncCall(); //返回的是一个promise对象 // console.log(asyncCall()); // Promise { <pending> } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

运行效果:
在这里插入图片描述
举例二:

let resolveAfter6Second = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Second = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let sequentialStart = async function () { console.log('sequential start'); const slow = await resolveAfter6Second(); console.log(slow); const fast = await resolveAfter4Second(); console.log(fast); } sequentialStart() //立即输出 // sequential start // start slow promise //再过6秒后输出 // slow promise is done // slow // start fast promise //再过4秒后输出 // fast promise is done // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

运行效果:
在这里插入图片描述
换一种await的写法,结果完全不同:两个计时器被同时创建

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentStart = async function () { console.log('concurrent start'); let slow = resolveAfter6Seconds(); let fast = resolveAfter4Seconds(); console.log(await slow); console.log(await fast); } setTimeout(() => { concurrentStart(); }, 2000); //2秒后执行 // concurrent start // start slow promise // start fast promise //再过4秒后执行 // fast promise is done //再过2秒后执行 // slow promise is done // slow // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

运行效果:
在这里插入图片描述
在 concurrentStart 中,两个计时器被同时创建,接着执行await。等待的是 promise的resolve回调,resolve后面的代码( console.log(‘fast promise is done’);)会继续执行。
这两个计时器同时运行。但是 await 仍旧是顺序执行的,第二个 await 还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。
也可以把 concurrentStart 改写成如下,运行效果一样:

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentPromise = async function () { console.log('concurrent start'); return Promise.all([resolveAfter6Seconds(), resolveAfter4Seconds()]).then((messages) => { console.log(messages[0]); // slow console.log(messages[1]); // fast }); } setTimeout(() => { concurrentPromise(); }, 2000); //2秒后输出 // concurrent start // start slow promise // start fast promise //再过6秒后输出 // fast promise is done //再过2秒后输出 // slow promise is done // slow // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

并行执行两个或更多的任务,如下例所示:

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallel = async function () { console.log('start paralel'); await Promise.all([ (async () => console.log(await resolveAfter6Seconds()))(), (async () => console.log(await resolveAfter4Seconds()))() ]); } setTimeout(parallel, 2000); //2秒后输出 // start paralel // start slow promise // start fast promise //再过4秒后输出 // fast promise is done // fast //再过2秒后输出 // slow promise is done // slow 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

运行效果:
在这里插入图片描述
如果希望并行执行两个或更多的任务,你必须像在parallel中一样使用await Promise.all([job1(), job2()])

也可以把parallel改写成如下,运行效果一样:

let resolveAfter6Seconds = function(){ console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }); } let resolveAfter4Seconds = function(){ console.log('start fast promise'); return new Promise(resolve =>{ setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallelPromise = function(){ console.log('parallelPromise start'); resolveAfter6Seconds().then(msg => console.log(msg)); resolveAfter4Seconds().then(msg => console.log(msg)); } setTimeout(() => { parallelPromise(); }, 2000); //2秒后输出 // parallelPromise start // start slow promise // start fast promise //再过4秒后输出 // fast promise is done // fast //再过2秒后输出 // slow promise is done // slow 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

async/await和Promise#then对比以及错误处理:
大多数异步函数(async functions )也可以使用 Promises函数 编写。然而,当涉及到错误处理时,异步函数不太容易出错。
上面例子中的concurrentStart函数和concurrentPromise函数在功能上都是等效的。在concurrentStart函数中,如果任一awaited调用失败,它将自动捕获异常,异步函数执行中断,并通过隐式返回Promise将错误传递给调用者。
在Promise例子中这种情况同样会发生,函数必须负责返回一个捕获函数完成的Promise。在concurrentPromise函数中,这意味着它从Promise.all([]).then()中返回一个Promise。事实上,在此示例的先前版本忘记了这样做!
但是,async函数仍有可能然可能错误地忽略错误。
以parallel异步函数为例。 如果它没有等待await(或 return)Promise.all([])调用的结果,则不会传播任何错误。
虽然parallelPromise函数示例看起来很简单,但它根本不会处理错误! 这样做需要一个类似于return Promise.all([])处理方式。(详见

使用async函数重写 promise 链

返回 Promise的 API 将会产生一个 promise 链,它将函数分解成许多部分。例如下面的代码:

function getProcessedData(url) { return downloadData(url)// returns a promise .catch(e => { return downloadFallbackData(url);// returns a promise }) .then(v => { return processDataInWorker(v);// returns a promise }) } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以重写为单个async函数:

async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(); } return processDataInWorker(v); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上述示例中,return 语句中没有 await 操作符,因为 async function 的返回值将被隐式地传递给 Promise.resolve。

return await promiseValue; 与 return promiseValue;的比较

返回值隐式的传递给Promise.resolve,并不意味着return await promiseValue;,只是在功能上等同于返回return promiseValue;
重写的上面代码,在processDataInWorker抛出异常时返回null:

async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch(e) { v = await downloadFallbackData(url); } try { return await processDataInWorker(v); // 注意 `return await` 和单独 `return` 的比较 } catch (e) { return null; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

简单地写上return processDataInworker(v);将导致在processDataInWorker(v)出错时function返回值为Promise而不是返回null。

return foo;return await foo;有一些细微的差异:
return foo;不管foo是promise还是rejects都将会直接返回foo。相反地,如果foo是一个Promise,return await foo;将等待foo执行(resolve)或拒绝(reject),如果是拒绝,将会在返回前抛出异常。


















蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


提高操作效率的B端设计

资深UI设计者

我从自身实践的B端项目经验中总结了几个最典型实用的b端的交互设计,来提高用户的操作效率。

目录:

一、简约至上

二、提高用户的操作效率

三、智能化操作设计



       在设计领域已经有很多经过时间和实践检验的定律法则来作为设计的指导原理,它能够帮助设计师更快更有效的将需求转化成合理的界面,并且可以有预见性的去提高产品的用户体验。被推崇的有尼尔森十大原则、用户界面设计的八项黄金法则等。但是实践出真知,一切的方法论都是源自不断实践中提炼和优化的。从原则的输入理解,到实践内化,就是自身不断进步的过程。站在巨人的肩膀上,我们应该总结更多属于自己的设计方法去解决问题优化设计。我从自身实践的B端项目经验中总结了几个最典型实用的b端的交互设计,来提高用户的操作效率。


一、简约至上

      

       1951年威廉.埃德蒙.希克首先提出,认为人们从数组中选择目标的时间取决于可用选项数量。这表明提出的选项数量与随后的选择反应时间之间存在线性关系。从广义上说,界面越复杂,用户就越难找到自己的核心操作点,功能越多,就越难发现真正对用户有价值的东西。

        2011年Giles Colborne在《简约至上》,提出“交互设计四策略”,即:合理删除、分层组织、适时隐藏和巧妙转移这四个令交互设计最大程度简单易用的策略。其本质上就是消除多余的信息干扰,保留了用户主操作流程的心流。

       作为设计师我们利用“删除、组合、隐藏、转移”,不单单是为了简化而简化,我们首要明白的就是要在对用户真正重要的事情上节省他们的脑力。需要把组织成功的标准清晰地构建在产品的简单上。一次交互就是用户与设备之间的一次对话,提高效率就是要节约他们的认知成本,学习成本,操作成本,衡量的指标就是完成某个目标的时间。

      B端管理项目有大量的表格处理,一个表格对应的数据项有很多,遵循简约至上的原则我们不会把所有字段都展示给用户看,只会优选跟业务最核心、用户关心的数据来展示给用户,让他们看到的尽量简约的表格信息。即使是最常用的查询工具,我们也会根据优先级排序,把常用的展示出来,其他的折叠收纳,用户想用到的时候可以展开更多查询条件。我们无时无刻不遵循着这个设计原则。

 


二、提高用户的操作效率


1、快速定位目标信息


       在信息量大的B端系统里,快速找到目标信息是最常用的功能。除了导航上的搜索,我所负责的项目几乎在每个信息页面中都使用了查询,筛选、排序功能,这也是常规表格对信息处理的一种快捷方式。常规的信息定位有搜索、查询、筛选、排序,不同的方式数据的检索模式也不同。根据不同业务场景,合理的使用才能帮助用户缩小信息范围,找到目标信息,提高用户完成一个任务的效率。


搜索:是用户指定任意条件(文本、语音等),平台对此条件进行检索后,展示对应内容。搜索由用户自定义条件,主动表达意图 ,目的性明确。由于搜索行为是用户主动表达意图,往往一个简短的关键词并不能完整表述用户想法,因此,搜索结果的内容通常包含多种类型从精确到模糊的展现规则。


查询:是利用关键字、词组对系统内的相关信息进行多条件组合检索。同时用户也可以输入指定条件的信息作为搜索项,但由于查询功能无法对非结构化的文件内容进行查找,所以输入条件不够精准将无法查询到最终信息。


筛选:是平台为用户提供指定条件,用户可以选择查看符合一类或多类条件下的内容。投顾项目一般都是先大范围查询,再从查询结果列表中,进行表头(快捷、对应、条件更明确细化)的信息筛选。


排序:是根据已设定的内在逻辑,将一组“无序”的记录序列调整为“有序”的记录序列。




2、缩短操作路径


        缩短操作路径简单的说就是减少操作的步骤来提升操作效率,是基于对用户、任务及环境的清晰理解的前提条件下,对用户操作的路径进行优化。我们可以从以下两方面入手:


2.1、通过预测用户下一步的行为

        通过预测用户下一步的行为,对用户进行直接引导,缩短用户的行为路径,减少操作步骤。比如在一系列连贯的操作流中某个链路执行出现问题时,用户下一步的行为是需要及时查看错误内容并处理相关信息,在执行结果中增加一个快速查看的按钮,引导他去查看和处理问题。这比他去菜单中重新查找对账信息效率要高很多。



2.2、通过用户操作路径分析减少操作步骤

      涉及到大量的信息管理时,那对于信息的快速处理就涉及到批量操作。通过用户操作路径分析,用户勾选批量执行的操作频繁,单项处理在较少情况才会用到。针对此分析,我们找到了一些具有共同批量操作特点的管理页面,对其进行操作路径的优化。批量操作可完全合并成一个执行触发点。将这个执行点,单独成一个tab切换页,细化操作为另一个切换页。tab页面的设计,也为错误信息的显示腾出了空间,整个页面清晰可对比。经过操作路径的验证,这个按钮使用率极高,明细操作几乎没有使用到,也缩短了管理页面的操作时间。




3、减少记忆负担


       减少记忆负担,是减少用户在操作时,需要记忆的信息量。一方面我们需要,简化多余的信息,减少用户对页面的认知负荷,另一方面我们可以设计记忆性功能可以帮助用户记忆。


       为什么要去减少用户的记忆负担,一方面,缩短整个操作的时间快速达成操作目标,另一方面,降低记忆数据量,有助于提升用户使用的愉悦感。从心里学来讲, 人们往往更容易记住那些自己喜欢的事物,而对不喜欢的东西记起来比较吃力,在信息大爆炸时代,我们要记忆的很多信息如登录号、证件号、密码、账户号等,这些信息有的不但复杂,而且对用户来说枯燥无味不想记忆,有一种天然的排斥感。那我们通过帮助用户去记忆留存,再在合适的机会调用显示,会提高他们在使用过程中的轻松和愉快感。比如对历史登录账户号的保留,秘钥储存功能,再到短信验证的直接不用密码即可登录,验证码还可以直接复制到剪贴板,这都是为了降低他们的记忆成本。



      随着业务的发展,平台菜单数越来越多,对用户来说非目标菜单的数量增加,用户需要更长时间来记忆所选项目的位置,到最后完全只能选择上方的搜索框进行菜单搜索。Google对用户的测试表明,没有一个人始终会把搜索作为第一选择。相反,他发现只有在网站没有提供有效导航的情况下,用户才会使用搜索。搜索需要输入关键词,即使有模糊匹配,还要进行选择,而且这个过程不一定顺利,可能需要反复操作才能顺利找到才能找到自己心中的目标。我们小组设计师通过竞品分析和用户访谈得到的一个验证性的问题,就是平台存在菜单设计命名不合理的情况,急需优化。优化思路一个是合理菜单命名与菜单结构,但这个不是一蹴而就的事情,需要从产品整个角度去整理和长远排期,持续迭代。为此我们先选择了帮助用户记忆的思路,即做一个菜单收藏的功能。用户可以手动把常用菜单直接收藏在首页,如果在没有收藏或者收藏未满限制数量时,会根据记录的用户访问次数提供最常用的菜单(以用户为导向,自定义功能;以首页为核心提供业务线支持),无需去记忆菜单位置,不断寻找菜单。




4、信息可对照 


      在处理信息的时候,提供信息的对照,减少了跳转,增强关联信息的对比,可以很大程度提升用户处理信息的效率。从系统上讲就是分屏,处理多任务事件(苹果和Windows系统均很好的使用了分屏功能)。从页面角度来讲,其实就是合理化信息模块展示,一个页面不止展示一个信息层级的内容。信息内容有从属关系(避免跳转)、因果关系(显示结果)、并列关系(同级对比)。



      同样具有审批功能的B端项目可能审批流程的设计会完全不同。我负责的另一个项目主要任务是对重大任务的监控,保障日间重点工作按时完成,审批必然严格,且需要单条仔细处理。所以我们设计的是树菜单的形式,让用户可以将待处理信息的条目和内容可以直接对照来处理,提高效率。



三、智能化操作设计


      随着B端行业日益成熟,越来越多的C端设计师转型成B端设计师,B端行业的设计思维也不断的融合和革新,如今B端产品也越来越重视产品的情感化建设、整体的用户体验、简约高效的智能化提升。

      首先让大家了解一个概念,那就是泰斯勒定律,也就是我们常说的复杂性守恒定律。泰斯勒定律认为每一个过程都有其固有的复杂性,这个复杂性存在一个临界点,超过了这个点就不能再简化了,你只能将固有的复杂性从一个地方移动到另外一个地方。



      对于我所负责的项目来说,最能体现产品日趋智能化的交互设计就是清算流程的设计。以往的清算流程是分大流程,点击流程步骤跳转至相关操作页,再进行子模块的操作与检验。完成后,切换回住流程去执行下一个模块的操作。操作员的操作连续性差且操作步骤多,完全由操作员手动操作触发,体验繁琐及不流畅。为此我们重新梳理了所有清算流程步骤,精间可合并的操作步骤,然后将所有步骤按照时间节点顺序排列,完成先前步骤才能进行下一个步骤。流程下方就是对应的执行模块,只需一键执行便可完成当前清算步骤。极大的提高了用户清算的操作成本。



      后续我们UE小组也会针对平台进行用户调研,建立了用户画像。对于运维人员痛点分析后,提出清算流程自动化设计,用定时任务直接去执行相关的流程操作,用户不用进行操作,即可完成结算,只需要关注状态和处理错误信息。



       自动化智能设计的最大缺陷就是无法遇到极致的准确率。实际处理过程中,还是会有清算错误信息存在。为了解决这个问题,我们保留了执行按钮(不手动操作时,自动跑完),运维人员也可以手动执行,处理问题。除了将操作日志信息模块,作为组件,分屏来显示错误信息,我们还按照商户维度来计算状态,以便于运维人员发现具体的错误位置。帮助操作员去查看和解决错误信息。智能化的设计解放了很大一部分的重复劳动,让用户更聚焦有意义的工作。

        智能化已然成为了设计趋势,这将会对系统的性能提升和信息处理精准化提出更高的要求。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:站酷  作者:上仙修行

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


关于后台系统设计规范总结

资深UI设计者

一套完善的产品化设计系统,可以解决内部协作的一致性问题,解决设计系统更新的周期性问题,解决一群设计师与工程师如何规模化的生产各种业务、UI的问题,从而最终解决用户体验一致性的问题。说到自己,公司的产品从接手开始便是以antdesign作为前端框架,所以很多人会说后台用antdesign、Element或者Taro的框架就足够了呀,当然不~在已有的成熟框架下,也并不能完全满足产品日(sang)益(xin)旺(bing)盛(kuang)的需求,所以设设计规范还是很有必要的。

作为B端设计师,视觉表现层面权重逐渐减少,更多的是需要梳理逻辑流程,将线下业务更好的梳理到线上流程,所以熟知设计规范可以更效率的完成工作。



设计规范的目的:


1、解决内部协作的一致性问题

为设计师内部沟通协作起到决定作用,当同一个项目存在多个设计师横向设计的时候,设计规范会避免颜色错误、间距失调、控件混乱等问题。

2、解决设计系统更新的周期性问题

随着产品的不断推进和发展,为了新增的需求和不断优化的用户体验,这时候会需要对某些规范控件进行调整,在有设计规范的情况下,可以迅速对接开发快速全局调整控件,极大的提升了设计和开发的工作效率。


3、解决设计师与工程师如何规模化的生产各种业务

关于和开发对接,图标在如今有了iconfont的项目管理下,项目可以建立自己的图标库。再加上设计建立的可复用的公共控件库,开发可以更加快捷的复用控件,减少返工率,也为后期的修改降低开发成本。


关于建立后台设计规范:


首先要了解项目适用的主要场景,也就是用户爸爸一般是在什么情况下用什么样的设备来进行操作的,然鹅你永远不知道会有什么的场景和什么样奇葩的设备在等待你。在后台的设计群一直有一个经久不衰的话题,那就是后台设计的设计分辨率是向下适配还是向上适配更合适(是1980*1080 还是 1440*900 ),这两者都是可以的,本案由于用户使用笔记本的情况居多,且设备并不是很新所以采用1440*900的分辨率向上适配1980向下适配1200。
在清楚的了解到项目背景之后,开始着手于设计规范的建立,这里关于设计规范的建立是随着设计的不断深入从而不断完善的,不必刻意深入,但是要随时更新规范文档。



关于页面构成


开发与设计所理解的页面是不一样的,所以会造成开发出来的页面有时候会因为各种原因与高保真相差较大,在设计看来(比如sketch),一个页面是由多个组结合而来,每个组里包含一个或多个字段、图片和图标等,在调整大小、间距、颜色之后慢慢成为高保真。而在开发的角度来看,整个页面就是由多个box构成,盒子与盒子之间存在空白间隔,且盒子存在一定的属性,例如盒子默认对齐于左上,盒子之间相互嵌套或覆盖需要基于所属盒子来定位。


颜色

根据品牌背景和产品定位来确定你的品牌色,用于字体、icon、按钮、插画等业务流程。功能色则是为特殊场景,例如失败、成功、提醒等情况。


字体

通过购买商用字体或使用免费字体来使用,如果选用免费字体同时也要注意区分系统,通常情况下mac系统使用默认字体苹方字体,windows系统使用微软雅黑。如今免费等字库已经越来越多了,所以这对设计师来说是一个好消息,今年阿里也在UCAN上公布了普惠体,年尾oppo也推出了自己的免费字体,文章末尾附上群友整理的免费字体导图。


边角

倒角的使用可以起到样式的区分,从而让用户感知到功能区域的分别。


图标

快速帮助用户理解产品并顺利完成操作,好的图标具有高度浓缩并快捷传达、便于记忆的特性,能够更好的传达品牌特性。


阴影

阴影的添加可以更好的提高界面品质,让用户易于区分功能区域


按钮

按钮是传达它将要发起动作的载体。 用户可以点击一个按钮来开始一个过程或工作流程,或触发一个动作。

用法:

1、要传达重要的行动。如:提交表单;

2、要导航到另一个屏幕,触发一个模式或启动一个动作。如:在进程中指定新的动作或模式;

3、按钮上的文本应保持简洁,带着明确、可操作的动词,例如:注册、下一步、下载 ;

4、优先考虑最重要的行动。行动号召太多会引起混乱,并使用户不知道下一步该做什么。

选择输入框

如无特殊需求,则默认采用框架内输入框,特殊情况可同研发一起讨论修改。这边因为一些特殊原因,在修改了代码的情况下实现了标题、选择、输入同时在框架内,这样为寸土寸金的后台界面留出了更多的空间。


表格

表格在后台系统中无处不在,对数据管理和分析起到了重要的作用,方便用户阅读,分析和比较数据。表格一般由表头、表尾、数据单元格组成。


模态/非模态弹窗

用户交互的两种方式,模态弹窗强制交互完成当前操作流程,非模态则是弱提示。

缺省状态

缺省页是指操作异常状态下给予用户反馈的提示页面,它的作用不仅是提醒用户,安抚情绪;更重要的是用“空白”触发用户的操作行为,营造良好用户体验。


结语


以上是我对于设计规范的部分总结,还有很多没有涉及到,包括非常重要的可视化部分,可以多了解一下ECharts(https://www.echartsjs.com/zh/index.html),然后希望可以和大家互相学习。设计规范的建立是长征的第一步,贯彻执行才是根本,在B端庞大的设计系统中,我们需要维护好产品的组件库,不断的完善用户体验和清晰的梳理线上业务,保证产品的功能需求才是重中之重。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:站酷  作者:请叫我红领今

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


整理数据报表系统的7个步骤

资深UI设计者

清晰且有效的数据报表可以反映出数据变化,进而帮助团队人员确定后续的产品优化迭代方向,找出可能存在的问题。那么,产品经理应当怎么整理出清晰且直观的数据报表?本篇文章里,作者总结了产品经理整理数据报表的可操作步骤,一起来看一下。

之前聊数据埋点的时候曾经提了一下,说是后面聊一下数据报表的事情,今儿个正好有空,捋一捋,跟大家做个分享。

上次分享的是《产品经理整理埋点需求的6个步骤》,有兴趣的朋友可以进去看看。

大家都很关心数据的事情,因为数据能比较直观地反应哪些地方发生了新的变化,能够提醒相关人员去关注和调整,同时一个新的优化上线之后也能够根据数据去判断优化方向是不是正确的问题。数据是最便捷的方式。

但是你想看数据就需要先把数据报表理出来,一个业务或者一个APP会产生大量的数据,你需要根据关联性和重要性去整理出具体的数据表,然后再去观察,直接看明细或者日志那你得疯。

怎么整理数据报表呢?

它需要根据核心业务流程和业务指标来梳理,然后兼顾到职级分层、部门分类、重要程度、使用频次来分别处理。

我们以电商业务为例来简单说说,选电商是因为大家对电商业务更熟悉。

我整理了一下,大致上可以按照以下步骤去整理数据报表系统。

第一步,确认要做哪些表。

你先确定有哪些部门需要看报表,常规来说包含市场、商务、运营、产品、客服、售后等部门。

然后你去看这些部门都会需要哪些报表,譬如市场部门需要渠道流量转化表等,运营部门需要营销转化表、业务流程表、销量排名表等,产品部门需要业务流程表、产品日常数据表等(观察用户留存与活跃的),客服需要用户反馈问题进度表等、售后需要售后问题进度表等。

以上只是我不专业的一个举例,实际上表是非常多的。

这里面有个地方需要注意一下,有些表看上去字段是差不多的,譬如渠道流量转化表和业务流程表,很多字段都是重复的,那么要不要并表就是一个需要考虑的问题。有的公司管理比较严格,那么最好不并表,这样可以通过后台权限来控制展示,如果相对宽松那么可以向相关部门做一下确认然后决定要不要并表。

注意:数据后台和管理后台是分开的,不能混淆。管理后台用来管理用户、商品、商户和看明细数据(用户信息表、购买订单表)等等,数据后台就是用来看统计数据的。

第二步,整理不同部门报表需要展现的字段。

以业务流程表为例。

先把业务主流程的关键节点梳理出来,到成交算是一个流程。电商的话流程大概是用户注册/登录→查看商品详情→加入购物车→立即购买/结算→立即付款→完成付款。

那么业务流程表的字段也就清楚了:

注意:报表字段是有了,但是也需要说清楚这些字段的具体含义,譬如注册/登录用户数,指的是在统计时段内,注册+登录用户的人数之和,需要去重。

不要小看这个说明,这个说明决定了大家的理解能不能一致,边界请不清晰,上面那个例子,如果没有后面那个“需要去重”那么技术在处理的时候是不会去重的,这样的话如果一个用户在指定时段内登录了多次就会统计多次。

一定要写这个说明,不写的话技术就自己发挥了,每个人对业务的理解是不一样的,所以一定要写。

第三步,去扩展报表的统计维度。

数据报表是有了,但是统计维度也需要定义,譬如需要按照日期、按渠道、按类目(商品)、按商户、按地区等等维度去看数据,那么就需要把这些和报表相关的维度加上去,这样就能实现按维度看数据的目的。

这个比较简单,有什么维度加什么维度就行,但是在处理的时候需要注意,多个条件组合能不能筛选出数据的问题,这个比较细节。

第四步,整理核心转化公式数据表。

核心转化公式数据表是给公司高管和核心业务骨干看的,高管是不可能看什么部门表的,看不过来也没必要,高管们看的表只需要体现核心数据和指标就可以。

高管们关心的也就是部门负责人关心的,部门负责人关心就应该是一线员工关心的,这就是一个拉齐公司内部认知的一个表,所以核心转化公式数据表特别重要,重要到需要单列一个步骤说明。

整理核心转化公式数据表之前就需要去梳理业务的核心转化公式,电商业务的核心转化公式如下:GMV=注册登录用户数*购买转化率*客单价*人均购买数量*(1-退货率)。

这就是一个用户从曝光到复购的一个简化的转化公式,这个公式的意义在于聚焦提高产值的关键步骤,目标不会偏。

注意:这个公式很重要,不能错,如果自己没把握的话可以问一下公司领导,知道弄清楚为止。

其实做KPI的时候也一定会需要这个核心转化公式,这样大家就能知道在哪些环节可以提高绩效,分别是提高多少,由哪些部门具体负责。

根据这个核心公式就可以整理相关的字段:

这样公司领导每天看这个数据就知道业务有没有在向预定目标发展,以及距离目标还有多远。

当然有了字段以后也需要加维度,这个就参考前面的步骤就可以。这里的统计维度其实是比较少用到的,但是功能还是必备。

 第五步,整理日常大盘数据表。

大盘表是给所有员工看的,可以作为数据后台的首页。

大盘表通常是昨日数据的汇总统计,譬如GMV、销售订单数、销售商品数、退货商品数、退货总金额、新增商户数、新增用户数、新增商品数,大概看一下数据的变化,给大家一个总体的印象。

第六步,整理实时统计表。

有一些业务对于数据的实时性要求比较高,所以会涉及到需要做实时统计表,实时统计表一般每小时更新一次数据,如果流程出现问题就可以及时进行排查和修复,但是对于大部分业务来说其实不需要,如果不是发布了新的代码,理论上是不会出现这个问题。

当然像电商APP,如果遇到双11这种,一般来说还是需要看一下实时数据的,因为全公司都很关心当天的战果,属于重要时刻。所以电商APP需要做实时表,字段的话一般也就是大盘数据表上的字段就行,额外字段的话可以根据领导的要求做。

第七步,最后确认报表字段和整理成需求文档。

把整理好的表格和各部门对一下,根据各部门的要求调整完成后制作成需求文档。

这个步骤就不多说了,按照需求的整理流程处理就行。

以上就是整理报表系统的几个步骤,当然因为细节太多了,其实没有办法在一篇文章里面讲的非常清楚,但是至少80%的东西还是在了,所以还是有参考性的。希望对大家有所帮助。

实际上做报表系统是一个持续优化和新增的过程,如果是从0开始做的话就需要单独立项然后分期做,一下子肯定是不现实的,因为工作量太大了,项目的进度不好控制,还有就是有些表并不需要马上做的,也可以缓一缓,这样优先级高的数据报表就会更快的上线。

如果业务不大的话甚至可以用excel先统计起来。总之展现形式和处理方式还是很多样化的。

产品经理在数据方面我认为其实可以多花点功夫,形成一套比较具有实操性的方法论比较好,一个数据产品和一个APP产品在竞争力上还是有差异,实际上越细分专业度越高,竞争力越强。当然首先至少要做到及格。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:人人都是产品经理  作者:代号道长

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

ERP和APS的联系与区别

资深UI设计者

ERP系统可以帮助跟踪、存储信息,有助于推动后续的产品决策,而APS系统是对ERP系统的补充和优化,具体而言,APS系统和ERP系统有什么关系?本篇文章里,作者就二者的关系、区别及应用等方面做了总结,一起来看一下。

APS作为对ERP计划系统的补充和优化,集成主要集中在与ERP计划系统的交互层次上。二者其实有很多相似和联系的地方。

  • ERP系统是企业资源计划的简称,是指建立在信息技术基础上,集信息技术与先进管理思想于一身,以系统化的管理思想,为企业员工及决策层提供决策手段的管理平台。
  • APS系统是高级计划与排程的简称,是解决企业内部生产排程和生产调度问题,常被称为排序问题或资源分配问题。

首先,APS的需求计划模块从ERP的订单输入中获得客户的实际需求,然后需求计划模块再结合外部数据中预测需求通过APS算法计算得出预测生产计划;同时再通过APS中的供应链计划模块中的约束条件,得到指导MRP的约束生产计划,传回ERP的主生产计划模块。

一、APS与ERP的关系

APS的制造计划模块与ERP的MRP通过制造订单,结合BOM、库存信息及采购信息等数据综合考虑,反复交互论证,得出将要生产排产的生产任务单。

该生产任务单包含的信息为所要加工产品的数量级需求日期。APS的排产计划模块则会根据算法而得到工作中心的生产排单以及在制品的排队序列。同时接受对车间活动的监测数据,实现对车间变化信息的动态反映。

二、APS与ERP的区别

ERP是依赖于MRP,主要基于无限物料、无限能力的理论,是通过缺料分析、能力分析、由人进行调整决定采取行动。APS的计划是基于约束理论通过事先定义的约束规则,由计算机自动采取计算。另外,APS与ERP在计划上也有许多关键的不同。

总之,ERP在除生产计划外的财务管理、成本管理、采购管理、销售管理、库存管理、人力资源管理等方面表现出了良好的管理效率和管理规范。而APS系统作为计划系统能够很好地规划基于供应链的长、中、短期计划系统,但是APS系统不能独立运行,它需要大量的基础数据的支撑才能良好地运行。

三、APS能取代ERP系统吗?

APS不能取代ERP系统,ERP系统采用的计划模型确实又不能满足目前的需要,ERP的计划模块的改变同时将影响到整个系统结构的变化。因此,用APS来优化ERP生产计划系统,既可以强化ERP的计划功能,同时又不必影响到其他成熟的商业流程。

四、APS计划层次概览

理论上,APS系统层次日趋立体化和丰富化,目前大多数APS包括6个主要的模块:供应链战略模块、供应链计划模块、需求计划、制造计划模块、排程计划模块、运输优化模块。

  • 供应链战略模块用来支持战略假设分析,确定生产地点、配送中心和其它实体的最优组合及选址方案,并对不同的成本和物料约束条件进行建模分析。
  • 供应链计划模块通过对物料、产能、运输以及服务水平等的诸多约束对供应链进行建模和最优化分析,并制定出各流程的详细计划。
  • 需求计划模块:用统计工具、因果要素和层次分析等手段实现市场与客户需求预测及管理。其关联预测功能,甚至可以通过产品水平水平的预测推出各零部件的需求量,从而优化采购决策。
  • 制造计划模块:根据已有数据,与 ERP 的 MRP 通过制造订单反复交互论证,得出将要生产排产的生产任务单。
  • 排程计划模块:考虑了生产中的产能、工序、物料及时间等约束条件制定出最优的生产计划。
  • 运输优化模块可确定运输模型以进行假设分析,并在约束条件下自动建立运载数量、发货时间、运输路线的安排。

五、APS之车间计划与排程计划

车间作业计划的目标是通过对制造过程中车间层、车间层以下各层次物流的合理计划,排程与控制,缩短产品的制造周期,减少在制品,降低库存,提高生产资源的利用率,最终达到提高生产率的目的。

从功能方面看,车间作业计划层比物料需求计划层有更具体的目标,那就是减少工件在制造系统中的“空闲时间”。

据调查,在中小批量自动化制造系统中,工件在系统中的“通过时间”主要由4部分:加工准备时间、加工时间、排队时间和运输时间。其中加工时间只占整个通过时间的的5%左右,大部分时间消耗在排队时间上,从而引起系统效益大卫降低。

车间作业计划层主要由生产作业计划层、排程计划层和生产活动控制层有机组成,其结构图如下所示。其中生产作业计划层是在战术层下达的月、旬或周生产计划的基础上,根据各种生产资源的实时状态数据,制定具体的生产作业计划,该计划将确定计划期间内各种制造设施的具体使用状况,每日/班的工件种类及数量等。

排程计划是在生产作业计划的基础上确定生产任务进行加工的顺序,以及加工过程中各种制造资源的实时排程。上述的生产计划于排程都只是为了运行层内物料的流动做出计划,虽然在规划时期系统能运行在最优或次优状态,但实际系统运行中总会出现各种随机的扰动,从而使系统是实际状态与期望状态之间产生偏差。

所以,生产活动控制的目标就是应用反馈控制原理校正这种系统的偏差,使物料流动和系统资源利用等尽可能与生产计划于排程计划所期望状况吻合。

让我们重点关注排程计划层,它在车间作业计划的三个层次中起到一个承上启下的作用,具体来说,排程计划就是针对一项可分解的工作如产品制造,探讨在尽可能满足约束条件如交货期、工艺路线、资源情况的前提下,通过下达生产指令,安排其组成部分操作使用哪些资源、其加工时间及加工的先后顺序,以获得产品制造时间或成本的优化。

车间排程计划的重要性在于它保证生产计划的有效实施,高效低耗低使用生产资源均衡生产,减少原料的加工准备、等待与传送时间,缩短产品生产周期、确保产品交货期,从而提高设备利用率与生产效率,同时,减少了在制品中的资金占用,降低了生产成本,使企业能更好地适应多变的市场需求。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:人人都是产品经理  作者:山人小道 

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

 

JavaScript 中 this 关键字

前端达人

this是什么 

一般情况下,this 指向调用他们的那个对象 ,也就是说谁调用就指向谁。

在全局作用域下 this指向谁 window

console.log(this);

普通函数里面 this 指向 window


  1. function fn() {
  2. console.log(this);
  3. };
  4. fn();

定时器里面的 this 指向 window


  1. window.setTimeout(function() {
  2. console.log(this);
  3. }, 3000);

对象的方法里面的this指向这个对象


  1. var idol = {
  2. myname: '某某某',
  3. age: '18岁',
  4. sex: '女',
  5. skill: function() {
  6. console.log(this);
  7. }
  8. };
  9. idol.skill()

给指定元素绑定事件,this指向事件绑定者 btn


  1. var btn = document.querySelector('button');
  2. // btn.addEventListener('click', function() {
  3. // console.log(this);
  4. // });
  5. btn.onclick = function() {
  6. console.log(this);
  7. };

构造函数里面的this指向对象的实例化 构造函数在调用的时候 使用new


  1. function Fun() {
  2. console.log(this);
  3. }
  4. var fun = new Fun();
  5. fun.uname = 'Jack';
  6. fun.age = '18岁';
  7. fun.sex = '男';
  8. console.log(fun)








蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

VSCode通过LocalHost打开html文件

前端达人



在这里插入图片描述

首先安装上图的插件,接着如下图右键HTML文件选择Open with Live Server即可

在这里插入图片描述

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Echarts图表根据浏览器窗口缩放进行动态缩放,多个echarts同时缩放

前端达人


更改之前的效果图:

在这里插入图片描述
更改之前浏览器窗口放大缩小图表都不会进行动态的缩放,
更改之后的效果图:

在这里插入图片描述
更改之后图表就会根据浏览器窗口大小实时监听进行缩放
代码:

 topChart.setOption({ series: [ {name: '最大值',type: 'line',stack: '最大值',data: dataMax}, {name: '最小值',type: 'line',stack: '最小值',data: dataMin}, {name: '平均值',type: 'line',stack: '平均值',data: dataAvg}, ] }); window.addEventListener("resize",()=> {//监听浏览器窗口大小 topChart.resize(); }); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果有多个图表同时渲染,给个定时器就可以了,ss[0],ss[1],ss[2],ss[3]分别表示四个图表的class

var resizeTimer = null; window.addEventListener("resize", () => { if (resizeTimer) { clearTimeout(resizeTimer) } resizeTimer = setTimeout(function(){ ss[0].resize(); ss[1].resize(); ss[2].resize(); ss[3].resize(); }, 10); }); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

没了,结束了,是不是很简单呐,如有问题,欢迎留言。


























蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档