最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

一份配置輕松搞定表單渲染,配置式表單渲染器在袋鼠云的實(shí)現(xiàn)思路與實(shí)踐

2023-06-07 14:46 作者:袋鼠云  | 我要投稿

前段時(shí)間,袋鼠云離線開(kāi)發(fā)產(chǎn)品接到改造數(shù)據(jù)同步表單的需求。

一方面,數(shù)據(jù)同步模塊的代碼可讀性和可維護(hù)性較差,導(dǎo)致在數(shù)據(jù)同步模塊開(kāi)發(fā)新功能和定位問(wèn)題的效率很低。另一方面,整體規(guī)劃上,希望在對(duì)接新的數(shù)據(jù)源時(shí),可以不再關(guān)心表單渲染相關(guān)問(wèn)題,從數(shù)據(jù)源中心新建數(shù)據(jù)源一直到數(shù)據(jù)源在數(shù)據(jù)同步模塊的應(yīng)用,全鏈路的表單都可以通過(guò)配置化的方式解決。

本文就將以此為例,拋磚引玉,為大家詳細(xì)介紹配置式表單渲染器實(shí)現(xiàn)的實(shí)踐之路。

數(shù)據(jù)同步表單背景

數(shù)據(jù)同步模塊整體上分為四個(gè)部分,數(shù)據(jù)來(lái)源表單、同步目標(biāo)表單、字段映射組件和通道控制表單。

其中前三個(gè)部分對(duì)應(yīng)的代碼非?;靵y,代碼量也很大,單個(gè)組件代碼 5000+ 行,這里著重說(shuō)一下數(shù)據(jù)來(lái)源表單和同步目標(biāo)表單。

數(shù)據(jù)來(lái)源和同步目標(biāo)表單的主要功能是收集數(shù)據(jù)源對(duì)應(yīng)的配置信息,并且根據(jù)數(shù)據(jù)源類型的不同,對(duì)應(yīng)需要渲染的表單項(xiàng)也不同。

目前袋鼠云離線開(kāi)發(fā)產(chǎn)品 BatchWorks 數(shù)據(jù)同步功能的數(shù)據(jù)源多達(dá)50+種。在長(zhǎng)時(shí)間的迭代過(guò)程中,日積月累出現(xiàn)了很多強(qiáng)行復(fù)用的代碼,這些強(qiáng)行復(fù)用的代碼內(nèi)部又包含著大量的 if else 邏輯。另外,數(shù)據(jù)同步模塊的表單內(nèi)部有很多聯(lián)動(dòng)關(guān)系,比如:

· 某個(gè)表單項(xiàng)的值變化時(shí),需要發(fā)起接口請(qǐng)求,請(qǐng)求的返回值被用作另一個(gè)表單項(xiàng)下拉框的數(shù)據(jù)

· 某個(gè)表單項(xiàng)的值變化時(shí),需要去清空/重置其他一些表單項(xiàng)的值

· 某個(gè)表單項(xiàng)的值變化時(shí),需要顯示/隱藏某個(gè)表單項(xiàng)

· 某個(gè)表單項(xiàng)的值變化時(shí),某個(gè)表單項(xiàng)的 label 文案、表單項(xiàng)組件(比如從 select 變成 input ) 等隨之發(fā)生變化

這些表單項(xiàng)的聯(lián)動(dòng)處理邏輯在代碼中混雜交叉,另外還要加上表單回顯的特殊邏輯處理,表單的值收集到 redux 的特殊邏輯處理等。

需求分析

基于上述需求背景,表單渲染器的核心功能是輸入一份配置,輸出表單 UI 組件。

基于上述數(shù)據(jù)同步表單背景,我們希望渲染器可以盡可能吸收掉表單內(nèi)部的復(fù)雜度,也就是說(shuō)在表單的配置中要能夠描述上述的聯(lián)動(dòng)關(guān)系,那么可以大概得出表單的配置需要描述:

· 表單項(xiàng)的基礎(chǔ)信息,比如字段名、label、表單組件、校驗(yàn)信息等

· 表單項(xiàng)數(shù)據(jù)之間的聯(lián)動(dòng)

· 表單項(xiàng) UI 的聯(lián)動(dòng)(控制顯示/隱藏)

· 表單項(xiàng)的值變化時(shí)需要觸發(fā)的副作用(比如調(diào)用接口)

表單基礎(chǔ)信息描述

