构建一个混合的费用跟踪应用程序

栏目: 数据库 · 发布时间: 6年前

内容简介:构建一个混合的费用跟踪应用程序

在构建 REST 应用程序时,如果使用某个 工具 来实现 API 组成和数据连接,可以提高您的工作效率。通过这种方式,您可以将更多的精力集中在应用程序的业务逻辑和用户体验上。

在本教程中,您将构建一个工作应用程序来了解如何使用来自 StrongLoop(IBM®的一家子公司)的 API 开发工具。借助开源 LoopBack 框架(该框架构建于 Node.js 之上),您可以轻松地以可视方式开发可扩展的 REST API 并连接到该应用程序所需的数据。 StrongLoop Arc 对 StrongLoop slc 命令行工具进行了补充,包括用于构建、分析和监测 Node.js 应用程序的工具。

您的练习是构建一个简单的混合费用跟踪应用程序,该应用程序使用了您用 StrongLoop 开发的 REST API。该 REST API 使用了 Bluemix 中的 Cloudant NoSQL DB 服务来实现数据集成。您将在本地创建一个服务器应用程序来公开 REST API。为了开发混合应用程序的客户端,可以使用 LoopBack Angular JavaScript SDK(LoopBack 包含的几个软件开发工具中的一个)和 Ionic 框架。作为最后一步,我们会将应用程序的服务器端代码部署到 Bluemix。

如果费用超出了规定的限制,您还可以使用 LoopBack 框架扩展 ExpenseTracker 来发送推送通知 —这方面的练习超出了本教程的讨论范围。

借助 ExpenseTracker 应用程序,用户可以按照类别记录自己的日常开销。客户端会生成一个费用报告,并以图表的形式提供该报告。您可以扩展 API,以便客户端可以根据特定类别或月份来显示图表。

构建您的应用程序需要做的准备工作

借助开源 LoopBack 框架,您可以轻松地以可视方式开发可扩展的 REST API 并连接到该应用程序所需的数据。

第 1 步 . 创建 Bluemix 应用程序

  1. 登录到 Bluemix。
  2. 单击 CREATE APP
  3. 选择 WEB 作为应用程序类型。
  4. 选择 SDK for Node.js构建一个混合的费用跟踪应用程序
  5. 单击 CONTINUE
  6. 输入带有附加的唯一标识符(比如您的用户名或日期)的 ExpenseTracker 。(如果您尝试使用的名称是不可用的,Bluemix 会告诉您。)
  7. 单击 FINISH

将 Cloudant NoSQL DB 服务绑定到您的应用程序

  1. 在载入您的应用程序后,返回到 Bluemix 仪表板并单击应用程序名称转到应用程序的概述页面。
  2. 单击 ADD A SERVICE OR API 按钮。
  3. 在目录的 Data and Analytics 部分,选择 Cloudant NoSQL DB
  4. 单击 CREATE 将 Cloudant 服务添加到应用程序。
  5. 在提示时重新载入应用程序。
  6. 返回到应用程序的概述页面,确认 Cloudant NoSQL DB 服务现在已绑定到应用程序。

为 ExpenseTracker 应用程序创建数据库

  1. 在应用程序的概述页面上,单击 Cloudant NoSQL DB 服务来显示相关细节。
  2. 单击 LAUNCH 按钮来启动 Cloudant NoSQL Database 仪表板。
  3. 单击右上方的 Create Database 链接。在提示您输入一个数据库名称时,输入 expense-tracker 并单击 Create

第 2 步 . 在本地开发环境中实现服务器端

在这一步中,将实现一个服务器端应用程序,该应用程序使用 LoopBack 框架来公开 REST API,以便添加费用信息。

创建一个新的服务器端应用程序

  1. 在 OS 命令行下,在您想要放置新应用程序的目录中,键入 slc loopback 并按下 Enter。
  2. 键入 ExpenseTracker 作为应用程序名称并按下 Enter。
  3. 按下 Enter 接受项目目录的默认名称 (ExpenseTracker)。

服务器端代码是在 ExpenseTracker/server 文件夹中生成的。

阅读: 项目布局引用

阅读: StrongLoop API 文档

将 Cloudant 连接器添加到应用程序

