tableau怎样保存本地_在Tableau中React本地语言3年

本文介绍了如何在Tableau中保存本地文件,并分享了Tableau使用React进行本地语言开发三年的经验总结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tableau怎样保存本地

Three years ago the Tableau Mobile team decided to rewrite our mobile app in React Native. A bit more than a year ago we released the new app on iOS and Android. It has been a great experience. Using React Native has enabled us to ship more features, more often, with better quality. There have been challenges of course, but on balance it was the right decision for us.

三年前,Tableau Mobile团队决定在React Native中重写我们的移动应用程序。 一年多以前,我们在iOSAndroid上发布了新应用。 这是一个很棒的经验。 使用React Native使我们能够更频繁地以更好的质量发布更多功能。 当然存在挑战,但总的来说,这是我们的正确决定。

In this blog post I want to share why we decided to use React Native, and what went well and what didn’t. Hopefully this will be useful to other teams out there considering React Native.

在这篇博客文章中,我想分享为什么我们决定使用React Native,什么成功了,什么没成功。 希望这对考虑使用React Native的其他团队有用。

For a little context on the app, Tableau Mobile is a companion app to Tableau Online (Tableau’s cloud offering) and Tableau Server (Tableau’s on-prem offering) that lets you view your organization’s visualizations, dashboards, and metrics on your phone or tablet.

对于应用程序的一些上下文,Tableau Mobile是Tableau Online(Tableau的云产品)和Tableau Server(Tableau的本地产品)的配套应用程序,可让您在手机或平板电脑上查看组织的可视化效果,仪表板和指标。

我们这是在哪 (Where we were)

Back in early 2017 the mobile team had to make a decision: rewrite our app or undertake some pretty significant refactoring. We had shipped both iOS and Android apps and our users were generally happy, but developers on the team were unhappy working in the codebase and our feature development was painfully slow.

早在2017年初,移动团队就不得不做出决定:重写我们的应用程序或进行一些相当重要的重构。 我们已经发布了iOS和Android应用程序,我们的用户总体上感到满意,但是团队中的开发人员对使用代码库感到不满意,并且功能开发缓慢。

The core problem was how our architecture had developed. When we first started working on the app we adopted Xamarin. This was mainly due to it being the most promising cross-platform solution. React Native didn’t exist yet, and solutions like Cordova were too limited. Code-sharing was very important because we didn’t feel like we were a large enough team to successfully maintain two separate codebases.

核心问题是我们的体系结构如何发展。 刚开始使用该应用程序时,我们采用了Xamarin。 这主要是因为它是最有希望的跨平台解决方案。 React Native还不存在,像Cordova这样的解决方案太有限了。 代码共享非常重要,因为我们觉得我们没有足够大的团队来成功维护两个独立的代码库。

Xamarin Forms wasn’t viable at that time, so we decided to implement the UI separately for both platforms and share all non-UI logic. Fatefully though, we decided to ship on iOS first and hold off on working on Android. That seemed like a reasonable choice at the time, but after we released the iOS app we went to do Android and found that a lot of the non-UI logic we hoped to share was much too heavily tied to iOS paradigms. While building the Android app we were constantly refactoring the supposedly sharable non-UI code to get things to work, and eventually we gave up on sharing large pieces.

Xamarin Forms当时不可行,因此我们决定为两个平台分别实现UI,并共享所有非UI逻辑。 不幸的是,我们决定首先在iOS上发布,并推迟在Android上运行。 当时,这似乎是一个合理的选择,但是当我们发布iOS应用之后,我们去做Android,发现我们希望分享的许多非UI逻辑与iOS范例之间的联系过于紧密。 在构建Android应用程序时,我们一直在重构所谓的可共享非UI代码以使事情正常进行,最终我们放弃了共享大型程序。

By the time we released the Android app we had ended up with a codebase that had a lot of platform-specific code, some of which was very awkwardly structured in layers below the UI. The codebase was very time consuming to work in and we were not even really leveraging Xamarin’s cross-platform capabilities. You could have argued that writing two separate apps from the start would have been better.