這里配置格式使用 JSON 格式,用一個(gè)數(shù)組描述所有的表單項(xiàng)信息,UI 上表單項(xiàng)的渲染順序即配置數(shù)組中表單項(xiàng)配置的順序,表單組件使用 Ant Design Form。

對(duì)于表單項(xiàng)基礎(chǔ)信息的描述配置,大多可以直接搬用 Ant Design Form Item 的 props,比如 label、rules、Tooltip 等屬性,這里不多贅述。

比較特殊的是,需要在配置里描述表單項(xiàng)描述的 UI 組件,比如 Select、Input,那么這里使用 widget 字段去描述。另外,組件的描述除了組件名稱,還需要描述組件的 props, 所以還需要一個(gè) widgetProps 字段去描述組件的屬性,比如 placeholder、disabled 等。

那么一個(gè)用于選擇數(shù)據(jù)源的表單項(xiàng)應(yīng)該這樣描述:

當(dāng)然可能會(huì)存在某些表單項(xiàng)的 UI 組件有自定義的情況,比如可編輯表格,代碼編輯器等。這個(gè)時(shí)候就需要開(kāi)發(fā)自定義表單組件了,然后把這些組件注入到 FormRenderer 中,偽代碼如下所示:

那么目前的結(jié)構(gòu)如圖所示:

這份配置寫(xiě)到這里的時(shí)候,問(wèn)題出現(xiàn)了:

· 無(wú)法在配置中描述 onChange、onSelect 等事件回調(diào)函數(shù)

· 相比于 jsx 強(qiáng)大的表達(dá)能力,JSON 中只能表達(dá)基本的數(shù)據(jù)結(jié)構(gòu),而沒(méi)辦法直接表達(dá)邏輯

· Select 下拉框的數(shù)據(jù)可能來(lái)源于接口,這種情況在業(yè)務(wù)中相當(dāng)常見(jiàn),這里也沒(méi)辦法表達(dá)

· 不能自定義表單校驗(yàn)器,無(wú)法支持復(fù)雜的 Tootip 提示,比如帶有 a 標(biāo)簽的 Tootip

上述問(wèn)題產(chǎn)生的根本原因,實(shí)際上是 JSON 與 jsx 之間表達(dá)能力的差距。但是從另一個(gè)角度來(lái)講,正因?yàn)?JSON 的表達(dá)能力和靈活性不如 jsx,所以在用來(lái)描述 UI 時(shí),JSON 更不容易導(dǎo)致混亂。

我們先思考如何表達(dá) Select 下拉框的數(shù)據(jù)來(lái)源于接口,這里可以拆解為兩個(gè)部分,數(shù)據(jù)獲取和取得接口的返回值并在配置項(xiàng)中表達(dá)。

數(shù)據(jù)獲取

實(shí)際上,Select 下拉框中的數(shù)據(jù)也并不一定來(lái)源于接口,也可能是來(lái)源于其他業(yè)務(wù)數(shù)據(jù),所以在配置項(xiàng)描述數(shù)據(jù)獲取時(shí),不應(yīng)該關(guān)心數(shù)據(jù)的來(lái)源。

很顯然,數(shù)據(jù)獲取邏輯需要用 js 描述 ,這里我們抽象出一個(gè) Service 的概念,用于描述/聲明數(shù)據(jù)獲取邏輯,Service 的聲明使用 js,在 JSON 配置中,只需要去描述 Service 的調(diào)用邏輯即可。對(duì)于 JSON 配置來(lái)說(shuō), Service 調(diào)用需要三個(gè)要素:

· Service 的標(biāo)識(shí)/名稱,表示哪一個(gè) Service 被觸發(fā)

· Service 的觸發(fā)時(shí)機(jī)

· Service 返回的數(shù)據(jù)如何存儲(chǔ)

● Service 的觸發(fā)時(shí)機(jī)

Service 的觸發(fā)一般來(lái)說(shuō)是由于用戶的交互引起的,當(dāng)然也存在在表單項(xiàng)組件掛載時(shí)就需要觸發(fā)的情況,那么調(diào)用時(shí)機(jī)大概就是以下幾種:

· onMount

· onChange

· onSearch

· onFocus

· onBlur

● Service 返回的數(shù)據(jù)如何存儲(chǔ)

