主頁 > 資料庫 > 從0到1設計通用資料大屏搭建平臺

從0到1設計通用資料大屏搭建平臺

2022-10-18 07:54:39 資料庫

?作者:vivo 互聯網大資料團隊- Wang Lei

一、前言

一直以來,許多產品平臺都在嘗試通過可視化搭建的手段來降低 GUI 應用的研發門檻,提高生產效率,隨著我們業務的發展,資料建設的完善,用戶對于資料可視化的訴求也日益增多,而資料大屏是資料可視化的其中一種展示方式,它作為大資料展示媒介的一種,被廣泛運用于各種會展、公司展廳、發布會等,

相比于傳統手工定制的圖表與資料儀表盤,通用大屏搭建平臺的出現,可以解決定制開發, 資料分散帶來的應用開發、資料維護成本高等問題,通過資料采集、清洗、分析到直觀實時的資料可視化展現,能夠多方位、多角度、全景展現各項指標,實時監控,動態一目了然,

本文將通過敏捷BI平臺的通用大屏搭建能力的實作方案,來講解一下通用可視化搭建平臺整體的設計思路,

二、快速了解可視化大屏

2.1 什么是資料可視化

從技術層面上來講,最直觀的就是前端可視化框架:Echart、Antv、Chart.js、D3.js、Vega 等,這些庫都能幫我們快速把資料轉換成各種形式的可視化圖表,

圖片

業務層面來講, 其最主要的意義就在于通過資料 -> 圖表組合 -> 可視化頁面這一業務流程,來幫助用戶更加直觀整體的分析不同行業和場景的趨勢和規律,

圖片

所以在資料領域里,對于復雜難懂且體量龐大的資料而言,圖表的資訊量要大得多,這也是資料可視化最根本的目的,

2.2 可視化大屏都有哪些部分

主要由 可視化組件 + 事件互動 + 坐標關系 組成,效果如下圖所示:

圖片

2.3 可視化大屏和常見的BI報表看板的區別

經常會有同學會問到,可視化大屏和BI報表看板的區別是什么?

這里簡單的做一下介紹:

  1. 大屏和報表看板都只是BI的其中一種展現方式,大屏更多是通過不同尺寸的顯示幕硬體上進行投屏,而報表看板更多是在電腦端進行展示使用,

  2. 大屏更加注重資料動態變化 ,會有極強的視覺體驗和沖擊力,提供豐富的輪播影片、表格滾動等影片特效,而報表看板更注重互動式資料探索分析,例如上卷下鉆、排序、過濾、圖表切換、條件預警等,

三、設計思路

3.1 技術選型

  • 前端框架:React 全家桶(個人習慣)

  • 可視化框架:Echarts\DataV-React (封裝度高,json結構的配置項易拓展) D3.js(可視化元素粒度小、定制能力強)

  • 拖拽插件:dnd-kit (滿足樹狀結構視圖的跨組件拖拽)

  • 布局插件:React-Grid-Layout(網格自由布局,修改原始碼,支持多個方向的拖拽,自由布局、鎖定縮放比等)

3.2 架構設計

下圖是我們搭建平臺的整體架構設計:

圖片

整個大屏搭建平臺包含四個非常重要的子系統和模塊:

  • 可視化物料中心:是整個平臺最基礎的模塊,我們在開源的圖表庫和自主開發的可視化組件上面定義了一層標準的 DSL 協議,這個協議和接入 畫布編輯器 的協議是對應的,目前已經有 40+ 相關組件,組件數量還在不斷增長,

  • 畫布編輯器:是搭建平臺的核心與難點,支持頁面布局配置、頁面互動配置和組件資料配置等功能,另外還支持代碼片段的配置,也可以稱得上是一個低代碼平臺,

  • 資料中心:是提供專門用于連接不同資料源的服務,例如直連 MySQL、ClickHouse、Elasticsearch、Presto 等,提供了大屏搭建所需要的原始資料,

  • 管理中心:是大屏的后臺運營管理模塊,包含了大屏模版管理、大屏發布下線、訪問權限等管理功能,

3.3 搭建流程

通過上面提到的大屏組成元素,我們可以分析總結出大屏搭建主流程如下圖所示:

圖片

四、核心功能實作

接下來我們會逐一對平臺幾個核心功能實作進行決議:

1、大屏自適應布局

背景:解決頁面錯亂問題,實作多種解析度的大屏適配:

思考:首先我們想到的是移動端適配主流的 vh、vw、rem組合的方式以及 font.js+rem 等兩種方案,第一種方案主要是通過媒體查詢來定義父級大小,然后對組件的height、margin、padding等多種css屬性采用rem作為單位,繼承父級設定等單位(1vw),實作自適應適配,第二種方案是參考第三方腳本,通過在main.js中寫代碼計算,使用rem進行繼承,實作適配,

① vh、vw、rem組合

