mirror of
https://gitee.com/dromara/go-view.git
synced 2025-10-13 22:12:11 +08:00
Pre Merge pull request !178 from cherubic_c/master-fetch-dev
This commit is contained in:
commit
fd319d9e2e
62
dev.md
Normal file
62
dev.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
## 二次开发
|
||||||
|
|
||||||
|
新增图表类型的组合图
|
||||||
|
|
||||||
|
1. 在`packages/components/Charts/`新建文件夹`COMBINATIONS`
|
||||||
|
2. 在文件夹新建`index.ts`,在文件夹下新建要添加的组合图表文件夹`BarLine`
|
||||||
|
3. 在`BarLine`下创建对应的文件`index.ts`、`index.vue`、`config.ts`、`config.vue`
|
||||||
|
index.ts内容如下
|
||||||
|
``` js
|
||||||
|
// 公共类型声明
|
||||||
|
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||||
|
// 当前[信息模块]分类声明
|
||||||
|
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
|
||||||
|
|
||||||
|
export const BarLineConfig: ConfigType = {
|
||||||
|
// 唯一key,注意!!!文件夹名称需要修改成与当前组件一致!!!
|
||||||
|
key: 'BarLine',
|
||||||
|
// 图表组件渲染 Components 格式: V + key
|
||||||
|
chartKey: 'VBarLine',
|
||||||
|
// 配置组件渲染 Components 格式: VC + key
|
||||||
|
conKey: 'VCBarLine',
|
||||||
|
// 名称
|
||||||
|
title: '柱状加折线图',
|
||||||
|
// 子分类目录
|
||||||
|
category: ChatCategoryEnum.COMBINATION,
|
||||||
|
// 子分类目录
|
||||||
|
categoryName: ChatCategoryEnumName.COMBINATION,
|
||||||
|
// 包分类
|
||||||
|
package: PackagesCategoryEnum.CHARTS,
|
||||||
|
// 组件框架类型 (注意!若此 Echarts 图表不支持 dataset 格式,则使用 ChartFrameEnum.COMMON)
|
||||||
|
chartFrame: ChartFrameEnum.ECHARTS,
|
||||||
|
// 图片 (注意!图片存放的路径必须在 src/assets/images/chart/包分类名称/*)
|
||||||
|
// 文件夹名称需要和包分类名称一致: PackagesCategoryEnum.CHARTS
|
||||||
|
image: 'bar_x.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
4. 在第二步创建的`index.ts`中进行组合图表的引入
|
||||||
|
``` js
|
||||||
|
import { BarLineConfig } from './BarLine/index'
|
||||||
|
|
||||||
|
export default [BarLineConfig]
|
||||||
|
```
|
||||||
|
5. 在`packages\components\Charts\index.d.ts`新增
|
||||||
|
``` js
|
||||||
|
export enum ChatCategoryEnum {
|
||||||
|
...,
|
||||||
|
COMBINATION = 'COMBINATIONS',
|
||||||
|
...,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ChatCategoryEnumName {
|
||||||
|
...,
|
||||||
|
COMBINATION='组合图'
|
||||||
|
...,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
6. 在`packages\components\Charts\index.ts`新增
|
||||||
|
``` js
|
||||||
|
import COMBINATIONS from './COMBINATIONS'
|
||||||
|
export const ChartList = [...Bars, ...Lines, ...Pies, ...Scatters, ...Maps, ...COMBINATIONS, ...Mores]
|
||||||
|
```
|
@ -8,7 +8,11 @@ import {
|
|||||||
RequestParamsObjType
|
RequestParamsObjType
|
||||||
} from '@/enums/httpEnum'
|
} from '@/enums/httpEnum'
|
||||||
import type { RequestGlobalConfigType, RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
|
import type { RequestGlobalConfigType, RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'
|
||||||
|
//新增取消下次请求开始时未完成的上一次请求 --start
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
let cancel:any;
|
||||||
|
//新增取消下次请求开始时未完成的上一次请求 --end
|
||||||
export const get = <T = any>(url: string, params?: object) => {
|
export const get = <T = any>(url: string, params?: object) => {
|
||||||
return axiosInstance<T>({
|
return axiosInstance<T>({
|
||||||
url: url,
|
url: url,
|
||||||
@ -18,13 +22,18 @@ export const get = <T = any>(url: string, params?: object) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const post = <T = any>(url: string, data?: object, headersType?: string) => {
|
export const post = <T = any>(url: string, data?: object, headersType?: string) => {
|
||||||
|
if (cancel !== undefined) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
return axiosInstance<T>({
|
return axiosInstance<T>({
|
||||||
url: url,
|
url: url,
|
||||||
method: RequestHttpEnum.POST,
|
method: RequestHttpEnum.POST,
|
||||||
data: data,
|
data: data,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': headersType || ContentTypeEnum.JSON
|
'Content-Type': headersType || ContentTypeEnum.JSON
|
||||||
}
|
},
|
||||||
|
//新增取消下次请求开始时未完成的上一次请求
|
||||||
|
cancelToken: new axios.CancelToken(c => cancel = c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +172,7 @@ export const customizeHttp = (targetParams: RequestConfigType, globalParams: Req
|
|||||||
params = translateStr(params)
|
params = translateStr(params)
|
||||||
// form 类型处理
|
// form 类型处理
|
||||||
let formData: FormData = new FormData()
|
let formData: FormData = new FormData()
|
||||||
|
formData.set('default', 'defaultData')
|
||||||
// 类型处理
|
// 类型处理
|
||||||
|
|
||||||
switch (requestParamsBodyType) {
|
switch (requestParamsBodyType) {
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
|
||||||
|
import { BarLineConfig } from './index'
|
||||||
|
import { CreateComponentType } from '@/packages/index.d'
|
||||||
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
|
import dataJson from './data.json'
|
||||||
|
|
||||||
|
|
||||||
|
export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
|
||||||
|
// 柱状折线组合图 分别定义series
|
||||||
|
// 写死name可以定义legend显示的名称
|
||||||
|
export const barSeriesItem = {
|
||||||
|
name:'事件上报数',
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: 15,
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'top',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: null,
|
||||||
|
borderRadius: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lineSeriesItem = {
|
||||||
|
name:'办结率',
|
||||||
|
type: 'line',
|
||||||
|
smooth: false,
|
||||||
|
symbol: "circle",
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'top',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
symbolSize: 5, //设定实心点的大小
|
||||||
|
itemStyle: {
|
||||||
|
color: '#FFE47A',
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
type: 'solid',
|
||||||
|
width: 3,
|
||||||
|
color: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const option = {
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
show: true,
|
||||||
|
type: 'shadow'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data:null
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'category'
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
show: true,
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
dataset: { ...dataJson },
|
||||||
|
series: [barSeriesItem, lineSeriesItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Config extends PublicConfigClass implements CreateComponentType {
|
||||||
|
public key = BarLineConfig.key
|
||||||
|
public chartConfig = cloneDeep(BarLineConfig)
|
||||||
|
// 图表配置项
|
||||||
|
public option = echartOptionProfixHandle(option, includes)
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<!-- Echarts 全局设置 -->
|
||||||
|
<global-setting :optionData="optionData"></global-setting>
|
||||||
|
<CollapseItem v-for="(item, index) in seriesList" :key="index" :name="`${item.type=='bar' ? '柱状图' : '折线图'}`" :expanded="true">
|
||||||
|
<SettingItemBox name="图形" v-if="item.type=='bar'">
|
||||||
|
<SettingItem name="宽度">
|
||||||
|
<n-input-number
|
||||||
|
v-model:value="item.barWidth"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
placeholder="自动计算"
|
||||||
|
></n-input-number>
|
||||||
|
</SettingItem>
|
||||||
|
<SettingItem name="圆角">
|
||||||
|
<n-input-number v-model:value="item.itemStyle.borderRadius" :min="0" size="small"></n-input-number>
|
||||||
|
</SettingItem>
|
||||||
|
</SettingItemBox>
|
||||||
|
<SettingItemBox name="线条" v-if="item.type=='line'">
|
||||||
|
<SettingItem name="宽度">
|
||||||
|
<n-input-number
|
||||||
|
v-model:value="item.lineStyle.width"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
placeholder="自动计算"
|
||||||
|
></n-input-number>
|
||||||
|
</SettingItem>
|
||||||
|
<SettingItem name="类型">
|
||||||
|
<n-select v-model:value="item.lineStyle.type" size="small" :options="lineConf.lineStyle.type"></n-select>
|
||||||
|
</SettingItem>
|
||||||
|
</SettingItemBox>
|
||||||
|
<SettingItemBox name="实心点" v-if="item.type=='line'">
|
||||||
|
<SettingItem name="大小">
|
||||||
|
<n-input-number
|
||||||
|
v-model:value="item.symbolSize"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
placeholder="自动计算"
|
||||||
|
></n-input-number>
|
||||||
|
</SettingItem>
|
||||||
|
</SettingItemBox>
|
||||||
|
<setting-item-box name="标签">
|
||||||
|
<setting-item>
|
||||||
|
<n-space>
|
||||||
|
<n-switch v-model:value="item.label.show" size="small" />
|
||||||
|
<n-text>展示标签</n-text>
|
||||||
|
</n-space>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item name="大小">
|
||||||
|
<n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item name="颜色">
|
||||||
|
<n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker>
|
||||||
|
</setting-item>
|
||||||
|
<setting-item name="位置">
|
||||||
|
<n-select
|
||||||
|
v-model:value="item.label.position"
|
||||||
|
:options="[
|
||||||
|
{ label: 'top', value: 'top' },
|
||||||
|
{ label: 'left', value: 'left' },
|
||||||
|
{ label: 'right', value: 'right' },
|
||||||
|
{ label: 'bottom', value: 'bottom' }
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</setting-item>
|
||||||
|
</setting-item-box>
|
||||||
|
</CollapseItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PropType, computed } from 'vue'
|
||||||
|
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
|
||||||
|
import { lineConf } from '@/packages/chartConfiguration/echarts/index'
|
||||||
|
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
optionData: {
|
||||||
|
type: Object as PropType<GlobalThemeJsonType>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const seriesList = computed(() => {
|
||||||
|
console.log(props.optionData);
|
||||||
|
return props.optionData.series
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"dimensions": ["product", "data1", "data2"],
|
||||||
|
"source": [
|
||||||
|
{
|
||||||
|
"product": "1月",
|
||||||
|
"data1": 104,
|
||||||
|
"data2": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "2月",
|
||||||
|
"data1": 56,
|
||||||
|
"data2": 56
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "3月",
|
||||||
|
"data1": 136,
|
||||||
|
"data2": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "4月",
|
||||||
|
"data1": 86,
|
||||||
|
"data2": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "5月",
|
||||||
|
"data1": 98,
|
||||||
|
"data2": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "6月",
|
||||||
|
"data1": 86,
|
||||||
|
"data2": 70
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"product": "7月",
|
||||||
|
"data1": 77,
|
||||||
|
"data2": 57
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
26
src/packages/components/Charts/COMBINATIONS/BarLine/index.ts
Normal file
26
src/packages/components/Charts/COMBINATIONS/BarLine/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 公共类型声明
|
||||||
|
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
|
||||||
|
// 当前[信息模块]分类声明
|
||||||
|
import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
|
||||||
|
|
||||||
|
export const BarLineConfig: ConfigType = {
|
||||||
|
// 唯一key,注意!!!文件夹名称需要修改成与当前组件一致!!!
|
||||||
|
key: 'BarLine',
|
||||||
|
// 图表组件渲染 Components 格式: V + key
|
||||||
|
chartKey: 'VBarLine',
|
||||||
|
// 配置组件渲染 Components 格式: VC + key
|
||||||
|
conKey: 'VCBarLine',
|
||||||
|
// 名称
|
||||||
|
title: '柱状加折线图',
|
||||||
|
// 子分类目录
|
||||||
|
category: ChatCategoryEnum.COMBINATION,
|
||||||
|
// 子分类目录
|
||||||
|
categoryName: ChatCategoryEnumName.COMBINATION,
|
||||||
|
// 包分类
|
||||||
|
package: PackagesCategoryEnum.CHARTS,
|
||||||
|
// 组件框架类型 (注意!若此 Echarts 图表不支持 dataset 格式,则使用 ChartFrameEnum.COMMON)
|
||||||
|
chartFrame: ChartFrameEnum.ECHARTS,
|
||||||
|
// 图片 (注意!图片存放的路径必须在 src/assets/images/chart/包分类名称/*)
|
||||||
|
// 文件夹名称需要和包分类名称一致: PackagesCategoryEnum.CHARTS
|
||||||
|
image: 'bar_x.png'
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()"
|
||||||
|
autoresize></v-chart>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch, PropType } from 'vue'
|
||||||
|
import VChart from 'vue-echarts'
|
||||||
|
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
|
||||||
|
import dataJson from './data.json'
|
||||||
|
import { use } from 'echarts/core'
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
|
//引入柱状图 折线图
|
||||||
|
import { BarChart, LineChart } from 'echarts/charts'
|
||||||
|
import config, { includes, barSeriesItem, lineSeriesItem } from './config'
|
||||||
|
import { mergeTheme, setOption } from '@/packages/public/chart'
|
||||||
|
import { useChartDataFetch } from '@/hooks'
|
||||||
|
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
|
||||||
|
import { isPreview } from '@/utils'
|
||||||
|
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
themeSetting: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
themeColor: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
chartConfig: {
|
||||||
|
type: Object as PropType<config>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
|
||||||
|
|
||||||
|
use([DatasetComponent, CanvasRenderer, BarChart, LineChart, GridComponent, TooltipComponent, LegendComponent])
|
||||||
|
|
||||||
|
const vChartRef = ref<typeof VChart>()
|
||||||
|
|
||||||
|
const option = computed(() => {
|
||||||
|
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
|
||||||
|
})
|
||||||
|
|
||||||
|
// dataset 无法变更条数的补丁
|
||||||
|
const dataSetHandle = (dataset: typeof dataJson) => {
|
||||||
|
if (dataset.source) {
|
||||||
|
props.chartConfig.option.series[0].data = dataset.source.map(i => i.data1)
|
||||||
|
props.chartConfig.option.series[1].data = dataset.source.map(i => i.data2)
|
||||||
|
// @ts-ignore
|
||||||
|
// props.chartConfig.option.legend.data = dataset.seriesData.map((i: { name: string }) => i.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vChartRef.value && isPreview()) {
|
||||||
|
setOption(vChartRef.value, props.chartConfig.option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.chartConfig.option.dataset,
|
||||||
|
newData => {
|
||||||
|
try {
|
||||||
|
dataSetHandle(newData)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
|
||||||
|
dataSetHandle(newData)
|
||||||
|
})
|
||||||
|
</script>
|
3
src/packages/components/Charts/COMBINATIONS/index.ts
Normal file
3
src/packages/components/Charts/COMBINATIONS/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { BarLineConfig } from './BarLine/index'
|
||||||
|
|
||||||
|
export default [BarLineConfig]
|
2
src/packages/components/Charts/index.d.ts
vendored
2
src/packages/components/Charts/index.d.ts
vendored
@ -5,6 +5,7 @@ export enum ChatCategoryEnum {
|
|||||||
LINE = 'Lines',
|
LINE = 'Lines',
|
||||||
SCATTER = 'Scatters',
|
SCATTER = 'Scatters',
|
||||||
MAP = 'Maps',
|
MAP = 'Maps',
|
||||||
|
COMBINATION = 'COMBINATIONS',
|
||||||
MORE = 'Mores'
|
MORE = 'Mores'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,5 +15,6 @@ export enum ChatCategoryEnumName {
|
|||||||
LINE = '折线图',
|
LINE = '折线图',
|
||||||
SCATTER = '散点图',
|
SCATTER = '散点图',
|
||||||
MAP = '地图',
|
MAP = '地图',
|
||||||
|
COMBINATION = '组合图',
|
||||||
MORE = '更多'
|
MORE = '更多'
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import Pies from './Pies'
|
|||||||
import Lines from './Lines'
|
import Lines from './Lines'
|
||||||
import Scatters from './Scatters'
|
import Scatters from './Scatters'
|
||||||
import Mores from './Mores'
|
import Mores from './Mores'
|
||||||
|
import COMBINATIONS from './COMBINATIONS'
|
||||||
import Maps from './Maps'
|
import Maps from './Maps'
|
||||||
|
|
||||||
export const ChartList = [...Bars, ...Lines, ...Pies, ...Scatters, ...Maps, ...Mores]
|
export const ChartList = [...Bars, ...Lines, ...Pies, ...Scatters, ...Maps, ...COMBINATIONS, ...Mores]
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 修复右下角白点用的 -->
|
<!-- 修复右下角白点用的 -->
|
||||||
<div v-if="designStore.getDarkTheme" class="fix-edit-screens-block"></div>
|
<!-- <div v-if="designStore.getDarkTheme" class="fix-edit-screens-block"></div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -321,6 +321,10 @@ window.onKeySpacePressHold = (isHold: boolean) => {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: rgba(144, 146, 152, 0.3);
|
background-color: rgba(144, 146, 152, 0.3);
|
||||||
}
|
}
|
||||||
|
// 修复右下角白点用的
|
||||||
|
&::-webkit-scrollbar-corner {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fix-edit-screens-block {
|
.fix-edit-screens-block {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user