日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

我們一起聊聊審核平臺前端新老倉庫遷移

來源: 責(zé)編: 時間:2024-07-06 07:42:38 975觀看
導(dǎo)讀背景審核平臺接入50+業(yè)務(wù),提供在線審核及離線質(zhì)檢、新人培訓(xùn)等核心能力,同時提供數(shù)據(jù)報表、資源追蹤、知識庫等工具。隨著平臺的飛速發(fā)展,越來越多的新業(yè)務(wù)正在或即將接入審核平臺,日均頁面瀏覽量為百萬級別。如今審核平

背景

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

審核平臺接入50+業(yè)務(wù),提供在線審核及離線質(zhì)檢、新人培訓(xùn)等核心能力,同時提供數(shù)據(jù)報表、資源追蹤、知識庫等工具。隨著平臺的飛速發(fā)展,越來越多的新業(yè)務(wù)正在或即將接入審核平臺,日均頁面瀏覽量為百萬級別。如今審核平臺已是公司內(nèi)容生產(chǎn)鏈路上的關(guān)鍵一環(huán),是保障內(nèi)容安全的重要防線,因此穩(wěn)定性至關(guān)重要。DOM28資訊網(wǎng)——每日最新資訊28at.com

過去一年我們曾對前端項目進行框架升級,考慮風(fēng)險與成本最小化,選擇了漸進式升級,利用微前端實現(xiàn)Vue2和Vue3共存,新接業(yè)務(wù)在Vue3倉庫中開發(fā)。經(jīng)過一年的迭代,Vue3項目趨于穩(wěn)定,沉淀了大部分通用能力。為了降低多倉庫維護心智,同時解決核心模塊的技術(shù)債務(wù),考慮將剩余活躍代碼進行重構(gòu)并遷移至新倉庫。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

面向遷移的重構(gòu) - 整潔架構(gòu)在前端的應(yīng)用

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

案例選擇

DOM28資訊網(wǎng)——每日最新資訊28at.com

參考前端埋點報表,選擇老倉庫中頁面維度訪問量最高的路由,對線上使用情況進行摸排。日常業(yè)務(wù)現(xiàn)狀是點直融合,直播業(yè)務(wù)配置化接入需求較多,因為業(yè)務(wù)形態(tài)的差異,定制需求多,現(xiàn)有配置能力無法滿足,需擴充。開發(fā)現(xiàn)狀是通用配置化代碼改動頻繁,邏輯復(fù)雜,開發(fā)門檻較高,影響范圍大,牽一發(fā)而動全身。因此選擇配置化詳情頁作為優(yōu)先重構(gòu)并遷移的對象。DOM28資訊網(wǎng)——每日最新資訊28at.com

配置化詳情頁采用的是業(yè)務(wù)定制化的低代碼方案,包含schema渲染器和任務(wù)流兩部分。當(dāng)前已沉淀近百份json schema,托管在內(nèi)部其他低代碼平臺上。頁面覆蓋40多個業(yè)務(wù),占據(jù)平臺約20%訪問量和35%獨立訪客。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

如果將頁面看做一個黑盒子,依據(jù)唯一標(biāo)識(路由path和query等)從node服務(wù)、平臺服務(wù)以及外部業(yè)務(wù)方服務(wù)獲取數(shù)據(jù),基于頁面內(nèi)部規(guī)則渲染頁面。審核員瀏覽并進行通過、駁回等操作,提交后將對視頻、彈幕等業(yè)務(wù)資源產(chǎn)生影響。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

schema渲染器基于json schema和接口數(shù)據(jù),在平臺內(nèi)生成路由信息與頁面內(nèi)容,負責(zé)各種模式的頁面分發(fā)、物料分發(fā),并提供敏感詞、快照、洗數(shù)等通用平臺能力。DOM28資訊網(wǎng)——每日最新資訊28at.com

代碼現(xiàn)狀是數(shù)據(jù)獲取、提交操作和頁面復(fù)雜邏輯分散在vue文件和store中,業(yè)務(wù)邏輯和UI框架耦合嚴(yán)重,不利于集成自動化測試和框架升級。待辦、任務(wù)、資源等邊界劃分不清晰,平鋪在“巨石store“中,維護成本極高且代碼改動風(fēng)險大。渲染器和任務(wù)流邏輯不夠內(nèi)聚,耦合嚴(yán)重,無法做到關(guān)注點分離。因此需要尋找一種合適的架構(gòu)進行重構(gòu),減弱業(yè)務(wù)邏輯對UI框架的依賴,增強可測試性。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

整潔架構(gòu)

DOM28資訊網(wǎng)——每日最新資訊28at.com

整潔架構(gòu)由Robert C. Martin在2012年提出,核心思想是將軟件系統(tǒng)拆分為獨立的層次,以實現(xiàn)高內(nèi)聚、低耦合、可測試和可維護。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

一共分為四個層級,環(huán)與環(huán)之間,存在一個依賴關(guān)系原則:源代碼中的依賴關(guān)系,必須只指向同心圓的內(nèi)層,即由低層機制指向高級策略。DOM28資訊網(wǎng)——每日最新資訊28at.com

  • 實體層:包含業(yè)務(wù)領(lǐng)域的核心概念和業(yè)務(wù)邏輯。
  • 用例層:實現(xiàn)特定的業(yè)務(wù)用例,將實體層的業(yè)務(wù)邏輯與具體的應(yīng)用場景結(jié)合起來。
  • 接口適配器層:負責(zé)處理與外部系統(tǒng)的交互比如用戶界面、數(shù)據(jù)庫、web服務(wù)等。將外部系統(tǒng)的請求和數(shù)據(jù)格式轉(zhuǎn)化為用例層和實體層能夠理解和處理的對象。
  • 框架和驅(qū)動層:包含具體的框架和工具,比如web框架、數(shù)據(jù)庫驅(qū)動等。