在发布Android应用程序时,我们最终获得了一个代码库,该代码库具有许多特定于平台的代码,其中一些在UI之下的层中结构非常笨拙。 代码库的工作非常耗时,我们甚至没有真正利用Xamarin的跨平台功能。 您可能会争辩说,从一开始就编写两个单独的应用程序会更好。

Eventually we collectively felt like we couldn’t continue in this state and so we had to decide between rewriting the app, or doing some significant refactoring.

最终,我们集体感到无法在这种状态下继续工作,因此我们不得不决定是重写应用程序还是进行一些重要的重构。

为什么我们用React Native重写? (Why did we rewrite in React Native?)

Generally when choosing between rewriting and refactoring the safe choice is refactoring because of all the well-known dangers of rewriting a codebase.

通常,在重写和重构之间进行选择时,由于重写代码库存在所有众所周知的危险,因此安全选择就是重构。

However, that is a general rule and there are exceptions. We decided to rewrite because our problems ran so deep that we really did need to fundamentally rearchitect the app. Rewriting was the cheaper and more realistic way to do that.

但是,这是一般规则,并且有例外。 我们决定重写,因为我们的问题非常严重,以至于我们确实需要从根本上重新构建应用程序。 重写是一种更便宜,更现实的方式。

Once we had decided to rewrite, that opened the door to choosing a different tech stack to build on. Xamarin had its fans on the team, but also its detractors. We debated rewriting with Xamarin, giving up on the cross-platform dream and going full native, and trying out this new kinda wild React Native thing people were talking about.

一旦我们决定进行重写,就为选择其他基于技术的堆栈打开了大门。 Xamarin在团队中拥有粉丝,但也有反对者。 我们与Xamarin讨论了重写问题,放弃了跨平台的梦想,转向了完全原生的,并尝试了人们谈论的这种新的野生React Native。

In the end we chose React Native for the following reasons.

最后,出于以下原因,我们选择了React Native。

开发人员生产力 (Developer Productivity)

First and foremost we were drawn to the promise of much faster iteration and higher productivity. We heard from other companies that things just went faster with React Native, and an initial React Native proof of concept app we wrote bore this out.

首先,我们被吸引到了更快迭代和更高生产率的承诺。 我们从其他公司那里听说,使用React Native可以使事情变得更快,而我们编写的最初的React Native概念证明应用程序证明了这一点。

跨平台 (Cross-Platform)

This was still very important to us. React Native promised to really let us be cross-platform with one codebase and a high level of code-sharing.

这对我们仍然非常重要。 React Native承诺真正让我们拥有一个代码库和高水平的代码共享跨平台。

与网络共享技术 (Sharing Technologies with Web)

Being able to use the same technology and libraries that the web development teams at Tableau use, such as React, Redux and TypeScript, was a huge plus. Aside from the technologies themselves being great, it makes it easier for someone from the web world to come work on mobile, and lets us share knowledge and experience across both domains. Additionally the possibility of sharing code between mobile and the web was very appealing.

能够使用Tableau的Web开发团队使用的相同技术和库(例如React,Redux和TypeScript)是一个巨大的优势。 除了出色的技术本身之外,它还使网络世界中的某人更容易使用移动设备工作,并使我们可以在这两个领域中共享知识和经验。 另外,在手机和网络之间共享代码的可能性非常吸引人。

社区与生态系统 (Community and Ecosystem)

Even in 2017 the React Native community was large and thriving, tons of libraries were being created, and people were excited about it. This was really important; it gave us confidence that React Native was not going to just disappear and that we could find help when we needed it.

即使在2017年,React Native社区仍然庞大且蓬勃发展,正在创建大量的图书馆,人们对此感到兴奋。 这真的很重要; 它使我们充满信心,React Native不会消失,我们可以在需要时找到帮助。

易于与本机代码集成 (Ease of Integrating with Native code)

We knew pretty much from the start that we would have to have some native code for certain features, so the ability to easily drop down to native when it was needed was a must have.

从一开始我们就很清楚,我们必须为某些功能提供一些本机代码,因此必须具备在需要时轻松降级为本机的能力。

我们的经验 (Our Experience)

So we chose React Native and spent around a year and a half rewriting our app. We released the new app to the Apple App Store and Google Play Store in February 2019. Since then we have shipped new versions regularly, enjoyed a low crash rate, and have had lots of positive feedback from our users. Our usage has also grown by around 60%.