這里 Service 返回的數(shù)據(jù)存儲(chǔ)需要能被 UI 獲取到,那么需要將返回的數(shù)據(jù)都維護(hù)在 FormRender 內(nèi)部,這里將存儲(chǔ)數(shù)據(jù)的地方命名為 extraData。那么我們描述 Service 返回的數(shù)據(jù)的存儲(chǔ),可以使用一個(gè) fieldInExtraData 的字段,描述當(dāng)前 Service 返回的數(shù)據(jù)被存儲(chǔ)在 extraData 的那個(gè)字段中,取值時(shí):extraData[fieldInExtraData]。

那么在表單項(xiàng)配置中描述 Service,如下所示:

● Service 的聲明

對(duì)于 Service 本身來(lái)說(shuō),要做的事情就是獲取并處理數(shù)據(jù)然后返回,當(dāng)然 Service 本身可能需要接受一些參數(shù),比如當(dāng)前 Form 收集到的數(shù)據(jù)、Service 是被哪個(gè)字段觸發(fā)的、觸發(fā)時(shí)機(jī)是什么等等,那么 Service 的格式如下所示:

由于 Service 可能是異步的,所以這里 Service 都返回一個(gè) Promise,然后將所有的 Service 都注入到 FormRenderer 中,F(xiàn)ormRenderer 根據(jù)表單項(xiàng)配置中聲明的調(diào)用時(shí)機(jī)去調(diào)用 Service,整個(gè)數(shù)據(jù)獲取的鏈路就完成了。

獲取 Service 返回值并在配置項(xiàng)中表達(dá)

上文中提到,Service 的返回的數(shù)據(jù)都被存儲(chǔ)在 FormRenderer 內(nèi)部的 extraData 中,一般情況下如果使用 jsx 當(dāng)然能很容易地取到對(duì)應(yīng)的值,但是在 JSON 中,是沒(méi)辦法表達(dá)的。但是我們可以借鑒 jsx 的插值表達(dá)式和 vue 的插值表達(dá)式。

在 jsx 中,如果在一對(duì)標(biāo)簽內(nèi)部寫(xiě)了一串字符串,對(duì)應(yīng)的會(huì)有兩種解析策略,第一種是直接識(shí)別為字符串,第二種如果識(shí)別到花括號(hào),則將其視為 js 表達(dá)式。 同理,在 JSON 配置中也可以使用這種方式去取值。

● 函數(shù)表達(dá)式

上例中,使用一對(duì)花括號(hào)聲明函數(shù)表達(dá)式,表面上是借鑒了 jsx 的插值表達(dá)式,但是其實(shí)兩者有很大的區(qū)別。jsx 的插值表達(dá)式是在編譯階段就轉(zhuǎn)化成了 js 表達(dá)式。而在 JSON 中的這種自定義的函數(shù)表達(dá)式要在運(yùn)行時(shí)轉(zhuǎn)換,上述的函數(shù)表達(dá)式只能被轉(zhuǎn)換為函數(shù)執(zhí)行。即:

出于安全問(wèn)題考慮,表達(dá)式還需要被放在一個(gè)類似沙箱的環(huán)境中執(zhí)行,避免表達(dá)式內(nèi)部修改全局環(huán)境變量。創(chuàng)建簡(jiǎn)易沙箱使用 proxy + with + symbol.unscopables 的方式,這里不展開(kāi)講解了。最終函數(shù)表達(dá)式的應(yīng)用大概是如下形式:

到目前為止,已經(jīng)有了兩個(gè)新概念:Service 和 函數(shù)表達(dá)式,回到上文中提到的問(wèn)題,我們已經(jīng)解決了 Select 下拉框來(lái)源于接口的問(wèn)題,那么還剩下如下問(wèn)題:

· JSON 中只能表達(dá)基本的數(shù)據(jù)結(jié)構(gòu),而沒(méi)辦法直接表達(dá)邏輯

· 無(wú)法在配置中描述 onChange、onSelect 等事件回調(diào)函數(shù),也不能自定義表單校驗(yàn)器

· 不能自定義表單校驗(yàn)器,無(wú)法支持復(fù)雜的 Tootip 提示,比如帶有 a 標(biāo)簽的 Tootip