//vw vh單位 w3c的官方解釋 vw:1% of viewport’s width vh:1% of viewport’s height
//例如,設計稿的寬度為1920px,則1vw=19.2px,為了方便計算,我們將html元素的font-size大小設定為100px,也就是5.208vw=100px,
body,html {
     font-size:5.208vw
}

② font.js + rem

//監聽視窗的oversize事件,來動態計算根節點字體大小,再配合rem做適配
(function(doc, win) {
    const docEl = doc.documentElement
    const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize'
    const recalc = function() {
      let clientWidth = docEl.clientWidth
      if (!clientWidth) return
      docEl.style.fontSize = 100 * (clientWidth / 1920) + 'px'
    }
    if (!doc.addEventListener) return
    win.addEventListener(resizeEvt, recalc, false)
    doc.addEventListener('DOMContentLoaded', recalc, false)
})(document, window)

缺陷:當我們大屏里面使用到的第三方插件,它的樣式使用的是px為單位時,例如 line-height 的設定為20px,此時就不能適應行高,就會出現重疊等錯亂問題,或者我們利用 postcss-px2rem 插件進行全域替換,但是在使用程序中,需要注意對已經處理過適配的插件,例如 Ant Design,否則引入的antd 控制元件使用會出現樣式錯亂的問題

解決思路:采用了css3 的縮放 transform: scale(X,Y) 屬性,主要是通過監聽瀏覽器視窗的 onresize 事件,當視窗大小發生變化時,我們只需要根據大屏容器的實際寬高,去計算對應的放大縮小的比例,就可以實作布局的自適應了,我們也提供了不同的布局適應效果,例如等高縮放、等寬縮放、全屏鋪滿等,不同的縮放方式,決定了我們在計算寬高比例的優先級,因此我們后面在做畫布的縮小功能,也可以直接使用這種方案來實作,

// 基于設定的設計稿尺寸 換算對應的寬高比
useEffect(() => {
    const wR = boxSize.width / viewWidth;
    const hR = boxSize.height / viewHeight;
 
    setBgScaleRatio(wR);
    setBgHeightScaleRatio(hR);
}, [boxSize, viewWidth, viewHeight]);
 
//根據等寬、等高、全屏等不同的縮放比例 計算scale值
const getScale = (proportion, x, y) => {
    if (proportion === 'radioWidth') {
        return `scaleX(${x})`
    }
    if (proportion === 'radioHeight') {
        return `scaleY(${y})`
    }
    return `scale(${x}, ${y})`
}

2、大屏組件通用開發流程設計

背景:隨著可視化組件的增多、新增組件流程繁瑣冗長,為了避免重復的造輪子以及后續引入第三方組件,需要制定一套通用的組件開發流程:

設計思路:組件 = component 組件主體 + schema 組件配置協議層 + 組件定義層(型別、從屬關系、初始化寬高等)

① component 組件主體:

  • 可視化框架選型:行業主流可視化庫有 Echart、Antv、Chart.js、D3.js、Vega、DataV-React 基于可視化的通用性和定制性的需求,我們選擇了 Echart、DataV-React 作為基礎組件的開發框架,面對定制性要求更高的自定義組件,我們選擇了可視化粒度更小的 D3.js,

  • 封裝通用 Echarts 組件(初始化、事件注冊、實體注銷等):

// initialization echarts
const renderNewEcharts = () => {
    // 1. new echarts instance
    const echartObj = updateEChartsOption();
    // 2. bind events
    bindEvents(echartObj, onEvents || {});
    // 3. on chart ready
    if (typeof onChartReady === 'function') onChartReady(echartObj);
    // 4. on resize
    echartObj.resize();
};
 
// bind the events
const bindEvents = (instance, events) => {
    const _bindEvent = (eventName, func) => {
       instance.on(eventName, (param) => {
           func(param, instance);
       });
    };
 
    // loop and bind
    for (const eventName in events) {
        if (Object.prototype.hasOwnProperty.call(events, eventName)) {
            _bindEvent(eventName, events[eventName]);
        }
    }
};
 
// dispose echarts and clear size-sensor
const dispose = () => {
    if ($chartEl.current) {
       clear($chartEl.current);
       // dispose echarts instance
       (echartsLib || echarts).dispose($chartEl.current);
    }
};
  • 封裝通用 DataV 組件(DataV-React、自定義等組件入口,統一負責配置、資料收集、監聽resize)

const DataV: React.FC<DataVProps> = (props) => {
    const { config } = props;
    const [renderCounter, setRenderCounter] = useState(0);
    const $dataVWarpEl = useRef(null);
    const $componentEl = useRef(null);
 
    useEffect(() => {
        // 系結容器size監聽
        const resizefunc = debounce(() => {
            $componentEl.resize();
        }, 500)
       // fixme
       addResizeListener($dataVWarpEl.current, resizefunc);
       return () => {
           // 清除訂閱
           removeResizeListener($dataVWarpEl.current, resizefunc);
       };
    }, []);
 
    return (
        <DataVWarp ref={$dataVWarpEl}>
            <CompRender config={config} ref={$componentEl} />
        </DataVWarp>
    );
};