因此,我们选择了React Native,并花了大约一年半的时间重写我们的应用程序。 我们于2019年2月在Apple App Store和Google Play商店中发布了新应用。此后,我们定期发布新版本,崩溃率低,并获得了用户的很多积极反馈。 我们的使用量也增长了约60%。

一切顺利吗? (What went well?)

开发人员生产力 (Developer Productivity)

Our team velocity is much higher now, and people are much happier working in the new codebase. One big reason for that is admittedly our new architecture, but it is also because of the great framework, tools, libraries, and especially the quick feedback cycle you get with React Native.

现在,我们的团队工作效率更高,并且人们在新代码库中的工作更加快乐。 公认的一个重要原因是我们的新架构,但这也归功于出色的框架,工具,库,尤其是React Native的快速反馈周期。

跨平台 (Cross-Platform)

Maintaining feature parity between iOS and Android has been easy. Roughly 90% of our code, excluding authentication, is in shared TypeScript.

保持iOS和Android之间的功能对等很容易。 除身份验证外,我们大约90%的代码在共享TypeScript中。

The reason for the qualification there about authentication is that we split out most of our authentication code into two separate native modules, one for each platform. Our app has to authenticate not only to our Tableau cloud-hosted servers, but also to servers hosted by our customers. There are lots of complicated scenarios we have to handle due to the variety of different authentication mechanisms that customers can use (SAML, NTLM/SSPI/Kerberos, OpenID, etc), and the fact that the servers can be behind corporate firewalls and reverse proxies. Very early on in the rewrite we realized that dealing with these authentication scenarios would require a lot of native code, very little of which would be related to the UI. So it made sense to split that code out.

之所以要进行身份验证,是因为我们将大多数身份验证代码分为两个单独的本机模块,每个平台一个。 我们的应用程序不仅必须向我们的Tableau云托管服务器进行身份验证,还必须向我们的客户托管的服务器进行身份验证。 由于客户可以使用多种不同的身份验证机制(SAML,NTLM / SSPI / Kerberos,OpenID等),并且服务器可能位于公司防火墙和反向代理之后,因此我们必须处理许多复杂的情况。 在重写的早期,我们意识到处理这些身份验证方案将需要大量的本机代码,其中很少一部分与UI相关。 因此,将代码分开是有意义的。

与网络共享技术 (Sharing Technologies with Web)

There has been a lot more knowledge sharing thanks to using shared libraries and technologies. For example, when designing our architecture we leveraged the experience other teams at Tableau had had with libraries like redux-thunk and redux-saga.

由于使用了共享的库和技术,因此有更多的知识共享。 例如,在设计架构时,我们利用Tableau的其他团队在redux-thunk和redux-saga之类的库中获得的经验。

We haven’t ended up sharing that much code between web and mobile, but we are making some headway there.

我们还没有最终在Web和移动设备之间共享这么多的代码,但是我们正在取得一些进展。

社区与生态系统 (Community and Ecosystem)

People were and still are excited about building things with React Native and the community is going strong.

人们过去和现在仍然对使用React Native构建事物感到兴奋,并且社区变得强大起来。

There are many amazing community projects. We have saved developer years, maybe decades, because of these projects. Often you can just think of something you need, search for it, and find that someone has already implemented it and open-sourced it. The community is great and pretty responsive.

有许多惊人的社区项目。 由于这些项目,我们节省了开发人员数年,甚至数十年的时间。 通常,您只需要想到所需的内容,进行搜索,然后发现有人已经实现了它并将其开源。 社区很棒,React灵敏。

We have also open sourced a small library for DNS lookups, contributed back a bunch of PRs to various projects, and have aspirations to do more in the future.

我们还开放了一个用于DNS查找小型库,为各种项目贡献了许多PR,并希望在将来做更多事情。

When we started we were a bit worried about the possibility of Facebook losing interest in the project, but that hasn’t been the case. They have invested a lot in maturing and updating the framework and moving it forward, and they are more transparent now than when we started.

当我们开始时,我们有点担心Facebook对这个项目失去兴趣的可能性,但事实并非如此。 他们在框架的成熟和更新以及向前发展方面投入了大量资金,并且与我们开始时相比,它们现在更加透明。