json 中沒(méi)辦法表達(dá)邏輯的問(wèn)題,其實(shí)已經(jīng)可以通過(guò)函數(shù)表達(dá)式來(lái)解決了。函數(shù)表達(dá)式內(nèi)部支持寫(xiě)任意的 js 表達(dá)式,另外,在函數(shù)表達(dá)式中也可以支持訪問(wèn) form 表單數(shù)據(jù),有了數(shù)據(jù)支持和邏輯表達(dá)能力支持,絕大多數(shù)情況下的已經(jīng)能夠滿足 UI 渲染中的邏輯表達(dá)了。

而描述 onChange、onSelect 等事件回調(diào)函數(shù)可以通過(guò)配置 Service 來(lái)解決。

自定義表達(dá)校驗(yàn)器可以通過(guò)函數(shù)表達(dá)式的變種來(lái)解決,可以向 FormRenderer 中注入 form 校驗(yàn)器的集合,然后通過(guò) {{ ruleMap.xxx }} 來(lái)指定表單項(xiàng)的某一條校驗(yàn)規(guī)則的校驗(yàn)器。

Tooltip 提示也是如此。目前結(jié)構(gòu)如下圖所示:

表單數(shù)據(jù)聯(lián)動(dòng)

表單數(shù)據(jù)聯(lián)動(dòng)實(shí)際上就是當(dāng)表單中某個(gè)表單項(xiàng)值變化時(shí),去重置其他表單項(xiàng)的值,那么要在配置中描述這種聯(lián)動(dòng)關(guān)系有兩種方式:

· 當(dāng)前字段受哪些字段的影響

· 當(dāng)前字段的值變化會(huì)影響到哪些字段

一般情況下,在代碼中描述這種邏輯時(shí)都是采用第二種方式,也就是監(jiān)聽(tīng)某個(gè)字段的值的變化,然后在回調(diào)函數(shù)中去做對(duì)應(yīng)的數(shù)據(jù)聯(lián)動(dòng)操作。

但是在配置 JSON 時(shí),第二種方式就變得不那么友好了,那會(huì)讓字段配置之間產(chǎn)生更多的耦合。更加友好的方式是在某個(gè)字段內(nèi)表達(dá)本字段受到哪些字段的影響,這樣做的另一個(gè)好處是,當(dāng)開(kāi)發(fā)者填寫(xiě)或者修改某一個(gè)字段的配置時(shí),可以更加聚焦,不用關(guān)心其他字段的配置。

這里用 dependecies 字段來(lái)表達(dá)當(dāng)前字段的值受哪些字段的影響。舉個(gè)例子,表單中有數(shù)據(jù)源、schema、table 三個(gè)字段,數(shù)據(jù)源變化時(shí),schema 的值應(yīng)該被重置;schema 變化時(shí),table 的值會(huì)被重置。那么在 json 中應(yīng)該這樣描述:

對(duì)應(yīng)的依賴關(guān)系圖如下:

這里新的問(wèn)題產(chǎn)生了,當(dāng)數(shù)據(jù)源變化時(shí),table 的值是否要被重置?一般情況下是肯定的。那么實(shí)際上它們的依賴關(guān)系是這樣的:

這里有兩種方式來(lái)解決這種隱式的依賴關(guān)系:

· 開(kāi)發(fā)者在配置時(shí)顯式得聲明所有的依賴關(guān)系

· 渲染器內(nèi)部解析依賴關(guān)系時(shí),將這種隱式的依賴關(guān)系也解析出來(lái)

那么如何選擇使用哪一種方式呢?

如果采用第一種方式,優(yōu)點(diǎn)是渲染器不再需要關(guān)心這種隱式的依賴關(guān)系了,但是在配置時(shí)的心智負(fù)擔(dān)可能比較大,很容易出現(xiàn)漏配依賴關(guān)系的情況。

如果采用第二種方式,優(yōu)點(diǎn)是配置起來(lái)心智負(fù)擔(dān)低,但是也有可能出現(xiàn) table 確實(shí)不依賴 sourceId 的情況,也就是間接依賴不生效的情況。

結(jié)合實(shí)際業(yè)務(wù)看,目前的業(yè)務(wù)中,所有的字段之間間接依賴其實(shí)都是隱式依賴,也就是需要生效的,這里采用第二種方式。前文中也提到了,期望是 FormRenderer 可以盡可能的吸收掉表單內(nèi)部的復(fù)雜度。

特殊的表單數(shù)據(jù)聯(lián)動(dòng)

在實(shí)際業(yè)務(wù)中還存在著一些比較特殊的表單數(shù)據(jù)聯(lián)動(dòng),比如:

· 選擇數(shù)據(jù)源時(shí),除了需要收集數(shù)據(jù)源的 id,還需要收集數(shù)據(jù)源類型

· 選擇數(shù)據(jù)源后,需要將數(shù)據(jù)源的其他信息展示為表單項(xiàng),比如下圖中的表單

對(duì)于這種業(yè)務(wù)場(chǎng)景,我們可以理解為某個(gè)表單項(xiàng)的值是由其他表單項(xiàng)的值派生出來(lái)的,那么就需要去描述這種派生邏輯。當(dāng)然,這種派生邏輯可以在業(yè)務(wù)代碼中描述,只需要在數(shù)據(jù)源變化時(shí),手動(dòng)的 setFieldValue 就可以了。但是還是上文中提到的期望,F(xiàn)ormRenderer 可以盡可能吸收掉復(fù)雜度。

處理這種情況,需要新增一個(gè)配置項(xiàng)去描述派生邏輯,這里配置項(xiàng)定為 valueDerived,這個(gè)配置項(xiàng)的值應(yīng)該為一個(gè)取值表達(dá)式,那么以第一個(gè)例子為例,配置應(yīng)該如下所示:

FormRenderer 內(nèi)部根據(jù)配置的 valueDerived 去自動(dòng)更新表單中對(duì)應(yīng)字段的值。

表單 UI 聯(lián)動(dòng)

表單 UI 聯(lián)動(dòng)可以分為以下兩個(gè)部分。

表單項(xiàng) UI 文案、樣式等根據(jù)數(shù)據(jù)聯(lián)動(dòng)

表單項(xiàng)的 UI 聯(lián)動(dòng)在 React 和 JSX 中,都能很輕易、很自然的發(fā)生。但是想要在 JSON 中描述,由于JSON本身不具備表達(dá)邏輯的能力,還是要借助函數(shù)表達(dá)式。只需要支持對(duì)應(yīng)的配置項(xiàng)可以使用函數(shù)表達(dá)式就能完成表單項(xiàng)的聯(lián)動(dòng)。舉個(gè)例子:

那么它們實(shí)際渲染時(shí)等同于以下偽代碼:

這樣就能做到表單項(xiàng)的文案樣式等根據(jù)數(shù)據(jù)變化自然的聯(lián)動(dòng)。

表單項(xiàng)的顯示與隱藏

表單項(xiàng)的隱藏也能拆分為以下兩種情況:

· 隱藏但不銷毀,表單項(xiàng)的值仍然會(huì)被收集和保留

· 銷毀,不再保留/收集表單項(xiàng)的值

隱藏但不銷毀的情況,antd form 本身就有 hidden 配置支持,那么這里只需要支持 hidden 配置使用函數(shù)表達(dá)式就可以了。

對(duì)于表單項(xiàng)的銷毀,就需要新增一個(gè)字段了,這里命名為 destory,同樣通過(guò)支持使用函數(shù)表達(dá)式完成聯(lián)動(dòng),但是這里需要考慮一些其他情況。比如從銷毀狀態(tài)變成顯示狀態(tài)時(shí),需要去觸發(fā) mount service 等。

思路小結(jié)

回顧上文需求分析中所說(shuō)的需要實(shí)現(xiàn)的功能:

· 表單項(xiàng)的基礎(chǔ)信息,比如字段名、label、表單組件、校驗(yàn)信息等

· 表單項(xiàng)數(shù)據(jù)之間的聯(lián)動(dòng)

· 表單項(xiàng) UI 的聯(lián)動(dòng)(控制顯示/隱藏)

· 表單項(xiàng)的值變化時(shí)需要觸發(fā)的副作用(比如調(diào)用接口)

目前在思路上,上述功能都是可以實(shí)現(xiàn)的。除了基礎(chǔ)的渲染功能以外,F(xiàn)ormRender 需要額外實(shí)現(xiàn)的功能有:

· 內(nèi)置一個(gè) extraData 存儲(chǔ) Service 返回的數(shù)據(jù)

· 支持根據(jù)配置在正確的時(shí)機(jī)觸發(fā) Service

· 支持函數(shù)表達(dá)式

· 支持根據(jù)配置在內(nèi)部處理數(shù)據(jù)聯(lián)動(dòng)邏輯

大體實(shí)現(xiàn)

