提升前端開發(fā)效率,攜程機(jī)票定制代碼生成器實(shí)踐
作者簡介
Zilin Wang,資深前端開發(fā)工程師,擅長前端打雜,專注于Remix、Radix UI、Haskell等領(lǐng)域。
Sheila Dai,資深前端開發(fā)工程師,關(guān)注前端性能優(yōu)化、前端智能化。
在日常的研發(fā)工作中,編寫前端界面結(jié)構(gòu)占據(jù)了一部分工作量。很多UI組件都存在共性,如何減少編寫UI界面的開發(fā)時(shí)間,以及提取公用的前端組件,從而達(dá)到提升研發(fā)效能的目的,是我們的重要課題。
在《前端智能化探索,骨架屏低代碼自動(dòng)生成方案實(shí)踐》中,我們?cè)?jīng)探索過一種自動(dòng)生成骨架屏代碼的方案,在此基礎(chǔ)上,我們?cè)O(shè)計(jì)了一套代碼生成器的定制流程,到達(dá)可以定制任意目的代碼的效果。本文將圍繞視覺稿生成任意代碼,探討代碼生成器的原理與細(xì)節(jié),最后是落地的效果展示。
一、背景
骨架屏代碼自動(dòng)生成,作為一個(gè)最小 MVP (Minimum Viable Product),驗(yàn)證了視覺稿自動(dòng)生成代碼的可行性與實(shí)用性。
那么,除了高度重復(fù)性質(zhì)的骨架屏以外,還能夠?qū)崿F(xiàn)哪些通用組件?甚至能不能實(shí)現(xiàn)應(yīng)用的業(yè)務(wù)組件?
如圖是視覺稿生成代碼的粗略步驟,我們可以看到,在提取視覺稿信息后使用通用算法,得到中間代碼后,可以生成我們的目的代碼。在這個(gè)步驟中,通過編輯中間代碼,我們可以自動(dòng)生成不同的目的代碼。
我們的預(yù)期則是把這一步驟,交付給業(yè)務(wù)研發(fā)自己來實(shí)現(xiàn),通過在 D2C 平臺(tái)上插入不同的代碼生成器,實(shí)時(shí)自動(dòng)生成需要的目的代碼。
在整個(gè)頁面的轉(zhuǎn)換結(jié)果上,頁面上的每個(gè)組件都可以通過選擇不同的代碼生成器來得到相應(yīng)的結(jié)果。
二、問題分析
本方案是在骨架屏探索成果上的拓展設(shè)計(jì),我們面臨的問題主要有以下三個(gè):
1)平臺(tái)角度:如何讓生成器可高度定制?
我們首先需要解決的問題,是讓業(yè)務(wù)研發(fā)可以自行定義代碼生成器。那么我們需要把中間代碼層從封閉的平臺(tái)中剝離出來,變成一個(gè)開放的插件入口。
2)生成器作者角度:如何快速上手編寫?
雖然針對(duì)一個(gè)指定目標(biāo)代碼結(jié)果的生成器,只需要一次中間代碼的編寫,即可作為一個(gè)公開插件在平臺(tái)上提供給其他研發(fā)進(jìn)行使用。但這個(gè)中間代碼的編寫過程依然存在一定的門檻,會(huì)讓想要使用的人望而卻步。我們需要降低這個(gè)門檻,讓業(yè)務(wù)研發(fā)可以隨時(shí)發(fā)布或者調(diào)整自己的代碼生成器。
3)普通使用者角度:如何零成本使用已有生成器?
如果平臺(tái)上提供的生成器,已經(jīng)滿足使用者的需求了,那么他可以在不學(xué)習(xí)相關(guān)知識(shí)的前提下進(jìn)行一鍵生成代碼使用。除此之外,我們需要在平臺(tái)上新增一些功能,以便讓使用者在這個(gè)過程中可以更加順暢地進(jìn)行預(yù)期的自動(dòng)代碼生成。
三、解決方案
為了解決上文提到的三個(gè)問題,我們從三個(gè)方向去解決這些問題:
- 中間代碼插件化
- 生成器編寫模版化
- D2C 平臺(tái)優(yōu)化
3.1 中間代碼插件化
在自動(dòng)生成代碼的流程中,我們需要把生成器這部分從封閉的平臺(tái)中剝離出來,提供給業(yè)務(wù)研發(fā)進(jìn)行自研。我們主要借助了 UIDL (Universal Interface Definition Language)結(jié)構(gòu),依據(jù)這個(gè) UI 層面的數(shù)據(jù)結(jié)構(gòu)解析得到我們需要的目的代碼內(nèi)容。
1 ) UIDL 簡介
UIDL,即通用界面定義語言,一種用于描述 Web、移動(dòng)和桌面應(yīng)用程序用戶界面的通用語言,是 teleport 對(duì)于 UI 描述的一種定義規(guī)范。UIDL是 DSL(Domain Specific Language,解決特定領(lǐng)域問題的語言) 的子集。它與平臺(tái)無關(guān),可以應(yīng)用于任何平臺(tái)或者應(yīng)用程序。
使用 UIDL 的主要目的就是將用戶界面描述成一種機(jī)器可讀的格式,以幫助開發(fā)人員更加高效地構(gòu)建、測試和維護(hù)用戶界面。UIDL具體定義內(nèi)容可以參考官方文檔,這里給出一個(gè)簡單的示例:
{
"name": "Badge",
"propDefinitions": {
"count": {
"type": "number"
}
},
"node": {
"type": "element",
"content": {
"elementType": "container",
"attrs": {
"class": "badge"
},
"children": [
{
"type": "element",
"content": {
"elementType": "text",
"attrs": {
"class": "badge-text"
},
"children": [
{
"type": "dynamic",
"content": {
"referenceType": "prop",
"id": "count"
}
}
]
}
}
]
}
}
上面的UIDL描述了一個(gè) Badge 組件,它接受一個(gè) number 類型的屬性 count,輸出我們常見的 Badge 組件 UI 結(jié)構(gòu)。通過使用teleport 提供的 React 代碼生成器,我們可以得到下面的結(jié)果:
import React from 'react'
import PropTypes from 'prop-types'
const Badge = (props) => {
return (
<div className="badge">
<span className="badge-text">{props.count}</span>
</div>
)
}
Badge.propTypes = {
count: PropTypes.number,
}
export default Badge
UIDL 會(huì)給出一個(gè)通用的 UI 界面節(jié)點(diǎn)描述,通過生成器可以渲染得到我們需要的指定框架代碼。
2 ) 生成器解析
在已有生成器滿足業(yè)務(wù)研發(fā)的需求前提下,可以直接進(jìn)行使用;不滿足則業(yè)務(wù)研發(fā)通過編輯模版可以得到新的生成器,再通過平臺(tái)研發(fā)審核發(fā)布到已有生成器列表中,開放給所有研發(fā)進(jìn)行代碼的自動(dòng)生成。
在把中間代碼層插件化的過程中,我們主要借助了 UIDL 的定義結(jié)構(gòu),使用 teleport 定義的生成器結(jié)構(gòu)來進(jìn)行代碼轉(zhuǎn)換,內(nèi)部包含了 Mappings(UI 組件映射)、Plugins(插件處理邏輯)、PostProcessors(后處理器)。
- Mappings:給出組件映射關(guān)系;
- Plugins:處理復(fù)雜對(duì)應(yīng)邏輯;
- PostProcessors:美化代碼格式等等。
代碼生成器實(shí)際上就是對(duì)中間代碼進(jìn)行解析,不同的解析得到不同的結(jié)果。
3 ) 生成器插槽
我們?cè)谄脚_(tái)上提供了選擇不同生成器的入口,根據(jù)即時(shí)選擇的類型,實(shí)時(shí)自動(dòng)生成對(duì)應(yīng)的代碼。
業(yè)務(wù)研發(fā)完成新生成器的編寫后,發(fā)布成npm包,通知平臺(tái)研發(fā)進(jìn)行審核。審核成功后,相應(yīng)的生成器版本會(huì)展示在平臺(tái)的生成器入口處。
其他業(yè)務(wù)研發(fā)可以在這個(gè)公開的生成器列表中,選擇適合自己業(yè)務(wù)場景的生成器,進(jìn)行代碼的一鍵自動(dòng)生成。
3.2 生成器編寫模版化
為了降低新生成器編寫者的學(xué)習(xí)成本,我們提供了可本地預(yù)覽的代碼模版,并且封裝了常用前端框架生成器及一些通用方法。
1 ) 開發(fā)流程
業(yè)務(wù)研發(fā)clone模版?zhèn)}庫到本地,模版編寫主要有兩個(gè)方向:
a. 編寫某種前端框架下的通用組件:視覺稿 DSL 轉(zhuǎn)換為需要的 UIDL 結(jié)構(gòu)(調(diào)整層級(jí)、組件名稱等),再調(diào)用對(duì)應(yīng)的框架生成器,生成代碼;
b. 編寫特定的數(shù)據(jù)結(jié)構(gòu):獲取 DSL 中的節(jié)點(diǎn)數(shù)據(jù),構(gòu)建為新的數(shù)據(jù)結(jié)構(gòu)。
再在本地進(jìn)行效果預(yù)覽,最后發(fā)布成為一個(gè)獨(dú)立的npm包,通知平臺(tái)研發(fā)審核后插入到插槽中。
2 ) 本地開發(fā)與預(yù)覽
業(yè)務(wù)研發(fā)可以根據(jù)我們提供的模版來進(jìn)行定制化輸出,也可以參考其他公開的生成器進(jìn)行編寫。
以下為提供的模版結(jié)構(gòu):
custom-generator-template
|----package.json // 發(fā)布的 npm 包信息
|----README.md
|----src
| |----index.ts // 編寫的自定義 DSL
|----test // 本地測試輸入與輸出
| |----files // 輸出的文件結(jié)構(gòu)
| |----dsl.json // 輸入的dsl結(jié)構(gòu)
| |----index.ts
|----tsconfig.json // 默認(rèn)配置源文件為 ts
|---- dist // 輸出的 dist 目錄
模版中內(nèi)置了輸入與輸出的本地便捷測試:在編輯src/index.ts文件后,執(zhí)行npm run test即可在test/目錄下看到輸出的內(nèi)容。
下圖為本地預(yù)覽示例,左為 DSL 結(jié)構(gòu),右為經(jīng)過生成器轉(zhuǎn)換的代碼:
本地測試使用的 DSL 結(jié)構(gòu)可以在平臺(tái)上快速復(fù)制得到。
3 ) 常用 API 封裝
為了降低生成器編寫者的學(xué)習(xí)成本,我們會(huì)處理前序與后序步驟,在實(shí)際使用中都是可選的:
- 前序:原始視覺稿 DSL 轉(zhuǎn)換為 UIDL 結(jié)構(gòu);
- 后序:調(diào)用 API 生成相應(yīng)框架代碼。
普通的 DSL 代碼生成模型如下:
export type GenerateCustomFiles = (dsl: DSL) => Promise<CompiledComponent>
// CompiledComponent 是定義好的輸出結(jié)構(gòu),包含代碼依賴和代碼文件
對(duì)于頁面級(jí)別的 DSL,引進(jìn)了 Design Tokens 和共享樣式的概念,會(huì)在普通的 DSL 上添加一些屬性:
export type GenerateCustomFiles = (rootDSL: RootDSL, options: GenerateCustomOptions) => Promise<CompiledComponent>;
// options 是傳入的生成文件參數(shù),當(dāng)前有樣式參數(shù)(CSS Module、Inline Style等)、布局參數(shù)(Pixel、Rem)等
如果調(diào)用平臺(tái)開發(fā)的API,就可以很方便的生成業(yè)務(wù)定制化的代碼:
const generateFiles: GenerateCustomFiles = async (rootDSL, options) => {
const rootUIDL = rootDSLToRootUIDL(rootDSL, {
layoutUnit: options.layoutUnit,
uidlAdjust,
}) // 前序:使用uidlAdjust進(jìn)行DSL轉(zhuǎn)成UIDL過程中屬性的修改
// 核心邏輯:UIDL 結(jié)構(gòu)修改
// ...
const cc = await generateReactFiles(rootUIDL, { layoutUnit: options.layoutUnit, style: options.style })
// 后序:調(diào)用前端框架生成API
return cc
}
在后序步驟中,攜程 Design To Code 支持的框架 API 如下:
- generateHtmlFiles
- generateVueFiles
- generateReactFiles
- generateReactNativeFiles
這樣處理是為了讓編寫者無需關(guān)心復(fù)雜的前端框架自動(dòng)生成過程,僅通過修改 DSL 結(jié)構(gòu)層次或名稱即可到達(dá)自己定制的目的。
3.3 D2C 平臺(tái)優(yōu)化
為了讓普通使用者零成本地在 D2C 平臺(tái)上進(jìn)行代碼的一鍵自動(dòng)生成,我們對(duì)平臺(tái)進(jìn)行了一些優(yōu)化。接下來介紹其中三個(gè)重要功能:
- 節(jié)點(diǎn)標(biāo)簽
- 局部自動(dòng)生成
- 沙盒預(yù)覽模式
1) 節(jié)點(diǎn)標(biāo)簽
點(diǎn)擊界面左側(cè)的 DSL 節(jié)點(diǎn)的標(biāo)簽 icon,彈出浮層,可以手動(dòng)給當(dāng)前節(jié)點(diǎn)添加語義化標(biāo)簽名稱。
手動(dòng)打標(biāo)簽,是在 DSL 節(jié)點(diǎn)中新增了一個(gè)屬性。在生成器中可以根據(jù)該屬性實(shí)現(xiàn)不同的效果。
例如在落地方案 Flybirds 測試用例的自動(dòng)生成中,通過給視覺稿中不同的文案部分做了三個(gè)特定標(biāo)簽識(shí)別:render、exist、click,分別對(duì)應(yīng)了以下的執(zhí)行語句:
- render: 頁面渲染完成出現(xiàn)元素 [機(jī)票]
- exist: 存在[機(jī)票]的文案
- click: 點(diǎn)擊[text=機(jī)票]
從視覺稿信息中來說,這些結(jié)構(gòu)都是文字節(jié)點(diǎn),沒有什么區(qū)別。通過手動(dòng)打標(biāo)可以在自動(dòng)生成時(shí)補(bǔ)充額外的信息。
2 ) 局部自動(dòng)生成
下圖中,左邊是 DSL 節(jié)點(diǎn),右邊是視覺稿標(biāo)注。點(diǎn)擊左側(cè)節(jié)點(diǎn)會(huì)突出顯示視覺稿中內(nèi)容,同樣地,點(diǎn)擊右側(cè)視覺稿局部也會(huì)在左側(cè)節(jié)點(diǎn)中同步突出對(duì)應(yīng)節(jié)點(diǎn)。
同時(shí),會(huì)在下端實(shí)時(shí)展示當(dāng)前選擇的局部畫板通過生成器自動(dòng)生成的代碼內(nèi)容。圖示為點(diǎn)選“僅看直飛”按鈕局部后,生成的 React Native 代碼。
在生成器滿足業(yè)務(wù)研發(fā)需求的前提下,可以點(diǎn)選局部后,直接復(fù)制下方的代碼到倉庫中進(jìn)行應(yīng)用。
在初始進(jìn)入畫板時(shí),或者點(diǎn)選了 DSL 的根節(jié)點(diǎn),下端會(huì)通過選擇的生成器實(shí)時(shí)渲染整個(gè)頁面的代碼。
3 ) 沙盒預(yù)覽模式
為了更加真實(shí)地預(yù)覽自動(dòng)生成的代碼,我們提供了沙盒模式。React / Vue 等代碼可以直接在 web 端預(yù)覽,React Native 我們也通過react-native-web
轉(zhuǎn)為web端代碼,可以進(jìn)行實(shí)時(shí)編輯并查看對(duì)應(yīng)效果。
此外,沙盒模式還提供了一鍵打包下載的功能,使項(xiàng)目可以進(jìn)行快速部署發(fā)布。
四、落地效果
落地效果均為機(jī)票實(shí)現(xiàn)的生成器,可在平臺(tái)中進(jìn)行一鍵自動(dòng)生成。我們從三個(gè)不同的維度來進(jìn)行自定義生成器效果展示。
4.1 自動(dòng)生成指定框架代碼
1 ) 效果演示
圖例為 React Native 代碼自動(dòng)生成。
2 ) 內(nèi)部實(shí)現(xiàn)
語言框架的應(yīng)用,是作為自動(dòng)化轉(zhuǎn)碼的一個(gè)基礎(chǔ)底層代碼內(nèi)容。在此基礎(chǔ)上,我們可以得到組件化的自動(dòng)代碼生成。但語言框架轉(zhuǎn)碼比組件化更為復(fù)雜,可以說語言框架轉(zhuǎn)碼是組件化轉(zhuǎn)碼的一個(gè)超集。
在這個(gè)過程中,借助了前文提到的 teleport 定義的 generator 生成器結(jié)構(gòu),其中需要調(diào)整mappings、plugins、postprocessors,來得到我們預(yù)期的框架代碼結(jié)構(gòu)。需要處理的具體內(nèi)容如下:
- 識(shí)別抽象 DSL 節(jié)點(diǎn):建立我們自定義的語言框架的首要步驟,需要把抽象的 DSL 映射為基礎(chǔ)的 HTML 節(jié)點(diǎn),識(shí)別 elementType 為正確的對(duì)應(yīng)組件名;
- 映射組件:支持 React Native 組件映射及對(duì)應(yīng)引用 package,讀取資源文件生成 React Native組件。在這里最終映射預(yù)覽的文件建立在 react-native-web 的基礎(chǔ)上;
- 處理依賴:處理文件之間的依賴關(guān)系,加載組件,以便輸出正確文件;
- 樣式表風(fēng)格化:第一步,將 CSS 風(fēng)格的樣式表轉(zhuǎn)換為 React Native StyleSheet;第二步,處理屏幕適配;
- 調(diào)整 DSL 結(jié)構(gòu):處理中間 DSL,減少冗余以及修正轉(zhuǎn)化錯(cuò)誤;在有了大體的轉(zhuǎn)化前后結(jié)構(gòu)內(nèi)容,依然需要進(jìn)一步修復(fù)轉(zhuǎn)化過程中的一些冗余,以減少代碼 size,或者降低生成的樣式在不同機(jī)型上出錯(cuò)的可能性。
以 React Native 為例,我們主要需要做到:
(i). 刪除冗余:刪除不需要的樣式節(jié)點(diǎn),例如 fontFamily、letterSpacing、text 節(jié)點(diǎn)的 width / height;
(ii). 合并代碼:合并節(jié)點(diǎn),例如 paddingTop 與 paddingBottom 需要合并為 paddingVertical;
(iii). 兼容樣式:刪除或者修改會(huì)引起不同機(jī)型樣式兼容問題的節(jié)點(diǎn),例如 lineHeight、fontWeight。
- 美化代碼:需要格式化生成的 typescript 代碼;
- 支持在線預(yù)覽自動(dòng)生成的 React Native 代碼:我們需要在 web 頁面進(jìn)行實(shí)時(shí)編輯預(yù)覽,因此引入了
react-native-web
,以便使用者能實(shí)時(shí)調(diào)試。
4.2 自動(dòng)生成指定組件代碼
1) 效果演示
圖例為 React Native Label 組件代碼自動(dòng)生成。
2) 內(nèi)部實(shí)現(xiàn)
我們可以通過編輯中間代碼,來得到預(yù)期的業(yè)務(wù)組件功能代碼,包含動(dòng)畫效果、交互邏輯等。目標(biāo)是生成一套在生產(chǎn)環(huán)境高可用性、復(fù)用性的組件。以標(biāo)簽組件為例,示范如何生成預(yù)期的組件代碼。
在這個(gè)過程中,需要使用多個(gè)真實(shí)場景視覺稿進(jìn)行代碼渲染,在線預(yù)覽效果,進(jìn)行代碼調(diào)試與可用性測試。經(jīng)過該場景的多次測試,我們需要覆蓋兩個(gè)結(jié)構(gòu)不同的轉(zhuǎn)換場景:
- 帶有漸變背景的標(biāo)簽處理
- 常規(guī)文案處理。
轉(zhuǎn)換核心代碼如下(抓取對(duì)應(yīng)節(jié)點(diǎn)信息,構(gòu)建為我們預(yù)期的代碼結(jié)構(gòu):
根據(jù)當(dāng)前節(jié)點(diǎn)的類型,做不同的層級(jí)處理。原始 DSL 與目的代碼前后預(yù)覽如下:
4.3 自動(dòng)生成測試用例代碼
1 ) 演示效果
圖例為 Flybirds 測試用例代碼自動(dòng)生成。
2) 內(nèi)部實(shí)現(xiàn)
我們使用攜程機(jī)票開源的跨端跨框架的BDD UI 自動(dòng)化測試方案——Flybirds 的用例結(jié)構(gòu)來進(jìn)行構(gòu)建該生成器的目的內(nèi)容。
因?yàn)槲谋竟?jié)點(diǎn)的結(jié)構(gòu)是一致的,我們需要手動(dòng)給不同的文本節(jié)點(diǎn)賦上不同的語句含義,在此處我們通過在平臺(tái)上給視覺稿圖層打標(biāo)簽進(jìn)行實(shí)現(xiàn)。
在實(shí)現(xiàn)上,通過遞歸 DSL 結(jié)構(gòu)中的文本節(jié)點(diǎn)進(jìn)行文案內(nèi)容的查找與輸出對(duì)比。轉(zhuǎn)換代碼如下:
執(zhí)行這段代碼,本地運(yùn)行npm run test
,前后輸出內(nèi)容對(duì)比:
測試用例生成作為一項(xiàng)實(shí)驗(yàn)性實(shí)踐,充分說明了自動(dòng)轉(zhuǎn)碼的自由性——有了視覺稿的原始信息結(jié)構(gòu),你可以從中解析出你需要的數(shù)據(jù)節(jié)點(diǎn),并且修改為需要的目的內(nèi)容。
五、未來規(guī)劃
在后續(xù)的開發(fā)規(guī)劃上,我們側(cè)重于完善流程中的細(xì)節(jié),以及通過我們官方的示例,增強(qiáng) D2C 自動(dòng)代碼內(nèi)容的實(shí)用性,繼續(xù)推出更多語言框架,以及適配更多應(yīng)用平臺(tái),例如小程序等等。
除了平臺(tái)細(xì)節(jié)的完善,在這里主要提出未來的兩個(gè)方向上的規(guī)劃:
5.1 人工智能:與 copilot 結(jié)合的未來
目前的 D2C 方案,存在一個(gè)很明顯的劣勢,那就是無法處理復(fù)雜的邏輯反饋。我們提供的自定義生成器功能雖然可以高度定制化生成的組件,但是開發(fā)使用的內(nèi)容依然沒有相關(guān)的邏輯代碼內(nèi)容。
人工智能的出現(xiàn)可以彌補(bǔ)這一缺憾。目前人工智能還未推出完善的編寫代碼功能,但能夠根據(jù)輸入的自然語言描述或者是環(huán)境來推斷開發(fā)需要使用的代碼片段。copilot 可以輔助開發(fā)人員在開發(fā)過程中自動(dòng)生成一些復(fù)雜的代碼,減少開發(fā)人員的負(fù)擔(dān),提高效率與質(zhì)量。
5.2 深度定制化:一鍵換膚,Design Tokens + custom DSL
Design Tokens 是一種用于描述設(shè)計(jì)系統(tǒng)中的基本視覺和品牌屬性的集合。這些屬性包括顏色、字體、間距、邊角半徑等。通過設(shè)計(jì)標(biāo)記,我們可以將視覺屬性抽象出來,從而實(shí)現(xiàn)統(tǒng)一的設(shè)計(jì)語言。
實(shí)際上目前平臺(tái)已經(jīng)支持了 tokens 的抽象抽取,與對(duì)應(yīng)的主題映射表。除了一些設(shè)計(jì)元素上的調(diào)整,我們也可以在不同環(huán)境下使用不同的組件來進(jìn)行兼容展示,例如在 React Native 中,通過修改 mapping 得到需要的交互組件。
這種深度定制化的方案,不僅可以為用戶提供更好的體驗(yàn),同時(shí)可以大大提高開發(fā)效率。
六、結(jié)語
攜程機(jī)票開放了視覺稿生成代碼流程中的生成器入口,通過讓業(yè)務(wù)研發(fā)參與生成器的發(fā)布與更新,抽象出更多適合業(yè)務(wù)場景的組件/數(shù)據(jù)結(jié)構(gòu)。
同時(shí),機(jī)票在三個(gè)維度上進(jìn)行了生成器落地示例,多次驗(yàn)證了該方案的可行性與實(shí)用性。在提高項(xiàng)目生產(chǎn)效率與設(shè)計(jì)稿還原質(zhì)量的同時(shí),確保了代碼的一致性與可維護(hù)性。
視覺稿自動(dòng)生成代碼,可以極大地提高團(tuán)隊(duì)的效率,減少人為錯(cuò)誤和重復(fù)勞動(dòng),從而更加專注于創(chuàng)意和創(chuàng)新。我們相信,在未來的發(fā)展中將會(huì)為我們帶來更加高效和便捷的工作體驗(yàn)。