優(yōu)點是可以在沒有UI、數(shù)據(jù)庫、web服務(wù)器或其他外部基礎(chǔ)設(shè)施的情況下測試業(yè)務(wù)邏輯;降低對UI框架的依賴,比如跨端開發(fā)時,業(yè)務(wù)邏輯可以復(fù)用,只需要做UI層的適配。相應(yīng)的,缺點也很明顯,過于復(fù)雜,數(shù)據(jù)需要經(jīng)過多層處理。學(xué)習(xí)成本較高,容易過度設(shè)計,增加復(fù)雜性,靈活性較低。適用于大型復(fù)雜項目,對于需要長期維護和持續(xù)開發(fā)的項目,清晰層次結(jié)構(gòu)和明確依賴關(guān)系有助于減少代碼腐化,更容易適應(yīng)需求變化。針對我們選擇的模塊,審核前端配置化頁面,比較適合。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

重構(gòu)

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

實體層

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

主要可拆分成待辦、任務(wù)、資源等實體。待辦實體,主要提供待辦的基礎(chǔ)信息、獲取配置等屬性和方法。任務(wù)實體提供任務(wù)的狀態(tài)、任務(wù)耗時、調(diào)度配置、任務(wù)數(shù)據(jù),計時和拉取任務(wù)流程等。資源實體提供資源的詳情數(shù)據(jù)、獲取詳情及數(shù)據(jù)清洗方法等。待辦實體包含了配置詳情頁所需的核心數(shù)據(jù),任務(wù)實體高度抽象了核心任務(wù)流。在新業(yè)務(wù)接入過程中,實體層一般不變動,通過依賴倒置劃分架構(gòu)邊界。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

// entities/todo.jsexport default class Todo {    todoId    businessId    todoConfig    ...    constructor() {}    async getTodoConfig() {        // 獲取配置    }}// entities/task.jsexport default class Task {  dispatch_conf  listData  timeCount  ...  constructor() {}  async getTaskDetail({ getTask, taskFormat, afterGetTask}) {    // 抽象封裝核心任務(wù)流程  }  // 計時邏輯  startTimer() {}  clearTimers() {}}// entities/resource.jsexport default class Resource {    detail    dataReady    constructor() {}    async getResourceDetail({ getResource, resourceFormat, afterGetResource }) {        // 抽象封裝資源模式核心流程    }}

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

用例層

DOM28資訊網(wǎng)——每日最新資訊28at.com

用例層針對洗數(shù)、提交等復(fù)雜場景,通過調(diào)用實體層來實現(xiàn)特定的業(yè)務(wù)邏輯,是適配器層與實體層的中介。例如封裝了基于配置的洗數(shù)中間件,列表模式的單個和批量提交,卡片模式的單個和批量提交,快照上報、自動化質(zhì)檢的復(fù)雜邏輯。用例層包含了系統(tǒng)的復(fù)雜業(yè)務(wù)邏輯,為單元測試提供了便利,可以獨立于UI和外部系統(tǒng)進行測試。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

// usecase/use-single-submitimport { get } from 'lodash-es' // 三方工具庫import { ANNOTATION_SINGLE_OPER_PASS_NAME } from '@/constants' // 常量import { workbenchApi } from '@/api'import { setLogData } from '@/utils/xx' // 工具函數(shù)export function getSingleSubmitParams({ data, state.xxx }) {  //... 邏輯處理  return params}export function submitAuditSingle({ data, afterTaskSubmit }) {  const params = ...  workbenchApi.submit(params).then((res) => {    if(res.code = xxx){      afterTaskSubmit() // 調(diào)用鉤子函數(shù)    }  })}

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

適配器層

DOM28資訊網(wǎng)——每日最新資訊28at.com

適配器層包含store和UI,調(diào)用用例層的代碼,主要負責(zé)將依賴UI、外部服務(wù)、設(shè)備等的數(shù)據(jù)處理為用例層可以使用的“干凈數(shù)據(jù)”。適配器層一般不包括復(fù)雜的業(yè)務(wù)邏輯,因此在框架遷移時僅需關(guān)注基本的框架差異,適合自動化代碼轉(zhuǎn)換。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

// store/todoConfigDetailimport { getTodoInfo } from '@/struct/TodoConfigDetailStruct/usecase/use-todo'import { getTaskInfo, getTask, taskDispatchListFormat } from '@/struct/TodoConfigDetailStruct/usecase/use-task'import { getSingleSubmitParams, submitAuditSingle } from '@/struct/TodoConfigDetailStruct/usecase/use-single-submit'const todo = ref({})async function init({ $route }) {  const query = $route.query  const todoId = +query.todo_id  ...  set(todo, getTodoInfo({ todoId, ... }))  await get(todo).getTodoConfig()  ...}function getTaskDetail() {  get(task).getTaskDetail({    getTask: async ({ noSeize, drillTaskIds }) => await getTask({ todo: get(todo), noSeize, drillTaskIds }),    taskFormat: async (data) => await taskDispatchListFormat({ data, schema: get(todo).schema })    afterGetTask: (res) => { ... }  })}async function submit(data) {  if (single) {    const params = getSingleSubmitParams({ data, todo: get(todo) })    submitAuditSingle({ params, afterTaskSubmit: () => { ... } })  } else {    ...  }}
// Audit.vueconst todoConfigDetailStore = useTodoConfigDetailStore()const { todo, task, multipleSelection } = storeToRefs(todoConfigDetailStore)const { getTaskDetail, submit } = todoConfigDetailStore

