mirror of
				https://github.com/Tencent/tmagic-editor.git
				synced 2025-11-04 18:52:18 +08:00 
			
		
		
		
	feat(editor): 支持禁用数据源与代码块
This commit is contained in:
		
							parent
							
								
									b1f020d532
								
							
						
					
					
						commit
						6152a78467
					
				@ -415,6 +415,26 @@ const renderFunction = async (stage) => {
 | 
			
		||||
</script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## renderType
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
  是用iframe渲染还是直接渲染
 | 
			
		||||
 | 
			
		||||
- **默认值:** `iframe`
 | 
			
		||||
 | 
			
		||||
- **类型:** `string`
 | 
			
		||||
  
 | 
			
		||||
  'iframe' | 'native'
 | 
			
		||||
 | 
			
		||||
- **示例:**
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<template>
 | 
			
		||||
  <m-editor render-type="native"></m-editor>
 | 
			
		||||
</template>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## autoScrollIntoView
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
@ -942,4 +962,88 @@ const updateDragEl = (el, target) => {
 | 
			
		||||
  <m-editor :disabled-multi-select="true"></m-editor>
 | 
			
		||||
</template>
 | 
			
		||||
```
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
## guidesOptions
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
标尺配置
 | 
			
		||||
 | 
			
		||||
- **类型:** `Partial<GuidesOptions>`
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
## disabledPageFragment
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
禁用页面片
 | 
			
		||||
 | 
			
		||||
- **类型:** `boolean`
 | 
			
		||||
  
 | 
			
		||||
## disabledStageOverlay
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
禁用双击在浮层中单独编辑选中组件
 | 
			
		||||
 | 
			
		||||
- **类型:** `boolean`
 | 
			
		||||
  
 | 
			
		||||
## disabledShowSrc
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
禁用属性配置面板右下角显示源码的按钮
 | 
			
		||||
 | 
			
		||||
- **类型:** `boolean`
 | 
			
		||||
 | 
			
		||||
## disabledDataSource
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
禁用数据源
 | 
			
		||||
 | 
			
		||||
- **类型:** `boolean`
 | 
			
		||||
 | 
			
		||||
## disabledCodeBlock
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
禁用代码块
 | 
			
		||||
 | 
			
		||||
- **类型:** `boolean`
 | 
			
		||||
 | 
			
		||||
## treeIndent
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
已选组件、代码编辑、数据源缩进配置
 | 
			
		||||
 | 
			
		||||
- **类型:** `number`
 | 
			
		||||
 | 
			
		||||
## treeNextLevelIndentIncrement
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
已选组件、代码编辑、数据源子节点缩进增量配置
 | 
			
		||||
 | 
			
		||||
- **类型:** `number`
 | 
			
		||||
 | 
			
		||||
## customContentMenu
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
用于自定义组件树与画布的右键菜单
 | 
			
		||||
 | 
			
		||||
- **类型:** `function`
 | 
			
		||||
 | 
			
		||||
## pageBarSortOptions
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
页面顺序拖拽配置参数
 | 
			
		||||
 | 
			
		||||
## pageFilterFunction
 | 
			
		||||
 | 
			
		||||
- **详情:**
 | 
			
		||||
  
 | 
			
		||||
页面搜索函数
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,10 @@ export interface EditorProps {
 | 
			
		||||
  disabledStageOverlay?: boolean;
 | 
			
		||||
  /** 禁用属性配置面板右下角显示源码的按钮 */
 | 
			
		||||
  disabledShowSrc?: boolean;
 | 
			
		||||
  /** 禁用数据源 */
 | 
			
		||||
  disabledDataSource?: boolean;
 | 
			
		||||
  /** 禁用代码块 */
 | 
			
		||||
  disabledCodeBlock?: boolean;
 | 
			
		||||
  /** 已选组件、代码编辑、数据源缩进配置 */
 | 
			
		||||
  treeIndent?: number;
 | 
			
		||||
  /** 已选组件、代码编辑、数据源子节点缩进增量配置 */
 | 
			
		||||
@ -111,6 +115,8 @@ export const defaultEditorProps = {
 | 
			
		||||
  containerHighlightDuration: 800,
 | 
			
		||||
  containerHighlightType: ContainerHighlightType.DEFAULT,
 | 
			
		||||
  disabledShowSrc: false,
 | 
			
		||||
  disabledDataSource: false,
 | 
			
		||||
  disabledCodeBlock: false,
 | 
			
		||||
  componentGroupList: () => [],
 | 
			
		||||
  datasourceList: () => [],
 | 
			
		||||
  menu: () => ({ left: [], right: [] }),
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="m-fields-data-source-field-select">
 | 
			
		||||
    <FieldSelect
 | 
			
		||||
      v-if="showDataSourceFieldSelect || !config.fieldConfig"
 | 
			
		||||
      v-if="!disabledDataSource && (showDataSourceFieldSelect || !config.fieldConfig)"
 | 
			
		||||
      :model-value="model[name]"
 | 
			
		||||
      :disabled="disabled"
 | 
			
		||||
      :size="size"
 | 
			
		||||
@ -26,7 +26,11 @@
 | 
			
		||||
      @change="onChangeHandler"
 | 
			
		||||
    ></component>
 | 
			
		||||
 | 
			
		||||
    <TMagicTooltip v-if="config.fieldConfig" :disabled="showDataSourceFieldSelect" content="选择数据源">
 | 
			
		||||
    <TMagicTooltip
 | 
			
		||||
      v-if="config.fieldConfig && !disabledDataSource"
 | 
			
		||||
      :disabled="showDataSourceFieldSelect"
 | 
			
		||||
      content="选择数据源"
 | 
			
		||||
    >
 | 
			
		||||
      <TMagicButton
 | 
			
		||||
        style="margin-left: 5px"
 | 
			
		||||
        :type="showDataSourceFieldSelect ? 'primary' : 'default'"
 | 
			
		||||
@ -83,10 +87,11 @@ watch(
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const { dataSourceService } = useServices();
 | 
			
		||||
const { dataSourceService, propsService } = useServices();
 | 
			
		||||
const mForm = inject<FormState | undefined>('mForm');
 | 
			
		||||
 | 
			
		||||
const dataSources = computed(() => dataSourceService.get('dataSources') || []);
 | 
			
		||||
const disabledDataSource = computed(() => propsService.getDisabledDataSource());
 | 
			
		||||
 | 
			
		||||
const type = computed((): string => {
 | 
			
		||||
  let type = props.config.fieldConfig?.type;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <TMagicInput
 | 
			
		||||
    v-if="disabledDataSource"
 | 
			
		||||
    v-model="state"
 | 
			
		||||
    :disabled="disabled"
 | 
			
		||||
    :size="size"
 | 
			
		||||
    :clearable="true"
 | 
			
		||||
    @change="changeHandler"
 | 
			
		||||
  ></TMagicInput>
 | 
			
		||||
  <component
 | 
			
		||||
    v-if="disabled || isFocused"
 | 
			
		||||
    v-else-if="disabled || isFocused"
 | 
			
		||||
    :is="getDesignConfig('components')?.autocomplete.component || 'el-autocomplete'"
 | 
			
		||||
    class="tmagic-design-auto-complete"
 | 
			
		||||
    ref="autocomplete"
 | 
			
		||||
@ -52,7 +60,7 @@ import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
 | 
			
		||||
import { Coin } from '@element-plus/icons-vue';
 | 
			
		||||
 | 
			
		||||
import type { DataSchema, DataSourceSchema } from '@tmagic/core';
 | 
			
		||||
import { getDesignConfig, TMagicAutocomplete, TMagicTag } from '@tmagic/design';
 | 
			
		||||
import { getDesignConfig, TMagicAutocomplete, TMagicInput, TMagicTag } from '@tmagic/design';
 | 
			
		||||
import type { DataSourceInputConfig, FieldProps } from '@tmagic/form';
 | 
			
		||||
import { getKeysArray, isNumber } from '@tmagic/utils';
 | 
			
		||||
 | 
			
		||||
@ -72,7 +80,7 @@ const emit = defineEmits<{
 | 
			
		||||
  change: [value: string];
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
const { dataSourceService } = useServices();
 | 
			
		||||
const { dataSourceService, propsService } = useServices();
 | 
			
		||||
 | 
			
		||||
const autocompleteRef = useTemplateRef<InstanceType<typeof TMagicAutocomplete>>('autocomplete');
 | 
			
		||||
const isFocused = ref(false);
 | 
			
		||||
@ -81,6 +89,7 @@ const displayState = ref<{ value: string; type: 'var' | 'text' }[]>([]);
 | 
			
		||||
 | 
			
		||||
const input = computed<HTMLInputElement>(() => autocompleteRef.value?.inputRef?.input);
 | 
			
		||||
const dataSources = computed(() => dataSourceService.get('dataSources'));
 | 
			
		||||
const disabledDataSource = computed(() => propsService.getDisabledDataSource());
 | 
			
		||||
 | 
			
		||||
const setDisplayState = () => {
 | 
			
		||||
  displayState.value = getDisplayField(dataSources.value, state.value);
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@ const emit = defineEmits<{
 | 
			
		||||
  change: [v: any, eventData?: ContainerChangeEventData];
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
const { editorService, dataSourceService, eventsService, codeBlockService } = useServices();
 | 
			
		||||
const { editorService, dataSourceService, eventsService, codeBlockService, propsService } = useServices();
 | 
			
		||||
 | 
			
		||||
// 事件名称下拉框表单配置
 | 
			
		||||
const eventNameConfig = computed(() => {
 | 
			
		||||
@ -173,24 +173,39 @@ const actionTypeConfig = computed(() => {
 | 
			
		||||
    text: '联动类型',
 | 
			
		||||
    type: 'select',
 | 
			
		||||
    defaultValue: ActionType.COMP,
 | 
			
		||||
    options: () => [
 | 
			
		||||
      {
 | 
			
		||||
        text: '组件',
 | 
			
		||||
        label: '组件',
 | 
			
		||||
        value: ActionType.COMP,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        text: '代码',
 | 
			
		||||
        label: '代码',
 | 
			
		||||
        disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
 | 
			
		||||
        value: ActionType.CODE,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        text: '数据源',
 | 
			
		||||
        label: '数据源',
 | 
			
		||||
        value: ActionType.DATA_SOURCE,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    options: () => {
 | 
			
		||||
      const o: {
 | 
			
		||||
        text: string;
 | 
			
		||||
        label: string;
 | 
			
		||||
        value: string;
 | 
			
		||||
        disabled?: boolean;
 | 
			
		||||
      }[] = [
 | 
			
		||||
        {
 | 
			
		||||
          text: '组件',
 | 
			
		||||
          label: '组件',
 | 
			
		||||
          value: ActionType.COMP,
 | 
			
		||||
        },
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      if (!propsService.getDisabledCodeBlock()) {
 | 
			
		||||
        o.push({
 | 
			
		||||
          text: '代码',
 | 
			
		||||
          label: '代码',
 | 
			
		||||
          disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
 | 
			
		||||
          value: ActionType.CODE,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!propsService.getDisabledDataSource()) {
 | 
			
		||||
        o.push({
 | 
			
		||||
          text: '数据源',
 | 
			
		||||
          label: '数据源',
 | 
			
		||||
          value: ActionType.DATA_SOURCE,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return o;
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  return { ...defaultActionTypeConfig, ...props.config.actionTypeConfig };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -197,6 +197,22 @@ export const initServiceState = (
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  watch(
 | 
			
		||||
    () => props.disabledCodeBlock,
 | 
			
		||||
    (disabledCodeBlock) => propsService.setDisabledCodeBlock(disabledCodeBlock ?? false),
 | 
			
		||||
    {
 | 
			
		||||
      immediate: true,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  watch(
 | 
			
		||||
    () => props.disabledDataSource,
 | 
			
		||||
    (disabledDataSource) => propsService.setDisabledDataSource(disabledDataSource ?? false),
 | 
			
		||||
    {
 | 
			
		||||
      immediate: true,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  onBeforeUnmount(() => {
 | 
			
		||||
    editorService.resetState();
 | 
			
		||||
    historyService.resetState();
 | 
			
		||||
 | 
			
		||||
@ -201,7 +201,7 @@ const props = withDefaults(
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const { depService, uiService } = useServices();
 | 
			
		||||
const { depService, uiService, propsService } = useServices();
 | 
			
		||||
 | 
			
		||||
const collecting = computed(() => depService.get('collecting'));
 | 
			
		||||
const taskLength = computed(() => depService.get('taskLength'));
 | 
			
		||||
@ -283,7 +283,19 @@ const getItemConfig = (data: SideItem): SideComponent => {
 | 
			
		||||
  return typeof data === 'string' ? map[data] : data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
 | 
			
		||||
const sideBarItems = computed(() =>
 | 
			
		||||
  props.data.items
 | 
			
		||||
    .map((item) => getItemConfig(item))
 | 
			
		||||
    .filter((item) => {
 | 
			
		||||
      if (item.$key === SideItemKey.DATA_SOURCE) {
 | 
			
		||||
        return !propsService.getDisabledDataSource();
 | 
			
		||||
      }
 | 
			
		||||
      if (item.$key === SideItemKey.CODE_BLOCK) {
 | 
			
		||||
        return !propsService.getDisabledCodeBlock();
 | 
			
		||||
      }
 | 
			
		||||
      return true;
 | 
			
		||||
    }),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  sideBarItems,
 | 
			
		||||
 | 
			
		||||
@ -57,6 +57,10 @@ class Props extends BaseService {
 | 
			
		||||
    propsConfigMap: {},
 | 
			
		||||
    propsValueMap: {},
 | 
			
		||||
    relateIdMap: {},
 | 
			
		||||
    /** 禁用数据源 */
 | 
			
		||||
    disabledDataSource: false,
 | 
			
		||||
    /** 禁用代码块 */
 | 
			
		||||
    disabledCodeBlock: false,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -66,6 +70,22 @@ class Props extends BaseService {
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setDisabledDataSource(disabled: boolean) {
 | 
			
		||||
    this.state.disabledDataSource = disabled;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setDisabledCodeBlock(disabled: boolean) {
 | 
			
		||||
    this.state.disabledCodeBlock = disabled;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getDisabledDataSource(): boolean {
 | 
			
		||||
    return this.state.disabledDataSource;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getDisabledCodeBlock(): boolean {
 | 
			
		||||
    return this.state.disabledCodeBlock;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setPropsConfigs(configs: Record<string, FormConfig | PropsFormConfigFunction>) {
 | 
			
		||||
    Object.keys(configs).forEach((type: string) => {
 | 
			
		||||
      this.setPropsConfig(toLine(type), configs[type]);
 | 
			
		||||
@ -74,7 +94,11 @@ class Props extends BaseService {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async fillConfig(config: FormConfig, labelWidth?: string) {
 | 
			
		||||
    return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px');
 | 
			
		||||
    return fillConfig(config, {
 | 
			
		||||
      labelWidth: typeof labelWidth !== 'function' ? labelWidth : '80px',
 | 
			
		||||
      disabledDataSource: this.getDisabledDataSource(),
 | 
			
		||||
      disabledCodeBlock: this.getDisabledCodeBlock(),
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async setPropsConfig(type: string, config: FormConfig | PropsFormConfigFunction) {
 | 
			
		||||
 | 
			
		||||
@ -188,6 +188,10 @@ export interface PropsState {
 | 
			
		||||
  propsConfigMap: Record<string, FormConfig>;
 | 
			
		||||
  propsValueMap: Record<string, Partial<MNode>>;
 | 
			
		||||
  relateIdMap: Record<Id, Id>;
 | 
			
		||||
  /** 禁用数据源 */
 | 
			
		||||
  disabledDataSource: boolean;
 | 
			
		||||
  /** 禁用代码块 */
 | 
			
		||||
  disabledCodeBlock: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface StageOverlayState {
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@
 | 
			
		||||
 | 
			
		||||
import { NODE_CONDS_KEY } from '@tmagic/core';
 | 
			
		||||
import { tMagicMessage } from '@tmagic/design';
 | 
			
		||||
import type { FormConfig, FormState, TabPaneConfig } from '@tmagic/form';
 | 
			
		||||
import type { FormConfig, FormState, TabConfig, TabPaneConfig } from '@tmagic/form';
 | 
			
		||||
 | 
			
		||||
export const arrayOptions = [
 | 
			
		||||
  { text: '包含', value: 'include' },
 | 
			
		||||
@ -165,7 +165,14 @@ export const displayTabConfig: TabPaneConfig = {
 | 
			
		||||
 * @param config 组件属性配置
 | 
			
		||||
 * @returns Object
 | 
			
		||||
 */
 | 
			
		||||
export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => {
 | 
			
		||||
export const fillConfig = (
 | 
			
		||||
  config: FormConfig = [],
 | 
			
		||||
  {
 | 
			
		||||
    labelWidth = '80px',
 | 
			
		||||
    disabledDataSource = false,
 | 
			
		||||
    disabledCodeBlock = false,
 | 
			
		||||
  }: { labelWidth?: string; disabledDataSource?: boolean; disabledCodeBlock?: boolean } = {},
 | 
			
		||||
): FormConfig => {
 | 
			
		||||
  const propsConfig: FormConfig = [];
 | 
			
		||||
 | 
			
		||||
  // 组件类型,必须要有
 | 
			
		||||
@ -208,20 +215,34 @@ export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormCo
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'tab',
 | 
			
		||||
      labelWidth,
 | 
			
		||||
      items: [
 | 
			
		||||
        {
 | 
			
		||||
          title: '属性',
 | 
			
		||||
          items: [...propsConfig, ...config],
 | 
			
		||||
        },
 | 
			
		||||
        { ...styleTabConfig },
 | 
			
		||||
        { ...eventTabConfig },
 | 
			
		||||
        { ...advancedTabConfig },
 | 
			
		||||
        { ...displayTabConfig },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
  const noCodeAdvancedTabItems = advancedTabConfig.items.filter((item) => item.type !== 'code-select');
 | 
			
		||||
 | 
			
		||||
  if (noCodeAdvancedTabItems.length > 0 && disabledCodeBlock) {
 | 
			
		||||
    advancedTabConfig.items = noCodeAdvancedTabItems;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const tabConfig: TabConfig = {
 | 
			
		||||
    type: 'tab',
 | 
			
		||||
    labelWidth,
 | 
			
		||||
    items: [
 | 
			
		||||
      {
 | 
			
		||||
        title: '属性',
 | 
			
		||||
        items: [...propsConfig, ...config],
 | 
			
		||||
      },
 | 
			
		||||
      { ...styleTabConfig },
 | 
			
		||||
      { ...eventTabConfig },
 | 
			
		||||
    ],
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (!disabledCodeBlock) {
 | 
			
		||||
    tabConfig.items.push({ ...advancedTabConfig });
 | 
			
		||||
  } else if (noCodeAdvancedTabItems.length > 0) {
 | 
			
		||||
    tabConfig.items.push({ ...advancedTabConfig });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!disabledDataSource) {
 | 
			
		||||
    tabConfig.items.push({ ...displayTabConfig });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return [tabConfig];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user