ExpenseTracker 应用程序使用 Cloudant NoSQL DB 来实现数据存储。因为 Cloudant 是 CouchDB 的衍生物,所以您可以将 LoopBack CouchDB 连接器用于应用程序:

  1. 在您的 OS 命令行下,转到 ExpenseTracker 目录。
  2. 运行以下命令来安装 LoopBack Couch 连接器:

    npm install loopback-connector-couch

阅读: loopback-connector-couch

添加 Cloudant 作为应用程序的数据库

配置 ExpenseTracker 应用程序,以便连接到您在第 1 步中在 Bluemix 中创建的 Cloudant NoSQL DB 服务:

  1. 在 Bluemix 中的您的费用跟踪应用程序的概述页面中,单击 Cloudant NoSQL DB 服务中的 Show Credentials构建一个混合的费用跟踪应用程序
  2. 还可以通过 StrongLoop 命令行工具或 Arc Composer 添加您的 Cloudant 凭证。

    在文本编辑器中,打开本地项目的 server/datasources.json 文件并添加 Cloudant 数据库的详细信息:
    "cloudant": { 
      "host": "yourhost-bluemix.cloudant.com", 
      "port": 443, 
      "url": "https://yourhost-bluemix.cloudant.com", 
      "name": "cloudant", 
      "connector": "couch", 
      "db": "expense-tracker", 
      "protocol": "https", 
      "auth": { 
        "admin": { 
          "username": "cloudant-admin-username", 
          "password": "cloudant-admin-password"
        }, 
        "reader": { 
          "username": "cloudant-reader-username", 
          "password": "cloudant-reader-password"
        }, 
        "writer": { 
          "username": "cloudant-writer-username", 
          "password": "cloudant-writer-password"
        } 
      } 
     }

设置应用程序数据模型

ExpenseTracker 应用程序使用了一个简单的数据模型。LoopBack 框架中的数据模型配置还可以公开 REST API:

  1. 在您的 OS 命令行下,转换到 ExpenseTracker 目录并输入:

    slc loopback:model

  2. 提供以下详细信息来响应提示:
    • 模型名称: expense
    • 要附加的数据源: cloudant
    • 模型基类: PersistedModel
    • 公开为 REST API: Yes
    • 复数形式: expenses
  3. 按下 Enter 键退出模型创建过程。

现在,设置模型属性( categoryitempriceexpensedate ):

  1. 对于每个属性,运行 slc loopback:property 命令并在提示时提供该属性的详细信息:
    属性 模型 属性名称 属性类型 是否是必需的
    category expense category string yes
    item expense item string yes
    price expense price number yes
    expensedate expense expensedate date yes

另外,您还可以使用 Arc Composer 添加属性。

与数据进行交互

LoopBack 框架会自动为您的数据模型的所有对象生成 REST 端点。它还会相应地生成 Swagger API 文档,为您提供连接到您的数据的便捷接口。

  1. 在您的 OS 命令行下,转换到 ExpenseTracker 目录。
  2. 运行 node 命令来启动 ExpenseTracker 应用程序。
  3. 在浏览器中,访问 http://localhost:3000/explorer,在 StrongLoop API Explorer 中打开 ExpenseTracker 应用程序的 Swagger API 文档: 构建一个混合的费用跟踪应用程序

    构建一个混合的费用跟踪应用程序

  4. 单击 List Operations 显示所有可能的操作,这些操作被公开为 REST 方法。通过使用 API Explorer,您可以与模型进行交互并测试服务。

扩展模型交互

您可以通过修改应用程序的 common/models 文件夹中的 expense.js 文件来扩展模型实现。默认文件内容包括:

module.exports = function(Expense) {};

为了使得 ExpenseTracker 根据类别或月份来检索费用成为可能,可以通过添加一个方法并将该模型模型公开为要使用的客户端的 REST API 来定制模型。在文本编辑器中,打开 common/models/expense.js 文件,并使用下面的代码替换其内容:

module.exports = function(Expense) { 
 //Method to get the category based expenses for the month. 
 Expense.getMonthlyCategoryBasedAnalysis = function(cb) 
 { 
    ONE_MONTH = 30 * 24 * 60 * 60 * 1000;  // Month in milliseconds 
    var lastDate = new Date(Date.now() - ONE_MONTH); 
    var result = ""; 
    var jsonArr = []; 
    Expense.find( { expensedate: {gt: lastDate} }, 
    function (err, instance) 
    { 
        var tempArr = [0, 0, 0, 0]; 
        for (var i=0;i<instance.length;i++) 
        { 
            if(instance[i].expensedate > lastDate) 
            { 
                if(instance[i].category == "Food") 
                    tempArr[0] = tempArr[0] + instance[i].price; 
                else if (instance[i].category == "Travel") 
                    tempArr[1] = tempArr[1] + instance[i].price; 
                else if (instance[i].category == "Education") 
                    tempArr[2] = tempArr[2] + instance[i].price; 
                else if (instance[i].category == "Miscellaneous") 
                    tempArr[3] = tempArr[3] + instance[i].price; 
            } 
        } 
        for (var i = 0; i < tempArr.length; i++) { 
            var cat = ""; 
            if(i == 0) cat = "Food"; 
            if(i == 1) cat = "Travel"; 
            if(i == 2) cat = "Education"; 
            if(i == 3) cat = "Miscellaneous"; 
            //create the JSON for the client to consume 
            jsonArr.push({ 
                "category": cat, 
                      "period": "LastMonth", 
                "price": tempArr[i] 
            }); 
        } 
        console.log("out is "+jsonArr); 
        response = jsonArr ; 

      cb(null, response); 
    }); 
 } 
 //Expose the method as a REST API 
 Expense.remoteMethod ('getMonthlyCategoryBasedAnalysis',{ 
      http: {path: '/getMonthlyCategoryBasedAnalysis', verb: 'get'}, 
      //accepts: {arg: 'categoryName', type: 'string', http: { source: 'query' } }, 
      returns: {arg: 'data', type: 'string'} 
    } 
 ); 
 };

上面的代码使用 find 方法来检索上一个月的基于类别的费用,然后按类别组织数据。 getMonthlyCategoryBasedAnalysis 被公开为客户端的一个远程方法。

阅读: 远程方法

第 3 步 . 在您的本地开发环境实现客户端

您正在构建的混合应用程序对前端使用了 Ionic 框架和 LoopBack 框架的 AngularJS SDK。

阅读: Ionic 概述

创建 Ionic 应用程序

将客户端应用程序创建为一个 Ionic 应用程序:

  1. 在您的 OS 命令行下,转到 ExpenseTracker 目录,并运行以下命令来下载应用程序模板(您必须处于联网状态):

    ionic start client tabs

  2. 在系统询问您是否覆盖该文件夹时,选择 yes。

阅读: Ionic 项目结构

生成 Angular 服务

阅读: AngularJS SDK 简介

LoopBack 框架支持 AngularJS SDK。Ionic 框架使用 Angular 客户端库来调用 REST API。要为您的 LoopBack 应用程序生成 Angular 客户端库,可以使用 LoopBack Angular 命令行工具:

  1. 转换到 ExpenseTracker/client 目录。
  2. 运行以下命令:

    lb-ng ../server/server.js www/js/lb-services.js

    在上面的命令中, ../server/server.js 是主要 LoopBack 服务器脚本的相对路径,而 www/js/lb-services.js

    是该工具生成的文件的名称和路径。

  3. 打开 client/www/js/lb-services.js 文件来查看该工具生成的代码。修改现有的 urlBase 变量,以便可以调用客户端实现(此更改仅适用于本地测试):
    var urlBase = "http://localhost:3000/api";

ng-resource 模块添加到应用程序