DOM28資訊網(wǎng)——每日最新資訊28at.com

新業(yè)務(wù)接入一般對實體層和用例層無改動,僅需適配器層增加相應(yīng)的展示物料,盡可能避免“牽一發(fā)動全身”。新架構(gòu)會有一定的初學(xué)成本,但結(jié)合審核平臺復(fù)雜的項目現(xiàn)狀和持續(xù)接入新業(yè)務(wù)的節(jié)奏,長遠來看對于系統(tǒng)穩(wěn)定性、可測試性有一定幫助,同時降低UI框架依賴性。DOM28資訊網(wǎng)——每日最新資訊28at.com

基于新的架構(gòu),可分層進行自動化測試和自動代碼轉(zhuǎn)換。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

完善用例層的單元測試

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

用例層為純函數(shù),不依賴框架、設(shè)備、三方服務(wù)等。單元測試的技術(shù)棧為jest和vue-test-utils,從審核員的基本工作模式入手,針對任務(wù)領(lǐng)取、數(shù)據(jù)清洗與展示、稿件處理三個環(huán)節(jié)完善測試用例。因為是新老倉庫遷移,所以可以將線上環(huán)境視為基準(zhǔn)進行用例采集。根據(jù)業(yè)務(wù)重要性、線上訪問情況,按優(yōu)先級執(zhí)行測試。單測能有效降低回歸成本,在新業(yè)務(wù)持續(xù)接入的背景下,保障系統(tǒng)穩(wěn)定性。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

適配器層的自動代碼轉(zhuǎn)換 - 基于gogocode將vue2升級為vue3 setup語法

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

調(diào)研與分析

DOM28資訊網(wǎng)——每日最新資訊28at.com

在尋求升級方案的過程中,我們對比了兩款工具:Gogocode 和 vue2-to-composition-api。以下是它們的簡要對比:DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

功能DOM28資訊網(wǎng)——每日最新資訊28at.com

GogocodeDOM28資訊網(wǎng)——每日最新資訊28at.com

vue2-to-composition-apiDOM28資訊網(wǎng)——每日最新資訊28at.com

缺點DOM28資訊網(wǎng)——每日最新資訊28at.com

默認不支持轉(zhuǎn)換成 Vue3 setup 語法DOM28資訊網(wǎng)——每日最新資訊28at.com

不支持 template 轉(zhuǎn)換DOM28資訊網(wǎng)——每日最新資訊28at.com

轉(zhuǎn)換規(guī)則覆蓋DOM28資訊網(wǎng)——每日最新資訊28at.com

轉(zhuǎn)換規(guī)則列表DOM28資訊網(wǎng)——每日最新資訊28at.com

轉(zhuǎn)換效果DOM28資訊網(wǎng)——每日最新資訊28at.com

特性DOM28資訊網(wǎng)——每日最新資訊28at.com

像 jQuery 一樣修改ASTDOM28資訊網(wǎng)——每日最新資訊28at.com

將 Vue2 代碼轉(zhuǎn)換為 Vue 3 的 Composition API 格式DOM28資訊網(wǎng)——每日最新資訊28at.com


DOM28資訊網(wǎng)——每日最新資訊28at.com

2. jQuery-like API 簡化了 AST 修改成本DOM28資訊網(wǎng)——每日最新資訊28at.com

2. 支持在線轉(zhuǎn)換DOM28資訊網(wǎng)——每日最新資訊28at.com

優(yōu)點DOM28資訊網(wǎng)——每日最新資訊28at.com

1. 支持自定義插件DOM28資訊網(wǎng)——每日最新資訊28at.com

1. 支持轉(zhuǎn)換成 Vue3 setup 語法DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

經(jīng)過調(diào)研,gogocode 是基于 AST 封裝的庫可擴展空間大,但是默認 gogocode-plugin-vue 不支持轉(zhuǎn)換成 Composition APIDOM28資訊網(wǎng)——每日最新資訊28at.com

vue2-to-composition-api 倒是支持 Composition API,但是不支持 template 部分的轉(zhuǎn)換。DOM28資訊網(wǎng)——每日最新資訊28at.com

考慮到我們的項目中有許多自定義的轉(zhuǎn)換邏輯,如 UI 庫替換、store 替換等,我們最終決定使用 gogocode 作為主要工具,并結(jié)合其他手段來實現(xiàn) vue2 到 vue3 的全面升級。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

實施與探索

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

基礎(chǔ):升級語法

DOM28資訊網(wǎng)——每日最新資訊28at.com

升級語法是借助 gogocode 的 replace 方法實現(xiàn)的,通過 $$$ 匹配符保留所需要的代碼塊,將 Vue2 的語法快速替換成 Vue3 的語法。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