That said, on occasion we have taken a dependency on a project that appeared active only to have the maintainer switch jobs or lose interest and let the project stagnate. This has led to some fretting and at least one time-consuming migration.

就是说,有时我们依赖于一个看起来很活跃的项目,而只是让维护者调换工作或失去兴趣并让项目停滞不前。 这导致了一些麻烦,并且至少进行了一次耗时的迁移。

As a brief aside, one great thing we found is that when there are bugs in our open source dependencies, we can just use patch-package to fix them locally. This way we aren’t blocked waiting on issues to get fixed or pull requests to get accepted, and we don’t have to resort to forking. This was not an option for third-party libraries consumed via NuGet with Xamarin.

简短地说,我们发现的一个很棒的事情是,当我们的开源依赖项中存在错误时,我们可以仅使用补丁程序包在本地修复它们。 这样,我们就不会在等待解决问题或等待请求被接受的过程中受阻,而且我们也不必求助于分叉。 对于通过Xamarin通过NuGet使用的第三方库,这不是一个选项。

易于与本机代码集成 (Ease of Integrating with Native Code)

As mentioned we have a good amount of native code that handles authentication, and a small amount for other miscellaneous things. We even use Swift and Kotlin. Exposing this native code to the JavaScript side of the app is well documented and has been a breeze for us.

如前所述,我们有大量用于身份验证的本机代码,还有少量用于其他杂项的代码。 我们甚至使用Swift和Kotlin。 将本机代码公开到应用程序JavaScript端已有充分的文档证明,对我们来说是一件轻而易举的事情。

带有React的声明式UI (Declarative UI w/ React)

The React way of writing declarative UI has proven to be really effective for everyone on the team. Our UX designer can even work directly in the code sometimes to get the UI exactly the way they want. This is quite a bit different from the traditional back-and-forth workflow we had before, where the designer would create redlines, the developer would attempt to implement them, then the designer would update the redlines, the developer would update the code, etc etc.

事实证明,编写声明式UI的React方法对团队中的每个人都是非常有效的。 我们的UX设计人员有时甚至可以直接在代码中工作,以完全按照他们想要的方式获取UI。 这与我们之前使用的传统来回工作流程有很大不同,在传统工作流程中,设计人员将创建红线,开发人员将尝试实现它们,然后设计人员将更新红线,开发人员将更新代码,依此类推。等等

Redux (Redux)

When we started the rewrite we made Redux a core part of our architecture, and it has proven to be a great choice. It’s a somewhat unfamiliar architecture pattern at first, but once it clicks it just makes everything easier to understand. Having all state management and business logic in a consistent pattern really simplifies things. It also makes development easier in ways you might not expect, like being able to easily log any state changes in the app, or even log the entire state of the app.

当我们开始重写时,我们将Redux作为我们体系结构的核心部分,事实证明它是一个不错的选择。 刚开始时,这是一种有点陌生的架构模式,但是一旦单击它,一切都会变得更容易理解。 使所有状态管理和业务逻辑保持一致的模式确实简化了事情。 这也使开发工作变得意外,例如可以轻松记录应用程序中的任何状态更改,甚至记录应用程序的整个状态。

打字稿 (TypeScript)

We decided very early to use TypeScript, and this has also worked out very well. Most of the web development at Tableau happens in TypeScript because it makes working in large codebases with large teams significantly easier. A lot of the React Native community uses JavaScript, so we were worried about that initially, but in practice it hasn’t been an issue. There are TypeScript type definitions for most of the libraries we use and actually quite a few libraries are written in TypeScript now.

我们很早就决定使用TypeScript ,而且效果也很好。 Tableau的大多数Web开发都是在TypeScript中进行的,因为它使与大型团队一起在大型代码库中工作变得更加容易。 许多React Native社区使用JavaScript,因此我们最初担心这一点,但实际上这并不是问题。 我们使用的大多数库都有TypeScript类型定义,实际上现在有很多库是用TypeScript编写的。

工具类 (Tools)

VS Code is a great IDE and won over basically everyone who came to it from Xcode, Android Studio, or Xamarin Studio. We are also particularly big fans of Reactotron, which gives you a few methods to inspect and manipulate your app when it is running without having to activate the debugger.