整體上,導(dǎo)出一個(gè) FormRenderer 組件,上文中提到的 json config、Service 聲明、自定義的表單校驗(yàn)器,自定義表單項(xiàng)組件等,都通過(guò) FormRenderer 的 props 傳入。

內(nèi)置 extraData

由于 extraData 內(nèi)部存儲(chǔ)的數(shù)據(jù)變化可能導(dǎo)致視圖更新,那么只能使用 React.Context 或者 state,事實(shí)上即使使用 Context 也還是需要聲明 state 來(lái)觸發(fā)視圖更新,但是 Conetxt 在傳遞數(shù)據(jù)時(shí)有著獨(dú)特的優(yōu)勢(shì),這里直接使用 Context 存儲(chǔ)數(shù)據(jù)。

在正確的時(shí)機(jī)觸發(fā) Service

在 JSON 配置中 Service 相關(guān)描述如下所示:

triggerServices 已經(jīng)很清楚直觀的描述了,該字段在什么時(shí)機(jī)應(yīng)該調(diào)用哪個(gè) service,在代碼實(shí)現(xiàn)上,為了這部分觸發(fā)邏輯與視圖渲染分離,采用發(fā)布訂閱模式。大體流程如下圖所示:

這里流程已經(jīng)走通了,但是可以發(fā)現(xiàn),renderer 中仍然需要去處理訂閱的邏輯,Service 觸發(fā)邏輯與視圖渲染邏輯分離的不夠徹底,那么可以繼續(xù)優(yōu)化一下,加入一個(gè)訂閱器去處理這部分邏輯,優(yōu)化后的邏輯如下圖所示:

支持函數(shù)表達(dá)式

上文中提到了,函數(shù)表達(dá)式的實(shí)現(xiàn)是用 new Function,以及處于安全問(wèn)題考慮需要將函數(shù)表達(dá)式放到模擬沙箱環(huán)境中執(zhí)行,執(zhí)行流程如下所示:

實(shí)現(xiàn)代碼如下所示(不包含正則處理):

比如在 label 配置中使用了函數(shù)表達(dá)式:

那么經(jīng)過(guò)轉(zhuǎn)換后,就是等同于以下函數(shù):

具體應(yīng)用如下:

支持根據(jù)配置在內(nèi)部處理數(shù)據(jù)聯(lián)動(dòng)邏輯

與上文中 Service 觸發(fā)邏輯一樣,將這部分聯(lián)動(dòng)的邏輯通過(guò)發(fā)布訂閱與視圖渲染邏輯分離。但是相比于 Service 觸發(fā)邏輯,這里多了分析依賴的步驟。比如,有如下 json 配置:

那么生成的依賴關(guān)系圖就應(yīng)該是:

生成上述依賴關(guān)系后,剩下的流程與觸發(fā)Service 的流程類似,在這里不多做贅述了。

《數(shù)據(jù)治理行業(yè)實(shí)踐白皮書(shū)》下載地址:https://fs80.cn/l134d5?

《數(shù)棧V6.0產(chǎn)品白皮書(shū)》下載地址:https://fs80.cn/cw0iw1

想了解或咨詢更多有關(guān)袋鼠云大數(shù)據(jù)產(chǎn)品、行業(yè)解決方案、客戶案例的朋友,瀏覽袋鼠云官網(wǎng):https://www.dtstack.com/?src=szbzhan

同時(shí),歡迎對(duì)大數(shù)據(jù)開(kāi)源項(xiàng)目有興趣的同學(xué)加入「袋鼠云開(kāi)源框架釘釘技術(shù) qun」,交流最新開(kāi)源技術(shù)信息,qun 號(hào)碼:30537511,項(xiàng)目地址:https://github.com/DTStack


一份配置輕松搞定表單渲染,配置式表單渲染器在袋鼠云的實(shí)現(xiàn)思路與實(shí)踐的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
于田县| 石城县| 陵川县| 浪卡子县| 永年县| 松原市| 抚松县| 商城县| 成武县| 莱阳市| 嘉兴市| 吉林市| 安溪县| 古浪县| 新龙县| 台山市| 右玉县| 行唐县| 广南县| 云霄县| 长岛县| 渝北区| 吉水县| 柳河县| 南部县| 永清县| 繁峙县| 神农架林区| 恭城| 汕头市| 滁州市| 常州市| 苗栗市| 迁安市| 孟津县| 乐安县| 高碑店市| 张家口市| 湟中县| 九台市| 慈利县|