// 替換datascriptAst.replace("data() {return {$$$};}", `const $data = reactive({$$$})`);
// 替換propsscriptAst.replace("props:{$$$}", "const props = defineProps({$$$})");
// 替換生命周期scriptAst.replace("created(){$$$}", "onBeforeMount(()=>{$$$})")  .replace("mounted(){$$$}", "onMounted(()=>{$$$})")  .replace("async mounted(){$$$}", "onMounted(async ()=>{$$$})")  .replace("beforeUnmount(){$$$}", "onBeforeUnmount(()=>{$$$})")  .replace("unmounted(){$$$}", "onUnmounted(()=>{$$$})")  .replace("beforeDestroy(){$$$}", "onBeforeUnmount(()=>{$$$})")  .replace("destoryed(){$$$}", "onUnmounted(()=>{$$$})");

DOM28資訊網(wǎng)——每日最新資訊28at.com

效果如下,通過 replace 替換的方式適合大部分場景,比如 methods、filters、watch 等DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

進階:處理模板中的變量、函數(shù)中的this變量DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

template綁定的變量可能是data,可能是props,還可能是 methodsDOM28資訊網(wǎng)——每日最新資訊28at.com

想要替換 template 中的變量,需要先收集 data、props、methods 中的 keysDOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

getDataKeys() {  const keys = new Set();  // 只需要第一層的key,所以deep設(shè)為1  this.scriptAst.find('data() {$$$}').find('$_$:$_$', { deep: 1 }).each(node => {    if (node.match[0] && node.match[0][0].node.type === 'Identifier') {      keys.add(node.match[0][0].value);    }  });  return Array.from(keys)}getPropsKeys() {  const keys = new Set();  this.scriptAst.find('props: {$$$1}', { deep: 1 }).each((node) => {    if (node.match['$$$1']) {      node.match['$$$1'].forEach((item) => {        if (item.key && item.key.type === 'Identifier') {          keys.add(item.key.name)        }      })    }  });  return Array.from(keys)}// methods 有點小復(fù)雜,需要考慮異步函數(shù),普通函數(shù)和鍵值對的寫法getMethodsKeys() {  const methodsAst = this.scriptAst.find('methods:{$$$}');  const methods = methodsAst.find('$_$() {$$$1}');  const asyncmMethods = methodsAst.find('async $_$(){$$$1}');  const mapKeys = methodsAst.find('$_$:$$$1', { deep: 1 });  const methodNames = [];  methods.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  asyncmMethods.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  mapKeys.each(node => {    if (node.match[0] && node.match[0][0]) {      methodNames.push(node.match[0][0].value);    }  });  return methodNames;}

DOM28資訊網(wǎng)——每日最新資訊28at.com

收集完成后可以開始遍歷 template 中的 attr,并替換所綁定的變量了。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

handlTemplate() {    // 替換attr, 例如 <div :value="value"></div>    this.ast.find("<template></template>").find(`<$_$ ="$$$0" >$$$1</$_$>`).each((node) => {      node.match['$$$0'].forEach(attr => {        if (attr && attr.value) {          this.dataKeys.some(keyName => {            const reg = new RegExp(`${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `$data.${keyName}`)            if (macth) {              return true;            }          })          this.methodsKeys.some(keyName => {            const reg = new RegExp(`//b${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `methods.${keyName}`)            if (macth) {              return true;            }          })          this.propsKeys.some(keyName => {            const reg = new RegExp(`//b${keyName}//b`, 'g')            const macth = reg.test(attr.value.content);            attr.value.content = attr.value.content.replace(reg, `props.${keyName}`)            if (macth) {              return true;            }          })        }      })      // 替換content,例如:<div>{{value}}<div>      node.match['$$$1'].forEach(node => {        if (node.content && node.content.value) {          // 省略:與上面類似        }      })    })  }

DOM28資訊網(wǎng)——每日最新資訊28at.com

說到 this 替換也是一個繁瑣的問題,this.xx, xx 可以是 data,可以是props,可以是 function,還可以是私有屬性等。DOM28資訊網(wǎng)——每日最新資訊28at.com

所以我們需要先把組件中的 data、props、methods、mapGetter 中的 keys 都收集一遍,然后再替換 script 中的 this 變量。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

// 正則替換更方便,所以需要放在最后一步替換handlThis(code) {  code = code.replace(/this/.([_$0-9a-zA-Z]+)/g, (match, $1) => {    // 替換function body 中的 data引用    if (this.dataKeys.includes($1)) {      return `$data.${$1}`;    }    // 替換function body 中的 methods調(diào)用    else if (this.methodsKeys.includes($1)) {      return `methods.${$1}`;    }    // 替換 vm 私有屬性    else if ($1 && $1[0] === '$') {      return `$vm.${$1}`;    } else if (this.computedKeys.includes($1)) {      return $1    } else if (this.propsKeys.includes($1)) {      return `props.${$1}`    }    return `$vm.${$1}`  })  // 替換function body 中的 動態(tài)methods調(diào)用  code = code.replace(/this/[(.+)/]/g, (match, $1) => {    return `methods[${$1}]`;  })  return code}

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

進階:動態(tài)調(diào)用this.xxx該如何解決

DOM28資訊網(wǎng)——每日最新資訊28at.com

async parseOpenDialog(payload) {  const { schema, data } = payload  await this[schema.method](    parseSchema,    data,    dialogParams,    dialogType  )}

按 vue3 新的寫法,一般是展開的DOM28資訊網(wǎng)——每日最新資訊28at.com

const parseOpenDialog = async (payload) => {}

但是按這個習(xí)慣來轉(zhuǎn)換,就無法做到動態(tài)調(diào)用this.xxx,我們可以嘗試把方法都放在methods對象中,有點類似 vue2DOM28資訊網(wǎng)——每日最新資訊28at.com

const methods = {  parseOpenDialog: async (payload) => {  },  xxx: async() => {  }}

在替換 this 時,將 this 替換成 methods 變成 methods[schema.method]()。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

其他技巧

DOM28資訊網(wǎng)——每日最新資訊28at.com

1 . 原來 vue2 中肯很多屬性掛在組件實例上,比如 $route, $router, $emit 甚至自定義的屬性等等。下面是 vue3 中獲取組件實例的方法。DOM28資訊網(wǎng)——每日最新資訊28at.com

import { getCurrentInstance } from 'vue'const { proxy: $vm } = getCurrentInstance()$vm.xxx = '自定義屬性'

2 . 原來使用的 vuex,現(xiàn)在使用的是 pinia。我們需要先收集 ...mapState($_$, [$$$1]),然后使用 storeToRefs 代替DOM28資訊網(wǎng)——每日最新資訊28at.com

// 獲取store 使用storeToRefsif (this.storeType === 'pinia') {  this.scriptAst  .find("computed:{}")  .before(`const {${stateNames.join(',')}} = storeToRefs(${this.getPiniaStoreName(key)})`)  .replace("computed:{$$$}", "$$$")}

最終將上述轉(zhuǎn)換能力封裝成一個庫,通過 npm 安裝來實現(xiàn)組件批量升級。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

遷移前后的E2E測試 - 視覺輔助UI自動化測試DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

端到端測試是確保新舊系統(tǒng)平穩(wěn)過渡的關(guān)鍵步驟。本次遷移依舊遵循漸進式升級的原則,新增v3路由,線上新老路由共存。共分為功能測試、UI測試、性能測試三個部分。功能測試為單元測試的補充,主要驗證新老路由下核心操作路徑及提交參數(shù)的一致性,攔截請求避免對線上造成影響。性能由通用監(jiān)控大盤進行保障。UI對比測試是本次的重點。DOM28資訊網(wǎng)——每日最新資訊28at.com

新老倉庫分別基于Element UI和Element Plus,Element Plus重新設(shè)計了組件以適應(yīng)Vue3,組件尺寸體系調(diào)整為更自然的大中小選項。間距優(yōu)化為更通用的4px體系,主要涉及 padding 和 margin 屬性修改、 font-size 等字體和圖標(biāo)大小修改等。因此,雖然大部分組件在外觀上保持相似,視覺和布局上可能有一些差異。由于業(yè)務(wù)組件具備一定復(fù)雜性,手寫測試用例工作量繁瑣,新舊頁面組件可能存在差異無法完全復(fù)用,方案也不具備通用性。因此考慮使用計算機視覺技術(shù)來識別和驗證用戶界面的元素。DOM28資訊網(wǎng)——每日最新資訊28at.com

基于公司內(nèi)部的自動化測試平臺,測試框架為Playwright,測試語言選擇Python以更好的利用豐富的圖像處理庫。指定CSS選擇器,隨機選擇頁面上的元素進行截圖和對比,設(shè)定閾值進行判斷。圖像相似度對比可分為傳統(tǒng)的基于像素差的方法和基于圖像特征的方法。圖像特征有SIFT、ORB等特征提取方法和深度學(xué)習(xí)方法。分別選擇一種代表性的算法進行對比和測試。DOM28資訊網(wǎng)——每日最新資訊28at.com

  • SSIM(結(jié)構(gòu)相似性指數(shù)),同時考慮圖片亮度、對比度與結(jié)構(gòu)信息。用于檢測兩張相同尺寸的圖像的相似性。對于圖像的亮度和對比度變化具有較好的魯棒性。
  • SIFT(尺度不變特征變換),用于在圖像中檢測和描述局部特征,這些特征對圖像的縮放、旋轉(zhuǎn)和部分亮度變化具有不變性。能夠檢測和匹配不同尺寸下的特征,對圖像的仿射變換、噪聲和部分遮擋具有較好的魯棒性。
  • LPIPS是一種深度學(xué)習(xí)特征,用于量化圖像之間的感知相似性,通過比較圖像在深度神經(jīng)網(wǎng)絡(luò)中的特征表示來工作,這些特征能夠捕捉到人類視覺所關(guān)注的圖像細節(jié)。基于一個大規(guī)模的人類感知相似性判斷數(shù)據(jù)集,包含484K個人類的判斷,涵蓋了多種圖像變換和失真類型。使用深度特征(例如VGG網(wǎng)絡(luò)中的特征)來衡量圖像相似性,比傳統(tǒng)的度量方法更有效。

DOM28資訊網(wǎng)——每日最新資訊28at.com

v2DOM28資訊網(wǎng)——每日最新資訊28at.com

v3DOM28資訊網(wǎng)——每日最新資訊28at.com

SSIMDOM28資訊網(wǎng)——每日最新資訊28at.com

SIFTDOM28資訊網(wǎng)——每日最新資訊28at.com

LPIPSDOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.656DOM28資訊網(wǎng)——每日最新資訊28at.com

0.855DOM28資訊網(wǎng)——每日最新資訊28at.com

0.909DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.916DOM28資訊網(wǎng)——每日最新資訊28at.com

0.874DOM28資訊網(wǎng)——每日最新資訊28at.com

0.961DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.658DOM28資訊網(wǎng)——每日最新資訊28at.com

0.857DOM28資訊網(wǎng)——每日最新資訊28at.com

0.881DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.877DOM28資訊網(wǎng)——每日最新資訊28at.com

0.855DOM28資訊網(wǎng)——每日最新資訊28at.com

0.926DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.551DOM28資訊網(wǎng)——每日最新資訊28at.com

0.836DOM28資訊網(wǎng)——每日最新資訊28at.com

0.947DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

0.929DOM28資訊網(wǎng)——每日最新資訊28at.com

0.884DOM28資訊網(wǎng)——每日最新資訊28at.com

0.942DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

實驗表明,基于深度學(xué)習(xí)特征的相似度對比結(jié)果更接近用戶感知,針對Vue2升級Vue3 UI組件庫導(dǎo)致的間距、字體、尺寸等細微差異判斷更準(zhǔn)確。因此采用LPIPS作為對比算法。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

def compare_images(url1, url2):  loss_fn = lpips.LPIPS(net = 'alex')  img1 = cv2.imread(url1)  img2 = cv2.imread(url2)  if img1 is not None and img2 is not None and img1.size > 0 and img2.size > 0:      img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))      cv2.imwrite(url2, img2)      combined_image = cv2.hconcat([img1, img2])      ex_img1 = lpips.im2tensor(lpips.load_image(url1))      ex_img2 = lpips.im2tensor(lpips.load_image(url2))      d = loss_fn.forward(ex_img1, ex_img2)      if d is not None:          cv2.putText(combined_image,'score: %.3f'%(1 - d.mean()), (20, 20), cv2.FONT_ITALIC, 0.4, (255, 0, 255))      return d, combined_image  else:      return None