VS Code是一款出色的IDE,基本上赢得了所有来自Xcode,Android Studio或Xamarin Studio的人的青睐。 我们也是Reactotron的忠实拥护者 ,它为您提供了一些在运行时检查和操作应用程序的方法,而无需激活调试器。

The debugging tools for React Native are really powerful though there are some occasional pain points we hit. Some issues aren’t really React Native’s fault, like how stepping through async/await JavaScript code in the debugger doesn’t work well, but others have been, like how the JavaScript engine can behave differently in some cases when debugging vs. not debugging.

尽管有时会遇到一些痛点,但React Native的调试工具确实功能强大。 有些问题并不是React Native的错,例如调试器中如何逐步执行异步/等待JavaScript代码无法正常工作,但其他问题却一直存在,如JavaScript引擎在调试和不调试时的某些情况下如何表现不同。

测试中 (Testing)

With React Native there are some great tools and libraries that make it easy to add automated tests. Jest takes a lot of the pain out of writing unit tests. We have unit tests covering just about all of our TypeScript code. We also use both enzyme and react-native-testing-library in different cases for testing our React component rendering and behavior.

使用React Native,有一些很棒的工具和库使添加自动化测试变得容易。 Jest消除了编写单元测试的痛苦。 我们的单元测试几乎涵盖了我们所有的TypeScript代码。 我们还在不同情况下同时使用了React本机测试库来测试我们的React组件渲染和行为。

For on-device integration testing we have started to use Cavy, and so far it has filled the gap between our Jest tests and E2E tests nicely. We do still have a small suite of Appium E2E tests, but we rarely add new ones due to the cost to write and maintain them.

在设备上集成测试中,我们开始使用Cavy ,到目前为止,它很好地填补了我们的Jest测试和E2E测试之间的空白。 我们仍然有少量的Appium E2E测试套件,但是由于编写和维护它们的成本较高,我们很少添加新的测试套件。

最大的挑战是什么? (What were the biggest Challenges?)

斜坡上升 (Ramp Up)

The more familiar you are with web technologies, web development, and JavaScript, the easier React Native will be to pick up. The less familiar you are, the harder it will be. The learning curve can be very steep, even for developers that have a lot of industry experience. This is due to having to understand: JavaScript and all its quirks as a language, TypeScript which mitigates some of those quirks but introduces its own ramp-up cost, new and different coding patterns and practices common in JavaScript projects, how React works and renders UI, what Redux does and how to use it, how React Native connects to Native code, and all the different new tools you will be using for development. It is a lot of stuff to take in before you can be, and feel, productive.

您对Web技术,Web开发和JavaScript越熟悉,React Native就越容易被接受。 您越不熟悉,就越难。 即使对于具有丰富行业经验的开发人员,学习曲线也可能非常陡峭。 这是由于必须了解以下内容:TypeScript和它的所有怪癖作为一种语言,TypeScript减轻了其中的一些怪癖,但引入了其自身的提升成本,JavaScript项目中常见的新的和不同的编码模式和实践,React的工作方式和渲染方式UI,Redux的功能以及如何使用它,React Native如何连接到Native代码,以及将用于开发的所有其他新工具。 在您变得有生产力之前,需要投入很多东西。

Developers new to mobile will also have to learn about native iOS and Android development, as React Native doesn’t completely shield you from it in our experience.

刚接触移动的开发人员还必须了解原生iOS和Android开发,因为React Native在我们的经验中并未完全将您与之隔离。

远离原住民 (Living Further Away from Native)

Using new flashy platform-specific stuff from Apple or Google can require finding third-party libraries or writing a React Native wrapper for it yourself. You don’t always get them for free, at least not quickly.

使用来自Apple或Google的新颖的,特定于平台的内容时,可能需要查找第三方库或自己为其编写React Native包装器。 您并非总是免费(至少不是很快)免费获得它们。

Additionally, cross-platform UI development requires some level of genericism, and, to be honest, compromise at times.

此外,跨平台的UI开发需要一定程度的泛泛性,老实说,有时需要妥协。