② schema 組件配置協議層 + 組件定義層(型別、從屬關系、初始化寬高等)

我們自定義了一套 schema 組件的DSL,結構協議層,通過DSL約定了組件的配置協議,包括組件的可編輯屬性、編輯型別、初始值等,之所以定義一致的協議層,主要是方便后期的組件擴展,配置后移,

圖片

  • JSON Schema設計:

{
    headerGroupName: '公共配置',                         //配置所屬型別
    headerGroupKey: 'widget',                           //配置所屬型別key值 相同的key值都歸屬一類
    name: '標題名稱',                                    //屬性名稱
    valueType: ['string'],                              //屬性值型別
    optionLabels: [],                                   //服務下拉串列、多選框等控制元件的標簽名
    optionValues: [],                                   //服務下拉串列、多選框等控制元件的標簽值
    tip: false,                                         //配置項的 Tooltip 注解
    ui: ['input'],                                      //使用的控制元件型別
    class: false,                                       //控制元件類名,定制控制元件樣式
    css: { width: '50%'},                               //修改控制元件樣式
    dependencies: ['widget,title.show,true'],           //屬性之間的聯動,規則['配置所屬型別, 屬性key, 屬性值']
    depContext: DepCommonShowState,                     //屬性之間的校驗回呼方法
    compShow: ['line'],                                 //哪些組件可配置
    dataV: { key: 'title.text', value: '' },            //配置的key值和默認value值
},
  • 表單DSL設計:

圖片

收益:以上是我們定制的DSL結構協議層,用戶只需要填寫Excel表格,就可以實作動態表單的創建,實作組件配置項分類、配置復用、配置項之間聯動、屬性注釋等功能,目前屬性配置器已經支持了常用的15種的配置UI控制元件,通過定制的DSL結構協議層,可以快速完成組件的配置界面初始化,為后續規劃的組件物料中心做準備,

3、拖拽器實作

背景:React-Grid-Layout 拖拽插件不支持自由布局和組件不同緯度拖拽:

解決方案:通過分析原始碼,對不同緯度的拖拽事件以及拖拽目標碰撞事件進行了重寫,并且也拓展了鎖定寬高比、旋轉透明度等功能,

原始碼分析:

圖片

resize伸縮特性增強(優化),拖拽的同時,除了修改容器寬高外,也動態調整了組件的坐標位置,

// CSS Transforms support (default)
if (useCSSTransforms) {
    if (activeResize) {
        const { width, height, handle } = activeResize;
        const clonePos = { ...pos };
        if (["w", "nw", "sw"].includes(handle)) {
            clonePos.left -= clonePos.width - width;
        }
        if (["n", "nw", "ne"].includes(handle)) {
            clonePos.top -= clonePos.height - height;
        }
        style = setTransform(clonePos, this.props.angle);
    } else {
        style = setTransform(pos, this.props.angle);
    }
}

堆疊顯示,自由布局(優化),通過控制布局是否壓縮,動態調整拖拽目標的層級zIndex來實作多圖層組件操作互動和自由定位,

// 每次拖拽時zIndex要在當前最大zIndex基礎上 + 1,并回傳給組件使用
const getAfterMaxZIndex = useCallback(i => {
    if (i === curDragItemI) {
        return;
    }
    setCurDragItemI(i);
    setMaxZIndex(maxZIndex => maxZIndex + 1);
    return maxZIndex;
}, []);

改造后效果展示

圖片

4、大屏狀態推送

背景:大屏的后期維護需要有版本發布自更新以及大屏下線等需求,這個時候就需要有一套訊息通知機制,通過命令來控制大屏的運行狀態,

解決方案:基于websocket通信機制,建立長鏈接,實作了心跳及重連機制,實時對上線發布后的大屏進行更新或下線管理,

圖片

五、效果預覽

圖片

六、總結

本文通過可視化頁面搭建、no/low code 平臺、Schema 動態表單等技術思想來分析講解了如何去設計開發一個通用的資料大屏搭建平臺,

當前的設計方案基本滿足了資料大屏的核心能力搭建需求,如果想實作更富有展現力, 滿足更多場景的大屏搭建平臺, 我們還需要進一步提高平臺的擴展性和完善整體的物料生態, 具體規劃如下:

  • 豐富和拓展大屏組件&配置能力,覆寫不同行業的可視化場景,

  • 可視化物料平臺的搭建,沉淀優秀的可視化組件、大屏模版素材,

  • 3D以及動效渲染引擎開發實作,

? 分享 vivo 互聯網技術干貨與沙龍活動,推薦最新行業動態與熱門會議,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/516451.html

標籤:大數據

上一篇:使用表單驗證器ZOD的discriminatedUnion()函式來區分3種表單

下一篇:華為云GaussDB資料庫榮獲國際CC EAL4+級別認證

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more