DOM28資訊網(wǎng)——每日最新資訊28at.com

依據(jù)業(yè)務(wù)流程,分別訪問新老路由,對頁面指定元素進行截圖、對比和拼接,輸出測試截圖和完整的測試報告。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

采用視覺輔助UI自動化測試,更接近用戶真實感知,大大降低測試用例復(fù)雜度,提升測試效率,無需關(guān)注繁雜的DOM元素層級。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

上線

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

以頁面配置的形式按待辦進行灰度,跳轉(zhuǎn)至新路由。單元測試已集成至項目流水線中,MR和發(fā)布前觸發(fā)。灰度過程中手動執(zhí)行E2E用例,以自定義環(huán)境變量的形式指定頁面路徑、元素選擇器、相似度閾值等。測試通過后修改頁面配置,引流至新路由。通過用戶故障群和頁面反饋入口響應(yīng)用戶反饋,結(jié)合前端埋點報表觀察線上使用情況和確定灰度策略。通過完善單元測試、E2E測試和制定合理的灰度策略,針對特定模板的遷移已順利完成,期間未收到線上故障反饋。DOM28資訊網(wǎng)——每日最新資訊28at.com

后續(xù)遷移策略將以老倉庫中改動較頻繁文件優(yōu)先入手,測試用例先行,借助自動代碼轉(zhuǎn)換工具快速平穩(wěn)遷移,線上埋點數(shù)據(jù)做輔助。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