This is something worth accepting rather than fighting. Use third-party libraries where you can and try to keep things less complex. When you want the latest and greatest platform-specific feature allow some time for the community to support it, or support the community by filing issues and submitting PRs. Doing these things will let you share a lot more code and you will be leaning on React Native’s strengths.

这是值得接受而不是奋斗的东西。 在可能的地方使用第三方库,并尝试简化事情。 当您想要最新,最强大的特定于平台的功能时,请社区留出一些时间来支持它,或者通过提交问题和提交PR来支持社区。 做这些事情将使您共享更多代码,并且您将依靠React Native的优势。

导航 (Navigation)

There is no first-party navigation functionality built into React Native, and the closest thing is react-navigation. Which is a great library and we make heavy use of it, but it has struggled at times to seamlessly accommodate new things like the iPhone X notch and display cutouts on Android. We have invested a lot of time fixing issues here. It does seem like things have improved over time, but navigation is so fundamental to building a mobile app of any complexity that as a framework React Native feels incomplete without support for it.

React Native没有内置第一方导航功能,而最接近的是react-navigation 。 这是一个很棒的库,我们大量使用它,但是它有时很难无缝地容纳新事物,例如iPhone X槽口和Android上的显示切口。 我们在这里花费了大量时间来解决问题。 似乎随着时间的推移,事情已经有所改善,但是导航对于构建任何复杂程度的移动应用程序来说都是至关重要的,以至于React Native作为框架,如果不支持它,就会感到不完整。

Getting modals to look great on various form factors (both phones and tablets), resize appropriately (due to orientation changes as well as split screen), and accommodate things like the notch correctly has also been a big pain.

使模态在各种外形尺寸(手机和平板电脑)上都看起来不错,适当调整尺寸(由于方向改变以及分屏)以及正确地容纳诸如缺口之类的东西,也是一个很大的痛苦。

升级中 (Upgrading)

Dealing with upgrading React Native varies, in terms of enjoyability, between “boring chore” and “getting a cavity filled sans anesthesia”.

在令人愉悦的方面,应对React Native的工作在“无聊的琐事”和“让腔充满无痛的麻醉药”之间有所不同。

Overall it has gotten better since we adopted React Native, but the upgrades have rarely gone completely smoothly. We usually end up investing about 2 weeks of developer time on doing the upgrade and then trying to fix whatever broke. We try to upgrade every 3 months so we don’t lag too far behind, since the longer you wait the harder it tends to be. Using React Native Upgrade Helper has been a huge timesaver so take advantage of that.

总的来说,自从我们采用React Native以来,它已经变得更好,但是升级很少能完全顺利进行。 我们通常最终会花费大约2个星期的开发人员时间进行升级,然后尝试修复任何故障。 我们会每3个月进行一次升级,因此我们不会太落后,因为您等待的时间越长,往往就越难。 使用React Native Upgrade Helper节省了大量时间,因此请充分利用它。

Additionally, we have a large number of dependencies apart from React Native itself. We try to update them every 3 months, but offset from the React Native upgrades by 6 weeks. These upgrades are more consistently at the “boring chore” level of enjoyability, but the sheer number of dependencies still makes the task pretty time-consuming.

此外,除了React Native本身之外,我们还有大量依赖项。 我们尝试每三个月更新一次,但与React Native的升级相隔6周。 这些升级在“无聊的琐事”级别的娱乐性上更加一致,但是依赖性的绝对数量仍然使任务非常耗时。

摘要 (Summary)

Choosing a new framework on its own won’t build a great app. A lot of the success we had rewriting our app was admittedly due to rearchitecting, but moving to React Native was also a huge factor. It was a very good choice for the Tableau mobile team, and we would be struggling to get to where we are today without it. While every team and project is different, we would definitely recommend it.

单独选择一个新框架不会构建一个出色的应用程序。 我们重新编写应用程序的许多成功都归功于重新配置,但迁移到React Native也是一个巨大的因素。 对于Tableau移动团队来说,这是一个很好的选择,如果没有它,我们将很难到达今天的状态。 尽管每个团队和项目都不同,但我们绝对会推荐它。

May your journey be as fruitful as ours.

愿您的旅途像我们一样富有成果。

翻译自: https://engineering.tableau.com/react-native-at-tableau-3-years-in-89d43c38354c

tableau怎样保存本地

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值