ng-resource 模块添加到客户端应用程序,以便应用程序可以调用 REST API:

  1. 在应用程序的客户端目录中,运行以下命令:

    bower install angular-resource

    如果被询问,请选择最新的版本。该命令会将所需的库添加到 client/www/lib 文件夹。(此外,您可以从某个 AngularJS 版本

    下载该库。

  2. <head> 部分,将与 angular-resource

    相关的 JavaScript 添加到 client/www/index.html 文件:

    &lt;script src=&quot;lib/angular-resource/angular-resource.js&quot;&gt;&lt;/script&gt;

实现费用输入

应用程序需要基于表单的输入来调用 REST API,让用户可以输入费用。在 controller.js、app.js 和 index.html 模板中执行以下更改:

  1. 修改 client/www/js/app.js 中的模块声明,使之包含 lbservices.js 文件,通过将以下代码行
    angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
    更改为:
    angular.module('starter', ['lbServices','ionic', 'starter.controllers'])
  2. 在 client/www/js/app.js 中,将以 .config(function($stateProvider, $urlRouterProvider) 开头的数据块更改为:
    .config(function($stateProvider, $urlRouterProvider) { 
      $stateProvider 
        .state('tab', { 
        url: '/tab', 
        abstract: true, 
        templateUrl: 'templates/tabs.html'
      }) 
      .state('tab.addexpense', { 
        url: '/addexpense', 
        views: { 
          'tab-addexpense': { 
            templateUrl: 'templates/tab-addexpense.html', 
            controller: 'ExpenseController'
          } 
        } 
      }) 
     //This is required for the below step to display charts 
      .state('tab.charts', { 
        url: '/charts', 
        views: { 
          'tab-charts': { 
            templateUrl: 'templates/tab-charts.html', 
            controller: 'ExpenseController'
          } 
    
        } 
      }); 
    
      // if none of the above states are matched, use this as the fallback 
      $urlRouterProvider.otherwise('/tab/addexpense'); 
     });
  3. 打开 client/www/templates/tabs.html 文件,并将 Dashboard 选项卡的 <ion-tab> 修改为:
    <!-- Add Expense Tab--><ion-tab title="Add Expense" icon-off="ion-ios-plus-outline" 
     icon-on="ion-ios-plus" href="#/tab/addexpense"> 
     <ion-nav-view name="tab-addexpense"></ion-nav-view> </ion-tab>
  4. 将 client/www/templates/tab-dash.html 文件的名称更改为 tab-addexpense.html。使用以下代码替换文件内容:
    <ion-view view-title="Add Expense"> 
      <ion-content padding="true" class="has-header" scroll="false" overflow-scroll="false"> 
        <div> 
          <br> 
          <form name="expensesForm" ng-submit="addExpense()"> 
          <div class="list"> 
            <label class="item item-input"> 
              <span class="input-label">Category</span> 
              <select class="form-control focus" 
                  name="category" required ng-model="newExpense.category"> 
                  <option name="Food" id="Food">Food</option> 
                  <option name="Travel" id="Travel">Travel</option> 
                  <option name="Miscellaneous" id="Cosmetics">Miscellaneous</option> 
                  <option name="Education" id="Education">Education</option> 
                </select> 
            </label> 
            <label class="item item-input"> 
              <span class="input-label">Item</span> 
                  <input type="text" class="form-control" name="item" placeholder="Expense Item Name" 
                      autocomplete="off" required ng-model="newExpense.item"> 
            </label> 
            <label class="item item-input"> 
              <span class="input-label">Price</span> 
                  <input type="text" class="form-control" name="price" placeholder="Expense Price" 
                      autocomplete="off" required ng-model="newExpense.price"> 
                   <input type="hidden" class="form-control" name="date" placeholder="Date" 
                       autocomplete="off" required ng-model="newExpense.expensedate"> 
           </label> 
         </div> 
               <br> 
           <button class="btn btn-default" ng-disabled="expensesForm.$invalid">Add Expense</button> 
         </form> 
       </div> 
     </ion-content> 
     </ion-view>
  5. 将 Add Expense REST API 调用添加到 client/www/js/controllers.js 文件。此外,将 ExpenseController 添加到控制器:
    .controller('ExpenseController', 
             [ '$scope','$rootScope', 'Expense', function($scope, $rootScope, Expense) { 
        $scope.newExpense = {}; 
        $scope.newExpense.category = 'Food'; 
        $scope.newExpense.expensedate = new Date(); 
        //Method call to create the expense record 
        $scope.addExpense = function() 
        { 
            Expense.create($scope.newExpense).$promise.then(function(expense) 
            { 
                $scope.newExpense = {}; 
                $scope.newExpense.category = 'Food'; 
    
            }); 
        }; 
     }])

将定制的 REST API 添加到 lb-services.js

对于要使用您在第 2 步中添加的定制 REST API 的应用程序,必须修改 lb-services.js 文件:

  1. 打开 client/www/js/lb-services.js。
  2. 搜索 findOne 方法声明,该声明位于 Expense 模型声明之下。
  3. 在紧接着 findOne 方法的后面,为第 2 步中在 expense.js 文件中声明的定制方法添加以下代码:
    "getMonthlyCategoryBasedAnalysis": { 
         url: urlBase + "/expenses/getMonthlyCategoryBasedAnalysis", 
         method: "GET"
       },

angular-chart 模块添加到应用程序

要在应用程序中显示基于类别的每月费用图表,可添加 angular-chart 模块:

  1. 在您的 OS 命令行下,转到客户端目录。
  2. 要在 client/www/lib 文件夹中包含所需的库,可以运行以下命令:

    bower install angular-chart.js

    此外,您还可以从 项目站点

    下载该库。

  3. <head> 部分,将 Angular SDK 添加到 client/www/index.html 文件:
    <script src="js/lb-services.js"></script>
  4. <head> 部分,将与 angular-chart 相关的 JavaScript 添加到 client/www/index.html 文件:
    <script src="lib/Chart.js/Chart.min.js"></script> 
     <script src="lib/angular-chart.js/dist/angular-chart.js"></script>
  5. <head> 部分,将与 angular-chart 相关的 CSS 代码添加到 index.html 文件:
    <link rel="stylesheet" href="lib/angular-chart.js/dist/angular-chart.css">
  6. 通过将 chart.js 添加到模块声明,将 chart 模块添加到应用程序:
    angular.module('starter', ['lbServices','ionic', 'chart.js','starter.controllers'])
  7. chart.js 添加到 controllers.js 的第一行:
    angular.module('starter.controllers', ['chart.js'])

添加一个基于类别的每月费用表

要检索基于类别的每月费用,必须调用 getMonthlyCategoryBasedAnalysis 方法:

  1. 打开 client/www/templates/tabs.html 文件并将 Chats 选项卡的 <ion-tab> 更改为:
    <!-- Charts Tab --> 
     <ion-tab title="Charts" icon-off="ion-load-d" icon-on="ion-load-b" href="#/tab/charts"> 
        <ion-nav-view name="tab-charts"></ion-nav-view> 
     </ion-tab>
  2. 删除或注释掉 client/www/templates/tabs.html 文件中的 Account 选项卡。
  3. 将 client/www/templates/tab-chats.html 重命名为 tab-charts.html。
  4. 将以下代码添加到 tab-charts.html 文件:
    <ion-view view-title="Charts" ng-init="drawCategoryMonthlyChart()"> 
      <ion-content> 
            <canvas id="bar" class="chart chart-bar" chart-data="data" chart-series="series" 
                chart-labels="labels" responsive="false" height="100" chart-legend="true" 
                chart-options="{datasetFill: false, scaleBeginAtZero : false}"> 
            </canvas> 
      </ion-content> 
     </ion-view>
  5. 将以下代码添加到 client/www/js/controllers.js 文件,作为 ExpenseController 控制器的一部分:
    //Method call to draw the chart. Calls the REST API & forms the angular chart based variables. 
      $scope.drawCategoryMonthlyChart = function() 
        { 
            Expense.getMonthlyCategoryBasedAnalysis().$promise.then(function(results) 
            { 
                      expenseData = results.data; 
                var foodPrice = 0, travelPrice = 0, eduPrice = 0, miscPrice = 0; 
                for(i=0;i<4;i++) 
                { 
                     if(expenseData[i].category == "Food") 
                         foodPrice = expenseData[i].price; 
                                 if(expenseData[i].category == "Travel") 
                        travelPrice = expenseData[i].price; 
                                 if(expenseData[i].category == "Education") 
                        eduPrice = expenseData[i].price; 
                                if(expenseData[i].category == "Miscellaneous") 
                        miscPrice = expenseData[i].price; 
                } 
    
    
            $rootScope.labels = ['Food','Travel','Education','Miscellaneous']; 
            $rootScope.series = ['ThisMonth']; 
               $rootScope.data = [ 
                  [foodPrice, travelPrice, eduPrice, miscPrice] 
                   ]; 
              }) 
        };

第 4 步 . 将应用程序推送到 Bluemix

将服务器应用程序推送到 Bluemix,以便客户端可以调用 REST API:

  1. 可选:为了减少您上传到 Bluemix 的代码量,请将客户端文件夹移动到不同的地方,并(在您进行到第 5 步时)从新的位置运行客户端应用程序。
  2. 在您的 OS 命令行下,转到 ExpenseTracker 目录并运行以下代码:

    cf push ExpenseTracker -c &quot;node server/server.js&quot;

  3. 转到 http:// app-name .mybluemix.net/explorer(其中的 app-name 是您在第 1 步中在 Bluemix 中创建的 Node.js expense-tracker 应用程序的名称)来检查正在运行的 REST API。

第 5 步 . 运行客户端混合应用程序

因为客户端应用程序是一个混合应用程序,所以它可以在一个浏览器、模拟器或移动设备中运行。这一节将介绍如何在一个浏览器或 iOS 设备中运行它。

在浏览器中测试应用程序

  1. 在 client/www/js/lb-services.js 文件中,更改 urlBase ,使之指向 Bluemix 路由: http://app-name.mybluemix.net/api
  2. 在您的 OS 命令行下,更改到 ExpenseTracker/client 目录并运行以下代码:

    ionic serve

  3. 在您的浏览器中,转换到 http://localhost:8100/。单击 Add Expense 来测试用于添加费用的表单: 构建一个混合的费用跟踪应用程序
  4. 单击 Charts 来查看费用报告: 构建一个混合的费用跟踪应用程序

在 iOS 设备中测试应用程序(可选)

  1. 在您的 OS 命令行下,转换到应用程序的客户端文件夹并运行以下代码:

    ionic platform add ios

    此命令将向客户端应用程序添加 iOS 平台支持。 (类似地, ionic platform add android

    将向客户端应用程序添加 Android 平台支持。)

  2. 运行 ionic build ios 来构建针对 iOS 设备的项目。
  3. 上面的命令创建了一个名为 client/platforms/ios 的文件夹,该文件夹包含一个 Xcode 项目。在您的 Xcode 工具中打开该项目。通过 USB 连接您的设备,并选择要运行该项目的设备: 构建一个混合的费用跟踪应用程序
  4. 测试用于添加费用和查看费用图表的应用程序界面: 构建一个混合的费用跟踪应用程序 构建一个混合的费用跟踪应用程序

阅读: 测试您的 Ionic 应用程序

备注:您的应用程序需要能够访问 HTTP 传输,因为它要调用 REST API。您可能会得到消息 App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure 。您可以通过添加以下代码,通过应用程序的 client/platforms/ios/client/Info.plist 文件处理临时异常:

<key>NSAppTransportSecurity</key> 
  <dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <true/>  </dict>

阅读: NSAppTransportSecurity

结束语

通过使用 StrongLoop LoopBack 框架和 Ionic 框架来开发示例应用程序,您现在知道了(使用正确的工具)公开 REST API 并在混合应用程序使用它们是多么容易。您可以扩展在本教程中学到的知识,通过定义模型之间的关系,创建生产就绪的、企业级的应用程序。

BLUEMIX SERVICE USED IN THIS TUTORIAL: Cloudant NoSQL DB 提供了对始终打开的完全托管 NoSQL JSON 数据层的访问。

相关主题: 移动开发 Node.js


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品经理必懂的技术那点事儿:成为全栈产品经理

产品经理必懂的技术那点事儿:成为全栈产品经理

唐韧 / 电子工业出版社 / 2018-1 / 59

《产品经理必懂的技术那点事儿:成为全栈产品经理》以非技术背景产品经理学习技术为主题,将技术知识以简单并且易于理解的方式讲述出来,帮助非技术背景产品经理了解技术、学习技术,旨在帮助产品经理高效地与技术人员进行沟通与合作,避免不懂技术带来的困扰。 《产品经理必懂的技术那点事儿:成为全栈产品经理》主要内容围绕产品经理需要了解的互联网基础技术知识展开,涉及客户端、服务器端、数据库及一些数据处理知识。......一起来看看 《产品经理必懂的技术那点事儿:成为全栈产品经理》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具