收益

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

活躍代碼陸續(xù)遷移,結(jié)束多倉庫并行,減少維護心智。之前我們的常態(tài)是新老倉庫并行,開發(fā)一個完整的業(yè)務(wù)功能時要在ts和js,選項式API和setup語法之間頻繁切換,心智負擔(dān)較重。活躍代碼陸續(xù)遷移至vue3新倉庫,結(jié)合新的框架特性和實用工具,能夠更專注于業(yè)務(wù)邏輯本身。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

核心模塊重構(gòu),“巨石store”輕量化,提高可維護性和可演進性,分層結(jié)構(gòu)保障核心邏輯穩(wěn)定性。原本配置能力擴充時需要在復(fù)雜的數(shù)據(jù)流中“走迷宮”,耦合嚴(yán)重,通用代碼影響范圍大,常常出現(xiàn)A業(yè)務(wù)需求上線導(dǎo)致B業(yè)務(wù)不可用的情況。利用整潔架構(gòu)進行分層設(shè)計后,新增一種審核模式僅需在適配器層新增對應(yīng)物料和action,用例層新增用例。無需修改實體層和其他業(yè)務(wù)相關(guān)的用例、通用頁面、物料等。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

業(yè)務(wù)邏輯的重新梳理,彌補測試用例空缺。領(lǐng)域提取是對業(yè)務(wù)邏輯的重新梳理,前端能加深業(yè)務(wù)理解。穩(wěn)定性至上的模塊很長時間缺少測試用例,造成對開發(fā)人員的經(jīng)驗、能力依賴極大。完善核心鏈路的測試用例能有效降低回歸成本,保障系統(tǒng)穩(wěn)定性。DOM28資訊網(wǎng)——每日最新資訊28at.com

工具沉淀,組內(nèi)復(fù)用。自動代碼轉(zhuǎn)換工具和基于AI能力的前端E2E測試方案為后續(xù)組內(nèi)其他項目的框架升級和遷移提供了便利。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)與展望

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

