提交前端utils文件
This commit is contained in:
parent
8149e3589a
commit
6516465df7
@ -14,7 +14,7 @@ const composeStore = composeStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const copyStore = copyStoreWithOut()
|
||||
const lockStore = lockStoreWithOut()
|
||||
const { curComponent, isInEditor, editMode } = storeToRefs(dvMainStore)
|
||||
const { curComponent, editMode } = storeToRefs(dvMainStore)
|
||||
const { areaData } = storeToRefs(composeStore)
|
||||
|
||||
const ctrlKey = 17,
|
||||
@ -88,7 +88,10 @@ const checkDialog = () => {
|
||||
}
|
||||
})
|
||||
document.querySelectorAll('.ed-popper').forEach(element => {
|
||||
if (window.getComputedStyle(element).getPropertyValue('display') != 'none') {
|
||||
if (
|
||||
!element.classList?.contains('template-popper-tips') &&
|
||||
window.getComputedStyle(element).getPropertyValue('display') != 'none'
|
||||
) {
|
||||
haveDialog = true
|
||||
}
|
||||
})
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { cos, sin } from '@/utils/translate'
|
||||
import {
|
||||
CHART_FONT_FAMILY_MAP,
|
||||
CHART_FONT_FAMILY_MAP_TRANS,
|
||||
DEFAULT_COLOR_CASE,
|
||||
DEFAULT_COLOR_CASE_DARK,
|
||||
DEFAULT_INDICATOR_STYLE
|
||||
DEFAULT_COLOR_CASE_DARK
|
||||
} from '@/views/chart/components/editor/util/chart'
|
||||
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
@ -160,6 +158,9 @@ export const customStyleTrans = {
|
||||
axisLabel: ['fontSize'],
|
||||
splitLine: {
|
||||
lineStyle: ['width']
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: ['width']
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
@ -167,6 +168,9 @@ export const customStyleTrans = {
|
||||
axisLabel: ['fontSize'],
|
||||
splitLine: {
|
||||
lineStyle: ['width']
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: ['width']
|
||||
}
|
||||
},
|
||||
yAxisExt: {
|
||||
@ -174,6 +178,9 @@ export const customStyleTrans = {
|
||||
axisLabel: ['fontSize'],
|
||||
splitLine: {
|
||||
lineStyle: ['width']
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: ['width']
|
||||
}
|
||||
},
|
||||
misc: {
|
||||
@ -286,7 +293,14 @@ export const THEME_ATTR_TRANS_MAIN = {
|
||||
color: 'color',
|
||||
proportionSeriesFormatter: ['color']
|
||||
},
|
||||
tooltip: ['color']
|
||||
tooltip: ['color'],
|
||||
misc: {
|
||||
bullet: {
|
||||
bar: {
|
||||
target: ['fill']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const THEME_ATTR_TRANS_MAIN_SYMBOL = {
|
||||
@ -488,9 +502,16 @@ export function adaptCurThemeCommonStyle(component) {
|
||||
// 背景融合-Begin 如果是大屏['CanvasBoard', 'CanvasIcon', 'Picture']组件不需要设置背景
|
||||
if (
|
||||
dvMainStore.dvInfo.type === 'dataV' &&
|
||||
['CanvasBoard', 'CanvasIcon', 'Picture', 'Group', 'SvgTriangle', 'SvgStar'].includes(
|
||||
component.component
|
||||
)
|
||||
[
|
||||
'CanvasBoard',
|
||||
'CanvasIcon',
|
||||
'Picture',
|
||||
'Group',
|
||||
'SvgTriangle',
|
||||
'SvgStar',
|
||||
'RectShape',
|
||||
'CircleShape'
|
||||
].includes(component.component)
|
||||
) {
|
||||
component.commonBackground['backgroundColorSelect'] = false
|
||||
component.commonBackground['innerPadding'] = 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { cloneDeep, forEach } from 'lodash-es'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import componentList, {
|
||||
ACTION_SELECTION,
|
||||
BASE_CAROUSEL,
|
||||
@ -32,8 +32,14 @@ import { deepCopy, nameTrim } from '@/utils/utils'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
|
||||
import { guid } from '@/views/visualized/data/dataset/form/util'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { inMobile, dvInfo, canvasStyleData, componentData, canvasViewInfo, appData } =
|
||||
storeToRefs(dvMainStore)
|
||||
const {
|
||||
inMobile,
|
||||
dvInfo: curDvInfo,
|
||||
canvasStyleData,
|
||||
componentData,
|
||||
canvasViewInfo,
|
||||
appData
|
||||
} = storeToRefs(dvMainStore)
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
||||
@ -141,6 +147,9 @@ export function historyItemAdaptor(
|
||||
canvasInfo
|
||||
) {
|
||||
componentItem['canvasActive'] = false
|
||||
if (componentItem.component === 'VQuery') {
|
||||
componentItem['freeze'] = componentItem['freeze'] || false // 冻结字段适配
|
||||
}
|
||||
// 定时报告过滤组件适配 如果当前是定时报告默认切有设置对应的过滤组件默认值,则替换过滤组件
|
||||
if (
|
||||
componentItem.component === 'VQuery' &&
|
||||
@ -239,6 +248,12 @@ export function historyAdaptor(
|
||||
attachInfo,
|
||||
canvasVersion
|
||||
) {
|
||||
// 防止出现主画布canvasId 不一致情况
|
||||
if (attachInfo?.resourceTable === 'snapshot') {
|
||||
canvasDataResult.forEach(componentItem => {
|
||||
componentItem.canvasId = 'canvas-main'
|
||||
})
|
||||
}
|
||||
const curVersion = wsCache.get('x-de-execute-version')
|
||||
// 含有定时报告过滤项每次都需要匹配
|
||||
const reportFilterInfo = canvasInfo?.reportFilterInfo
|
||||
@ -251,6 +266,7 @@ export function historyAdaptor(
|
||||
canvasStyleResult['fontFamily'] = canvasStyleResult['fontFamily'] || 'PingFang'
|
||||
canvasStyleResult.dashboard['showGrid'] = canvasStyleResult.dashboard['showGrid'] || false
|
||||
canvasStyleResult.dashboard['matrixBase'] = canvasStyleResult.dashboard['matrixBase'] || 4
|
||||
canvasStyleResult.dashboard['gapMode'] = canvasStyleResult.dashboard['gapMode'] || 'middle'
|
||||
canvasStyleResult.component['seniorStyleSetting'] =
|
||||
canvasStyleResult.component['seniorStyleSetting'] || deepCopy(SENIOR_STYLE_SETTING_LIGHT)
|
||||
canvasStyleResult['suspensionButtonAvailable'] =
|
||||
@ -318,11 +334,12 @@ export function refreshOtherComponent(dvId, busiFlag) {
|
||||
}
|
||||
}
|
||||
|
||||
export function initCanvasDataPrepare(dvId, busiFlag, callBack) {
|
||||
export function initCanvasDataPrepare(dvId, params, callBack) {
|
||||
const busiFlag = params.busiFlag
|
||||
const copyFlag = busiFlag != null && busiFlag.includes('-copy')
|
||||
const busiFlagCustom = copyFlag ? busiFlag.split('-')[0] : busiFlag
|
||||
const method = copyFlag ? findCopyResource : findById
|
||||
let attachInfo = { source: 'main' }
|
||||
let attachInfo = { source: params.source ? params.source : 'main' }
|
||||
if (dvMainStore.canvasAttachInfo && !!dvMainStore.canvasAttachInfo.taskId) {
|
||||
attachInfo = { source: 'report', taskId: dvMainStore.canvasAttachInfo.taskId }
|
||||
const showWatermarkExist =
|
||||
@ -334,12 +351,14 @@ export function initCanvasDataPrepare(dvId, busiFlag, callBack) {
|
||||
attachInfo['showWatermark'] = enable
|
||||
}
|
||||
}
|
||||
|
||||
attachInfo['resourceTable'] = params.resourceTable ? params.resourceTable : 'core'
|
||||
method(dvId, busiFlagCustom, attachInfo).then(res => {
|
||||
const canvasInfo = res.data
|
||||
const watermarkInfo = {
|
||||
...canvasInfo.watermarkInfo,
|
||||
settingContent: JSON.parse(canvasInfo.watermarkInfo.settingContent)
|
||||
settingContent: canvasInfo.watermarkInfo?.settingContent
|
||||
? JSON.parse(canvasInfo.watermarkInfo.settingContent)
|
||||
: {}
|
||||
}
|
||||
|
||||
const dvInfo = {
|
||||
@ -378,21 +397,21 @@ export function initCanvasDataPrepare(dvId, busiFlag, callBack) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function initCanvasData(dvId, busiFlag, callBack) {
|
||||
export async function initCanvasData(dvId, params, callBack) {
|
||||
initCanvasDataPrepare(
|
||||
dvId,
|
||||
busiFlag,
|
||||
params,
|
||||
function ({ canvasDataResult, canvasStyleResult, dvInfo, canvasViewInfoPreview }) {
|
||||
dvMainStore.setComponentData(canvasDataResult)
|
||||
dvMainStore.setCanvasStyle(canvasStyleResult)
|
||||
dvMainStore.updateCurDvInfo(dvInfo)
|
||||
dvMainStore.setCanvasViewInfo(canvasViewInfoPreview)
|
||||
// 刷新联动信息
|
||||
getPanelAllLinkageInfo(dvInfo.id).then(rsp => {
|
||||
getPanelAllLinkageInfo(dvInfo.id, params.resourceTable).then(rsp => {
|
||||
dvMainStore.setNowPanelTrackInfo(rsp.data)
|
||||
})
|
||||
// 刷新跳转信息
|
||||
queryVisualizationJumpInfo(dvInfo.id).then(rsp => {
|
||||
queryVisualizationJumpInfo(dvInfo.id, params.resourceTable).then(rsp => {
|
||||
dvMainStore.setNowPanelJumpInfo(rsp.data)
|
||||
})
|
||||
callBack({ canvasDataResult, canvasStyleResult, dvInfo, canvasViewInfoPreview })
|
||||
@ -403,7 +422,7 @@ export async function initCanvasData(dvId, busiFlag, callBack) {
|
||||
export async function backCanvasData(dvId, mobileViewInfo, busiFlag, callBack) {
|
||||
initCanvasDataPrepare(
|
||||
dvId,
|
||||
busiFlag,
|
||||
{ busiFlag },
|
||||
function ({ canvasDataResult, canvasStyleResult, canvasViewInfoPreview }) {
|
||||
const componentDataCopy = canvasDataResult.filter(ele => !!ele.inMobile)
|
||||
const componentDataId = componentDataCopy.map(ele => ele.id)
|
||||
@ -450,10 +469,10 @@ export async function backCanvasData(dvId, mobileViewInfo, busiFlag, callBack) {
|
||||
)
|
||||
}
|
||||
|
||||
export function initCanvasDataMobile(dvId, busiFlag, callBack) {
|
||||
export function initCanvasDataMobile(dvId, params, callBack) {
|
||||
initCanvasDataPrepare(
|
||||
dvId,
|
||||
busiFlag,
|
||||
params,
|
||||
function ({ canvasDataResult, canvasStyleResult, dvInfo, canvasViewInfoPreview }) {
|
||||
const componentData = canvasDataResult.filter(ele => !!ele.inMobile)
|
||||
canvasDataResult.forEach(ele => {
|
||||
@ -504,7 +523,7 @@ export function initCanvasDataMobile(dvId, busiFlag, callBack) {
|
||||
dvMainStore.updateCurDvInfo(dvInfo)
|
||||
dvMainStore.setCanvasViewInfo(canvasViewInfoPreview)
|
||||
// 刷新联动信息
|
||||
getPanelAllLinkageInfo(dvInfo.id).then(rsp => {
|
||||
getPanelAllLinkageInfo(dvInfo.id, params.resourceTable).then(rsp => {
|
||||
dvMainStore.setNowPanelTrackInfo(rsp.data)
|
||||
})
|
||||
// 刷新跳转信息
|
||||
@ -523,12 +542,12 @@ export function initCanvasDataMobile(dvId, busiFlag, callBack) {
|
||||
|
||||
export function checkCanvasChangePre(callBack) {
|
||||
// do pre
|
||||
const isUpdate = dvInfo.value.id && dvInfo.value.optType !== 'copy'
|
||||
const isUpdate = curDvInfo.value.id && curDvInfo.value.optType !== 'copy'
|
||||
// 桌面版为单人模式不需要检查
|
||||
if (isUpdate && !isDesktop()) {
|
||||
const params = { ...dvInfo.value, watermarkInfo: null }
|
||||
const params = { ...curDvInfo.value, watermarkInfo: null }
|
||||
const tips =
|
||||
(dvInfo.value.type === 'dashboard'
|
||||
(curDvInfo.value.type === 'dashboard'
|
||||
? t('work_branch.dashboard')
|
||||
: t('work_branch.big_data_screen')) + t('visualization.save_conflict_tips')
|
||||
checkCanvasChange(params).then(rsp => {
|
||||
@ -551,6 +570,10 @@ export function checkCanvasChangePre(callBack) {
|
||||
}
|
||||
|
||||
export async function canvasSave(callBack) {
|
||||
await canvasSaveWithParams(null, callBack)
|
||||
}
|
||||
|
||||
export async function canvasSaveWithParams(params, callBack) {
|
||||
dvMainStore.removeGroupArea()
|
||||
const componentDataToSave = cloneDeep(componentData.value)
|
||||
componentDataToSave.forEach(item => {
|
||||
@ -574,7 +597,7 @@ export async function canvasSave(callBack) {
|
||||
componentData: JSON.stringify(componentDataToSave),
|
||||
canvasViewInfo: canvasViewInfo.value,
|
||||
appData: appData.value,
|
||||
...dvInfo.value,
|
||||
...curDvInfo.value,
|
||||
checkVersion: wsCache.get('x-de-execute-version'),
|
||||
contentId: newContentId,
|
||||
watermarkInfo: null
|
||||
@ -593,19 +616,26 @@ export async function canvasSave(callBack) {
|
||||
ElMessage.error('数据集分组名称已存在')
|
||||
return
|
||||
}
|
||||
nameTrim(dvInfo.value, t('components.length_1_64_characters'))
|
||||
const method = dvInfo.value.id && dvInfo.value.optType !== 'copy' ? updateCanvas : saveCanvas
|
||||
nameTrim(curDvInfo.value, t('components.length_1_64_characters'))
|
||||
const method =
|
||||
curDvInfo.value.id && curDvInfo.value.optType !== 'copy' ? updateCanvas : saveCanvas
|
||||
if (method === updateCanvas) {
|
||||
await dvNameCheck({
|
||||
opt: 'edit',
|
||||
nodeType: 'leaf',
|
||||
name: dvInfo.value.name,
|
||||
type: dvInfo.value.type,
|
||||
id: dvInfo.value.id
|
||||
name: curDvInfo.value.name,
|
||||
type: curDvInfo.value.type,
|
||||
id: curDvInfo.value.id
|
||||
})
|
||||
}
|
||||
method(canvasInfo).then(res => {
|
||||
dvMainStore.updateDvInfoId(res.data, newContentId)
|
||||
if (method === updateCanvas) {
|
||||
// saveCanvas 为初次保存 状态为0 updateCanvas为二次保存状态为2 当存在传入状态时,则修改对应的传入状态
|
||||
const status = params?.status ? params?.status : res.data?.status
|
||||
dvMainStore.updateDvInfoCall(status, null, newContentId)
|
||||
} else {
|
||||
dvMainStore.updateDvInfoCall(0, res.data, newContentId)
|
||||
}
|
||||
snapshotStore.resetStyleChangeTimes()
|
||||
callBack(res)
|
||||
})
|
||||
@ -630,7 +660,7 @@ export function setIdValueTrans(from, to, content, colList) {
|
||||
pre[next[from]] = next[to]
|
||||
return pre
|
||||
}, {})
|
||||
const on = content?.match(/\[(.+?)\]/g)
|
||||
const on = content?.match(/\[(.+?)\]/g) || []
|
||||
if (on) {
|
||||
on.forEach(itm => {
|
||||
const ele = itm.slice(1, -1)
|
||||
@ -896,12 +926,18 @@ export async function decompressionPre(params, callBack) {
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
historyAdaptor(deTemplateData.canvasStyleData, deTemplateData.componentData, null, null, null)
|
||||
historyAdaptor(
|
||||
deTemplateData.canvasStyleData,
|
||||
deTemplateData.componentData,
|
||||
null,
|
||||
{ resourceTable: 'snapshot' },
|
||||
null
|
||||
)
|
||||
callBack(deTemplateData)
|
||||
}
|
||||
|
||||
export function isDashboard() {
|
||||
return dvInfo.value.type === 'dashboard'
|
||||
return curDvInfo.value.type === 'dashboard'
|
||||
}
|
||||
|
||||
export function trackBarStyleCheck(element, trackbarStyle, _scale, trackMenuNumber) {
|
||||
@ -983,12 +1019,12 @@ export function findComponentById(componentId) {
|
||||
return result
|
||||
}
|
||||
|
||||
export function onInitReady(params) {
|
||||
export function onInitReady(params, eventName = 'canvas_init_ready') {
|
||||
try {
|
||||
console.info('Canvas initReady')
|
||||
console.info('event:' + eventName)
|
||||
const targetPm = {
|
||||
type: 'dataease-embedded-interactive',
|
||||
eventName: 'canvas_init_ready',
|
||||
eventName: eventName,
|
||||
args: params
|
||||
}
|
||||
window.parent.postMessage(targetPm, '*')
|
||||
|
@ -2,7 +2,7 @@ import { deepCopy } from './utils'
|
||||
import { divide, multiply } from 'mathjs'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { groupSizeStyleAdaptor } from '@/utils/style'
|
||||
import { groupItemStyleAdaptor, groupSizeStyleAdaptor } from '@/utils/style'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
@ -53,7 +53,17 @@ function changeComponentsSizeWithScaleCircle(componentDataCopy, scale) {
|
||||
})
|
||||
|
||||
if (['Group'].includes(component.component)) {
|
||||
changeComponentsSizeWithScaleCircle(component.propValue, scale)
|
||||
groupSizeStyleAdaptor(component)
|
||||
const parentStyle = component.style
|
||||
component.propValue.forEach(componentInner => {
|
||||
if (['DeTabs'].includes(componentInner.component)) {
|
||||
componentInner.propValue.forEach(tabItem => {
|
||||
changeComponentsSizeWithScaleCircle(tabItem.componentData, scale)
|
||||
})
|
||||
} else {
|
||||
groupItemStyleAdaptor(componentInner, parentStyle)
|
||||
}
|
||||
})
|
||||
} else if (['DeTabs'].includes(component.component)) {
|
||||
component.propValue.forEach(tabItem => {
|
||||
changeComponentsSizeWithScaleCircle(tabItem.componentData, scale)
|
||||
|
@ -3,11 +3,20 @@ export default function decomposeComponent(
|
||||
component,
|
||||
editorRect,
|
||||
parentStyle,
|
||||
canvasId = 'canvas-main'
|
||||
canvasId = 'canvas-main',
|
||||
parentGroupStyle?
|
||||
) {
|
||||
// 计算出元素新的 top left 坐标
|
||||
component.style.left = component.style.left + parentStyle.left
|
||||
component.style.top = component.style.top + parentStyle.top
|
||||
component.groupStyle = {}
|
||||
if (parentGroupStyle && component.groupStyle) {
|
||||
const originLeftScale = component.groupStyle['left'] / component.groupStyle['width']
|
||||
const originTopScale = component.groupStyle['top'] / component.groupStyle['height']
|
||||
component.groupStyle['width'] = component.groupStyle['width'] * parentGroupStyle['width']
|
||||
component.groupStyle['height'] = component.groupStyle['height'] * parentGroupStyle['height']
|
||||
component.groupStyle['left'] =
|
||||
parentStyle.left + component.groupStyle['width'] * originLeftScale
|
||||
component.groupStyle['top'] = parentStyle.top + component.groupStyle['height'] * originTopScale
|
||||
}
|
||||
component.canvasId = canvasId
|
||||
}
|
||||
|
@ -174,7 +174,8 @@ function findStaticSourceInner(componentDataInfo, staticResource) {
|
||||
) {
|
||||
staticResource.push(item.propValue['url'])
|
||||
} else if (
|
||||
item.component === 'picture-group' &&
|
||||
item.component === 'UserView' &&
|
||||
item.innerType === 'picture-group' &&
|
||||
item.propValue['urlList'] &&
|
||||
item.propValue['urlList'].length > 0
|
||||
) {
|
||||
|
@ -267,11 +267,14 @@ function dataVTabSizeStyleAdaptor(tabComponent) {
|
||||
tabComponent.propValue.forEach(tabItem => {
|
||||
tabItem.componentData.forEach(tabComponent => {
|
||||
groupItemStyleAdaptor(tabComponent, parentStyleAdaptor)
|
||||
if (['Group'].includes(tabComponent.component)) {
|
||||
groupSizeStyleAdaptor(tabComponent)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function groupItemStyleAdaptor(component, parentStyle) {
|
||||
export function groupItemStyleAdaptor(component, parentStyle) {
|
||||
// 分组还原逻辑
|
||||
// 当发上分组缩放是,要将内部组件按照比例转换
|
||||
const styleScale = component.groupStyle
|
||||
|
@ -75,23 +75,6 @@ const getSecondEnd = timestamp => {
|
||||
return [+new Date(timestamp), +new Date(timestamp) + 999]
|
||||
}
|
||||
|
||||
const getYearBegin = timestamp => {
|
||||
const time = new Date(timestamp)
|
||||
return +new Date(time.getFullYear(), 0, 1)
|
||||
}
|
||||
|
||||
const getMonthBegin = timestamp => {
|
||||
const time = new Date(timestamp)
|
||||
const date = new Date(time.getFullYear(), time.getMonth(), 1)
|
||||
date.setDate(1)
|
||||
date.setMonth(date.getMonth() + 1)
|
||||
return +new Date(time.getFullYear(), time.getMonth(), 1)
|
||||
}
|
||||
|
||||
const getDayBegin = timestamp => {
|
||||
return +new Date(timestamp)
|
||||
}
|
||||
|
||||
const getUtcTime = timestamp => {
|
||||
if (timestamp) {
|
||||
const time = new Date(timestamp)
|
||||
|
@ -2,8 +2,6 @@ import { BusiTreeNode } from '@/models/tree/TreeNode'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { loadScript } from '@/utils/RemoteJs'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
const { t } = useI18n()
|
||||
|
||||
const { wsCache } = useCache()
|
||||
export function deepCopy(target) {
|
||||
@ -295,3 +293,17 @@ export const nameTrim = (target: {}, msg = '名称字段长度1-64个字符') =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getActiveCategories = contents => {
|
||||
const result = ['最近使用']
|
||||
if (contents) {
|
||||
contents.forEach(item => {
|
||||
if (item.showFlag) {
|
||||
item.categories.forEach(category => {
|
||||
result.push(category.name)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return new Set(result)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user