Prechádzať zdrojové kódy

reactor:387 新增旅游信件的督办和台账查询功能

zhangchong 1 mesiac pred
rodič
commit
0f50e1b786

+ 1 - 1
.env.development

@@ -3,7 +3,7 @@ VITE_MODE_NAME=development
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
 VITE_STORAGE_NAME=dev
 # 业务系统基础请求地址
-VITE_API_URL=http://110.188.24.28:50200
+VITE_API_URL=http://110.188.24.28:50300
 # 业务系统socket请求地址
 VITE_API_SOCKET_URL=http://110.188.24.28:50100/hubs/hotline
 # 业务系统文件上传上传请求地址

+ 5 - 4
src/utils/echarts.ts

@@ -4,8 +4,8 @@ import {
   CanvasRenderer
 } from 'echarts/renderers'
 import {
-  BarChart, PieChart, MapChart, EffectScatterChart, LineChart, PictorialBarChart, GraphChart, GaugeChart, ScatterChart
-} from 'echarts/charts'
+  BarChart, PieChart, MapChart, EffectScatterChart, LineChart, PictorialBarChart, GraphChart, GaugeChart, ScatterChart, FunnelChart,
+} from 'echarts/charts';
 import {
   GridComponent,
   TitleComponent,
@@ -17,7 +17,7 @@ import {
   MarkPointComponent,
   GraphicComponent,
   DataZoomComponent,
-  ToolboxComponent
+  ToolboxComponent,
 } from 'echarts/components'
 
 use([
@@ -33,7 +33,8 @@ use([
   MarkPointComponent,
   GraphicComponent,
   DataZoomComponent,
-  ToolboxComponent
+  ToolboxComponent,
+  FunnelChart
 ])
 
 export const registerEcharts = (app: any) => {

+ 1 - 1
src/views/early/push/components/Push-Select.vue

@@ -71,7 +71,7 @@ const gridOptions = reactive<any>({
 		reserve: true,
 		showReserveStatus: true,
 	},
-	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true, keyField: 'id' },
 	minHeight: 300,
 	maxHeight: 500,
 	columns: [

+ 1 - 1
src/views/early/push/components/Push-add.vue

@@ -95,7 +95,7 @@ const gridOptions = reactive<any>({
 			buttons: 'toolbar_buttons',
 		},
 	},
-	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true, keyField: 'id' },
 	minHeight: 300,
 	maxHeight: 500,
 	columns: [

+ 323 - 83
src/views/early/statistics/index.vue

@@ -1,88 +1,63 @@
 <template>
 	<div class="early-statistics-container layout-padding">
 		<div class="layout-padding-auto layout-padding-view pd20">
-			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent :disabled="state.loading">
-				<el-form-item label="推送报告名称" prop="EarlyWarningPushName">
-					<el-input
-						v-model="state.queryParams.EarlyWarningPushName"
-						placeholder="请填写推送报告名称"
-						clearable
-						@keyup.enter="handleQuery"
-						class="keyword-input"
-					/>
-				</el-form-item>
-				<el-form-item label="推送状态" prop="EarlyPushStatus">
-					<el-select v-model="state.queryParams.EarlyPushStatus" placeholder="请选择推送状态" @change="handleQuery">
-						<el-option v-for="item in earlyWarningLevel" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
-					</el-select>
-				</el-form-item>
-				<el-form-item>
-					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
-					<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
-				</el-form-item>
-			</el-form>
-			<vxe-toolbar
-				ref="toolbarRef"
-				:loading="state.loading"
-				custom
-				:refresh="{
-					queryMethod: handleQuery,
-				}"
-			>
-				<template #buttons>
-					<el-button type="primary" @click="onAdd" v-auth="'early:push:add'"> <SvgIcon name="ele-Plus" class="mr5" />新增推送 </el-button>
-				</template>
-			</vxe-toolbar>
+			<el-tabs v-model="type" @tab-change="changeTab">
+				<el-tab-pane name="0" label="预警统计图表" :disabled="state.loading"></el-tab-pane>
+				<el-tab-pane name="1" label="预警统计列表" :disabled="state.loading"></el-tab-pane>
+			</el-tabs>
+			<div class="flex-center-between">
+				<div></div>
+				<el-date-picker v-model="monthValue" type="month" placeholder="请选择月份" :clearable="false" @change="selectMonth" />
+			</div>
 			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
-				<vxe-table
-					border
-					:loading="state.loading"
-					:data="state.tableData"
-					:column-config="{ resizable: true, useKey: true }"
-					:row-config="{ isCurrent: true, isHover: true, useKey: true, height: 30 }"
-					ref="tableRef"
-					height="auto"
-					auto-resize
-					show-overflow
-					:scrollY="{ enabled: true, gt: 100 }"
-					id="earlyStatistics"
-					:custom-config="{ storage: true }"
-					:sort-config="{ remote: true }"
-					@sort-change="sortChange"
-				>
-					<vxe-column field="earlyWarningSetting.earlyWarningName" title="预警名称"></vxe-column>
-					<vxe-column field="earlyWarningSetting.earlyWarningLevelName" title="预警级别"></vxe-column>
-					<vxe-column field="earlyWarningSetting.earlyWarningTypeName" title="时间/时间段"></vxe-column>
-					<vxe-column field="earlyWarningSetting.earlyWarningTypeName" title="预警类型"></vxe-column>
-					<vxe-column field="earlyWarningSetting.frequencyText" title="频率"></vxe-column>
-					<vxe-column field="fullAddress" title="预警地点"></vxe-column>
-					<vxe-column field="isEnable" title="关联工单">
-						<template #default="{ row }">
-							<el-button type="primary" link  @click="onDetail(row)">{{ row.earlyWarningOrderDetails.length }}</el-button>
-						</template>
-					</vxe-column>
-					<vxe-column field="lastEarlyTime" title="最新预警时间" width="160">
-						<template #default="{ row }">
-							{{ formatDate(row.lastEarlyTime, 'YYYY-mm-dd HH:MM:SS') }}
-						</template>
-					</vxe-column>
-					<vxe-column title="操作" fixed="right" width="90" align="center">
-						<template #default="{ row }">
-							<el-button link type="primary" @click="onDetail(row)" title="查看详情"> 详情 </el-button>
-						</template>
-					</vxe-column>
-				</vxe-table>
+				<el-row :gutter="20" v-show="type === '0'" class="w100 h100">
+					<el-col :span="12">
+						<v-chart class="chart" :option="option" :loading="state.loading" autoresize />
+					</el-col>
+					<el-col :span="12" class="w100 h100">
+						<div style="height: 50%" class="w100">
+							<v-chart class="chart" :option="option1" :loading="state.loading" autoresize />
+						</div>
+						<div style="height: 50%" class="w100">
+							<v-chart class="chart" :option="option2" :loading="state.loading" autoresize />
+						</div>
+					</el-col>
+				</el-row>
+				<vxe-grid v-bind="gridOptions" v-show="type === '1'">
+					<template #form>
+						<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent :disabled="state.loading">
+							<el-form-item label="预警名称" prop="EarlyWarningPushName">
+								<el-input
+									v-model="state.queryParams.EarlyWarningPushName"
+									placeholder="请填写预警名称"
+									clearable
+									@keyup.enter="handleQuery"
+									class="keyword-input"
+								/>
+							</el-form-item>
+							<el-form-item label="预警类型" prop="EarlyPushStatus">
+								<el-select v-model="state.queryParams.EarlyPushStatus" placeholder="请选择预警类型" @change="handleQuery">
+									<el-option v-for="item in earlyWarningLevel" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
+								</el-select>
+							</el-form-item>
+							<el-form-item>
+								<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+								<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+							</el-form-item>
+						</el-form>
+					</template>
+					<template #pager>
+						<pagination
+							@pagination="queryList"
+							:total="state.total"
+							v-model:current-page="state.queryParams.PageIndex"
+							v-model:page-size="state.queryParams.PageSize"
+							:disabled="state.loading"
+						/>
+					</template>
+				</vxe-grid>
 			</div>
-			<pagination
-				@pagination="queryList"
-				:total="state.total"
-				v-model:current-page="state.queryParams.PageIndex"
-				v-model:page-size="state.queryParams.PageSize"
-				:disabled="state.loading"
-			/>
 		</div>
-		<!--  新增  -->
-		<push-add ref="pushAddRef"  @updateList="queryList"/>
 		<!--  详情  -->
 		<push-detail ref="pushDetailRef" />
 	</div>
@@ -95,13 +70,14 @@ import { formatDate } from '@/utils/formatTime';
 import { deleteEarlySetting, getEarlySettingBaseData, getEarlySettingList } from '@/api/early/setting';
 import { getEarlyManageList } from '@/api/early/manage';
 import { getEarlyPushList } from '@/api/early/push';
+import { statisticsOrderAcceptExport } from '@/api/statistics/order';
+import dayjs from 'dayjs';
 // 引入组件
 const PushDetail = defineAsyncComponent(() => import('@/views/early/push/components/Detail.vue')); // 详情
-const PushAdd = defineAsyncComponent(() => import('@/views/early/push/components/Push-add.vue')); // 新增
 const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
 
 // 定义变量内容
-const state = reactive({
+const state = reactive<any>({
 	loading: false, // 加载状态
 	queryParams: {
 		// 查询参数
@@ -115,7 +91,215 @@ const state = reactive({
 	total: 0, // 总条数
 	tableData: [], // 表格数据
 });
-const ruleFormRef = ref<any>(null); // 表单ref
+const monthValue = ref<Date | null>(new Date()); // 月份 默认当月
+const days = dayjs(monthValue.value).daysInMonth(); // 获取当月有多少天
+const dataX = Array.from({ length: days }, (v, k) => k + 1 + '日');
+const xData = ref<EmptyArrayType>(dataX); // x轴数据
+xData.value = dataX;
+const selectMonth = (val: Date) => {
+	// 获取当月的天数 并组成数组
+	const days = dayjs(val).daysInMonth(); // 获取当月有多少天
+	const dataX = Array.from({ length: days }, (v, k) => k + 1 + '日');
+	xData.value = dataX;
+	queryList();
+	console.log(dataX, '111');
+};
+console.log(monthValue.value, '111');
+const type = ref<string>('0');
+const changeTab = () => {};
+const requestParams = ref<EmptyObjectType>({});
+const gridOptions = reactive<any>({
+	loading: false,
+	border: true,
+	showOverflow: true,
+	printConfig: {},
+	columnConfig: {
+		resizable: true,
+	},
+	toolbarConfig: {
+		zoom: true,
+		custom: true,
+		refresh: {
+			queryMethod: () => {
+				queryList();
+			},
+		},
+		tools: [{ toolRender: { name: 'exportAll' } }],
+	},
+	customConfig: {
+		storage: true,
+	},
+	id: 'earlyStatistics',
+	rowConfig: { isHover: true, height: 30, isCurrent: true, useKey: true },
+	height: 'auto',
+	columns: [
+		{ field: 'acceptType', title: '预警名称', minWidth: 90 },
+		{ field: 'sumCount', title: '级别' },
+		{ field: 'completionCount', title: '预警类型' },
+		{ field: 'completionRate', title: '频率' },
+		{ field: 'visitCount', title: '出现次数' },
+		{ field: 'sumCountRate', title: '占比' },
+		{
+			title: '操作',
+			width: 90,
+			align: 'center',
+			slots: {
+				default: ({ row }) => {
+					return (
+						<el-button link type="primary" onClick={() => onDetail(row)}>
+							详情
+						</el-button>
+					);
+				},
+			},
+		},
+	],
+	data: [],
+	params: {
+		exportMethod: statisticsOrderAcceptExport,
+		exportParams: requestParams,
+	},
+});
+const option = ref<any>({});
+// 信件来源统计
+const setOption = (legendData: string[], seriesData: any) => {
+	option.value = {
+		title: {},
+		tooltip: {
+			// 提示框组件
+			trigger: 'axis', // 触发类型
+			axisLabel: {
+				fontSize: 12, // 文字像素
+			},
+		},
+		legend: {
+			top: '1%',
+			data: legendData,
+			icon: 'roundRect',
+		},
+		xAxis: {
+			data: xData.value, // 数据
+			min: 0, // 最小值
+			type: 'category',
+			boundaryGap: true, // 开始和结尾是否隔开
+			axisLabel: {
+				color: '#808080', // 文字颜色
+				fontSize: 12, // 文字像素
+			},
+			axisLine: {
+				show: false, // 是否显示坐标轴轴线
+			},
+			axisTick: {
+				show: false, // 去除刻度线
+			},
+		},
+		yAxis: {
+			type: 'value',
+			min: 0, // 最小值
+			axisLine: {
+				show: false,
+			},
+			axisLabel: {
+				color: '#808080', // 文字颜色
+				fontSize: 12, // 文字像素
+			},
+			// y轴分割线的颜色
+			splitLine: {
+				lineStyle: {
+					color: 'rgba(0,0,0,0.15)', // 分割线的颜色
+				},
+			},
+		},
+		series: seriesData,
+	};
+};
+const option1 = ref<any>({});
+// 信件来源统计
+const setOption1 = (legendData: string[], data: any) => {
+	option1.value = {
+		title: {
+			text: '信件来源统计',
+			left: 'center',
+		},
+		tooltip: {
+			formatter: '{b0}: {c0} ({d}%)',
+		},
+		legend: [
+			{
+				left: 'left',
+				top: '40',
+				orient: 'vertical',
+				data: legendData,
+			},
+		],
+		series: [
+			{
+				type: 'pie',
+				radius: ['0%', '80%'],
+				label: {
+					show: true,
+					overflow: 'none',
+					formatter: function (params) {
+						if (params.name !== '') {
+							return `${params.name}:${params.data.value}(${params.percent}%)`;
+						}
+					},
+				},
+				data: data,
+			},
+		],
+	};
+};
+const option2 = ref<any>({});
+// 信件来源统计
+const setOption2 = (legendData: string[], data: any) => {
+	option2.value = {
+		tooltip: {},
+		grid: {
+			left: '10%',
+			right: '10%',
+			bottom: '10%',
+			containLabel: true,
+		},
+		series: [
+			{
+				name: '漏斗图',
+				type: 'funnel',
+				width: '55%',
+				minSize: '15%',
+				left: '25%',
+				gap: 0,
+				labelLayout: {
+					verticalAlign: 'top',
+				},
+				label: {
+					show: true,
+					position: 'rightTop',
+					color: '#4B5265',
+					fontSize: 12,
+					formatter: (params) => {
+						return `${params.data.name}${params.data.value} ${params.data.percent}%`;
+					},
+				},
+				labelLine: {
+					show: false,
+				},
+				itemStyle: {
+					borderColor: '#fff',
+					borderWidth: 0,
+				},
+				data: [
+					{ name: '浏览1', value: 400, percent: 100 },
+					{ name: '浏览2', value: 320, percent: 40 },
+					{ name: '浏览3', value: 200, percent: 20 },
+					{ name: '浏览4', value: 50, percent: 10 },
+					{ name: '浏览5', value: 20, percent: 8 },
+				],
+			},
+		],
+	};
+};
+const ruleFormRef = ref<RefType>(); // 表单ref
 /** 搜索按钮操作 */
 const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
@@ -124,11 +308,67 @@ const handleQuery = () => {
 // 获取列表
 const queryList = () => {
 	state.loading = true;
-	getEarlyPushList(state.queryParams)
+	const params = {
+		...state.queryParams,
+		StartTime: dayjs(monthValue.value).startOf('month').format('YYYY-MM-DD[T]HH:mm:ss'), // 获取当月的开始时间
+		EndTime: dayjs(monthValue.value).endOf('month').format('YYYY-MM-DD[T]HH:mm:ss'), // 获取当月的结束时间
+	};
+	getEarlyPushList(params)
 		.then((res) => {
 			state.loading = false;
 			state.tableData = res.result.items ?? [];
 			state.total = res.result.total ?? 0;
+			const legendData = ['一级', '二级', '三级', '四级'];
+			const seriesData = [
+				{
+					name: '一级',
+					type: 'line',
+					data: [5, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 5, 3, 5, 6, 7, 2, 1, 2, 4, 4, 7, 1, 2, 2, 21, 1, 2, 4, 1, 7],
+					areaStyle: {
+						// 区域填充样式
+						color: '#BADEFF', // 填充颜色
+					},
+					smooth: true,
+				},
+				{
+					name: '二级',
+					type: 'line',
+					data: [8, 23, 3, 2, 7, 2, 6, 2, 2, 8, 0, 1, 5, 3, 5, 6, 7, 4, 1, 2, 4, 2, 7, 1, 2, 2, 21, 2, 2, 4, 1], // 随机数
+					areaStyle: {
+						// 区域填充样式
+						color: '#C1EDCE', // 填充颜色
+					},
+					smooth: true,
+				},
+				{
+					name: '三级',
+					type: 'line',
+					data: [12, 1, 5, 1, 7, 3, 6, 4, 3, 8, 0, 1, 4, 3, 5, 6, 7, 5, 1, 2, 4, 1, 7, 1, 2, 2, 3, 6, 2, 4, 1], // 随机数],
+					areaStyle: {
+						// 区域填充样式
+						color: '#FBECB8', // 填充颜色
+					},
+					smooth: true,
+				},
+				{
+					name: '四级',
+					type: 'line',
+					data: [5, 23, 3, 4, 4, 5, 6, 4, 2, 8, 0, 1, 2, 3, 5, 6, 7, 1, 1, 2, 4, 4, 7, 1, 2, 2, 21, 4, 2, 4, 3], // 随机数
+					areaStyle: {
+						// 区域填充样式
+						color: '#BDC2D5', // 填充颜色
+					},
+					smooth: true,
+				},
+			];
+			setOption(legendData, seriesData);
+			setOption1(legendData, [
+				{ value: 335, name: '一级' },
+				{ value: 310, name: '二级' },
+				{ value: 234, name: '三级' },
+				{ value: 135, name: '四级' },
+			]);
+			setOption2();
 		})
 		.finally(() => {
 			state.loading = false;