在2023年開始漸進式升級Vue3后,我們經(jīng)歷了很長一段時間的多倉庫并行。在新業(yè)務(wù)不斷接入、開發(fā)新成員加入的背景下,這樣的模式無疑提升了開發(fā)門檻和維護心智。本次活躍代碼的陸續(xù)遷移結(jié)束了多倉庫并行的現(xiàn)狀,同時在整個實踐過程中我們?yōu)閷徍似脚_這個大型復(fù)雜項目前端引入了整潔架構(gòu)的思想,為后續(xù)的開發(fā)維護提供了一種新的思路。沉淀了一套自動化vue2代碼轉(zhuǎn)vue3 setup的工具,可為后臺項目的框架升級提供便利。同時借助AI能力提升前端E2E測試的效率,利用計算機視覺輔助前端UI自動化測試。有幾點心得:DOM28資訊網(wǎng)——每日最新資訊28at.com

完美重構(gòu)、敏捷重構(gòu)、系統(tǒng)穩(wěn)定性難以平衡。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

既然下定決心對年久失修的代碼進行重構(gòu),我們一定是追求極致優(yōu)化和整潔的。但是需求現(xiàn)狀是不斷有新特性進來,戰(zhàn)線拉的太長必將導(dǎo)致抹平差異的成本增加,因此敏捷性也很重要。同時底線是關(guān)注系統(tǒng)的可靠性和穩(wěn)定性。這三者一定程度上存在矛盾,需平衡:DOM28資訊網(wǎng)——每日最新資訊28at.com

  • 任務(wù)拆分,基于埋點數(shù)據(jù)選擇最重要或最緊急的鏈路進行重構(gòu),而非追求大而全,先落地架構(gòu),后擴充功能
  • 測試用例先行,重構(gòu)必將引入風(fēng)險,用例先行能最大程度保障核心功能的穩(wěn)定遷移
  • 制定合理的灰度策略,新增路由,以頁面配置形式進行灰度,優(yōu)先uv較低的頁面驗證,并保證及時的反饋渠道
  • 持續(xù)優(yōu)化,重構(gòu)應(yīng)成為一種思想,在迭代中持續(xù)優(yōu)化

整潔架構(gòu)非銀彈,容易過度設(shè)計,學(xué)習(xí)門檻較高。DOM28資訊網(wǎng)——每日最新資訊28at.com

  • 按模塊重構(gòu),而非項目
  • 針對新架構(gòu),制定長期維護計劃,組織團隊培訓(xùn),降低學(xué)習(xí)成本

DOM28資訊網(wǎng)——每日最新資訊28at.com

多倉庫遷移路線:數(shù)據(jù)為支撐,測試用例先行,借助自動代碼轉(zhuǎn)換工具和視覺輔助UI自動化測試,制定合理的灰度策略并建立及時的故障反饋和響應(yīng)渠道。對于大型復(fù)雜項目或模塊,先進行面向遷移的重構(gòu),也能起到事半功倍的作用。DOM28資訊網(wǎng)——每日最新資訊28at.com

DOM28資訊網(wǎng)——每日最新資訊28at.com

對我們而言,遷移的結(jié)束只是起點,基于更整潔的架構(gòu)和更先進的前端框架,未來仍有很多發(fā)力點:DOM28資訊網(wǎng)——每日最新資訊28at.com

  • 對于遷移過程中沉淀下來的新架構(gòu),需不斷優(yōu)化和改進,以適應(yīng)復(fù)雜的業(yè)務(wù)場景。
  • 在更多的業(yè)務(wù)場景下評估遷移后的性能改進,確保用戶體驗得到提升。
  • 持續(xù)審查并解決在遷移過程中發(fā)現(xiàn)的技術(shù)債務(wù)。
  • 持續(xù)建設(shè)自動代碼轉(zhuǎn)換工具,賦能團隊內(nèi)其他項目。
  • 視覺輔助UI自動化測試的方案,進一步抽象,給到不熟悉自動化測試的團隊成員“開箱即用”。
  • ...

本文鏈接:http://m.www897cc.com/showinfo-26-99167-0.html我們一起聊聊審核平臺前端新老倉庫遷移

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: AI 引領(lǐng)佛山智造 數(shù)聚禪城開拓創(chuàng)新 2024 華為開發(fā)者大會佛山分會場圓滿落幕

下一篇: Go語言助力安全測試:24小時內(nèi)發(fā)送5億次HTTP/1.1請求

標(biāo)簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
伊人成人在线视频| 欧美 日韩 国产 一区| 99视频在线观看一区三区| 日韩视频一区| 亚洲视频 欧洲视频| 亚洲欧美日韩精品| 久久日韩粉嫩一区二区三区| 麻豆国产精品va在线观看不卡| 欧美日韩国产小视频在线观看| 国产精品视频在线观看| 伊人成人开心激情综合网| 亚洲精品欧美日韩专区| 亚洲在线播放| 免费日韩精品中文字幕视频在线| 欧美日韩一区二区在线| 国产一区91| 亚洲精品中文字幕有码专区| 亚洲免费视频网站| 免费日韩成人| 欧美亚韩一区| 在线日韩中文| 亚洲男人第一av网站| 男人的天堂亚洲| 国产精品欧美日韩| 亚洲人妖在线| 欧美专区在线播放| 欧美日韩亚洲高清一区二区| 国外成人网址| aa亚洲婷婷| 久久综合久久久久88| 国产精品日韩高清| 亚洲第一精品电影| 午夜精品福利视频| 欧美精品v日韩精品v国产精品 | 国产乱肥老妇国产一区二| 亚洲大胆女人| 久久国产福利国产秒拍| 欧美深夜影院| 亚洲人线精品午夜| 久久久九九九九| 欧美性jizz18性欧美| 最新69国产成人精品视频免费| 久久se精品一区精品二区| 欧美日韩亚洲一区二区三区在线| 在线免费观看欧美| 亚洲欧美日韩精品| 欧美视频网站| 亚洲伦理一区| 免费国产一区二区| 韩国亚洲精品| 欧美一区亚洲二区| 国产精品久久久久久久一区探花 | 欧美精品日韩www.p站| 国产揄拍国内精品对白| 亚洲欧美成人精品| 欧美日韩午夜视频在线观看| 91久久黄色| 猛男gaygay欧美视频| 国产资源精品在线观看| 亚洲欧美另类在线| 国产精品国产三级国产a| 99xxxx成人网| 欧美国产激情二区三区| 亚洲二区在线观看| 久久综合久色欧美综合狠狠| 国产人成一区二区三区影院| 亚洲欧美不卡| 国产精品无码专区在线观看 | 欧美成人第一页| 亚洲东热激情| 免费的成人av| 亚洲国产一二三| 欧美va日韩va| 亚洲风情亚aⅴ在线发布| 久久一区二区三区av| 精品1区2区3区4区| 久久综合999| 亚洲国产成人在线| 久久永久免费| 精品不卡一区| 久久综合色影院| 亚洲高清在线观看一区| 免费看av成人| 亚洲区中文字幕| 欧美人与禽猛交乱配| 99视频一区| 国产精品久久久免费| 亚洲欧美电影在线观看| 国产精品网站在线观看| 欧美一级日韩一级| 好看的亚洲午夜视频在线| 久久亚洲一区二区| 91久久亚洲| 欧美日韩精品综合在线| 亚洲先锋成人| 国产精品婷婷| 久久久久久久综合| 亚洲福利专区| 欧美日韩精品系列| 亚洲欧美成人| 黄色成人av网| 欧美黄色免费| 亚洲无玛一区| 国产一区二区三区日韩欧美| 久久精品综合一区| 亚洲国产精品成人va在线观看| 欧美激情免费在线| 亚洲小少妇裸体bbw| 国产精品一区二区黑丝| 久久久久久91香蕉国产| 亚洲国产乱码最新视频| 欧美日韩一区二区三| 亚洲欧美日韩另类| 影音先锋久久资源网| 欧美日韩国语| 欧美在线视频一区二区三区| 亚洲高清自拍| 欧美亚州韩日在线看免费版国语版| 亚洲欧美国产精品桃花| 一区精品在线播放| 欧美日韩一区二区三区视频| 欧美一区二区三区电影在线观看| 狠色狠色综合久久| 欧美日韩国产页| 久久成人精品| 亚洲免费av观看| 国产日韩综合| 欧美精品一区视频| 欧美一进一出视频| 91久久在线播放| 国产精品制服诱惑| 欧美成年视频| 午夜在线成人av| 亚洲欧洲免费视频| 国产欧美一区二区精品忘忧草 | 麻豆91精品| 亚洲曰本av电影| 亚洲国产精品久久| 国产精品久久久久aaaa樱花| 米奇777在线欧美播放| 亚洲在线一区二区三区| 亚洲电影在线看| 国产精品欧美激情| 欧美国产综合视频| 久久国产主播精品| 亚洲精品资源| 韩国精品久久久999| 欧美午夜精品一区| 蜜桃av久久久亚洲精品| 亚洲欧美日韩一区在线| 亚洲国产精品欧美一二99| 国产精品一区二区久久国产| 欧美片在线观看| 久久综合色影院| 先锋影院在线亚洲| 在线视频精品一| 亚洲国产经典视频| 国产一区二区三区高清| 欧美色另类天堂2015| 免费视频亚洲| 欧美亚洲午夜视频在线观看| 夜色激情一区二区| 亚洲国内高清视频| 激情久久综合| 国产香蕉久久精品综合网| 欧美另类69精品久久久久9999| 久久久久免费| 午夜一级在线看亚洲| 一个色综合导航| 亚洲人成网站999久久久综合| 国产在线视频欧美一区二区三区| 国产精品家庭影院| 欧美日韩国产精品自在自线| 麻豆成人在线观看| 久久视频一区二区| 久久国产精品久久w女人spa| 在线亚洲国产精品网站| 亚洲人久久久| 亚洲黄色三级| 亚洲第一在线综合在线| 一区二区三区在线视频播放| 国产精品亚洲成人| 欧美视频在线观看一区二区| 欧美日本一区二区高清播放视频| 免费欧美日韩| 老司机凹凸av亚洲导航| 久久另类ts人妖一区二区| 久久精品成人一区二区三区| 欧美一级久久| 性欧美大战久久久久久久免费观看| 亚洲一区二区高清视频| 亚洲视频在线播放| 日韩视频一区二区三区在线播放免费观看 | 欧美一区在线看| 欧美一区二区三区在线观看视频 | 国产日韩三区| 国产偷久久久精品专区| 国产精品色午夜在线观看| 国产精品啊v在线| 国产精品久久久久久久久果冻传媒| 欧美日韩精品一区视频| 欧美日韩精品免费看| 欧美日韩色一区| 欧美性猛交xxxx乱大交蜜桃|