<template>
	<div class="sys-sysLogHttp-container">
		<el-card shadow="hover" :body-style="{ padding: '5px 5px 0 5px' }">
			<scEcharts v-if="echartsOption.series.data" height="200px" :option="echartsOption" @clickData="clickData"></scEcharts>
		</el-card>
		<el-card shadow="hover" :body-style="{ padding: '5px', display: 'flex', width: '100%', height: '100%', alignItems: 'start' }">
			<el-form :model="state.queryParams" ref="queryForm" :show-message="false" :inlineMessage="true" label-width="auto" style="flex: 1 1 0%">
				<el-row :gutter="10">
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="客户端" prop="httpClientName">
							<el-select v-model="state.queryParams.httpClientName" placeholder="请选择客户端" clearable @keyup.enter.native="handleQuery(true)">
								<el-option v-for="item in state.clientNameList" :key="item" :label="item" :value="item" />
							</el-select>
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="模块名" prop="actionName">
							<el-input v-model="state.queryParams.actionName" placeholder="请输入模块名" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="接口描述" prop="httpApiDesc">
							<el-input v-model="state.queryParams.httpApiDesc" placeholder="请输入接口描述" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="请求方式" prop="httpMethod">
							<el-input v-model="state.queryParams.httpMethod" placeholder="请输入请求方式" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="是否成功" prop="isSuccessStatusCode">
							<g-sys-dict v-model="state.queryParams.isSuccessStatusCode" :code="'YesNoEnum'" render-as="select" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="请求地址" prop="requestUrl">
							<el-input v-model="state.queryParams.requestUrl" placeholder="请输入请求地址" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="请求体" prop="requestBody">
							<el-input v-model="state.queryParams.requestBody" placeholder="请输入请求体" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="响应状态码" prop="statusCode">
							<el-input v-model="state.queryParams.statusCode" placeholder="请输入响应状态码" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="响应体" prop="responseBody">
							<el-input v-model="state.queryParams.responseBody" placeholder="请输入响应体" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="异常信息" prop="exception">
							<el-input v-model="state.queryParams.exception" placeholder="请输入异常信息" clearable @keyup.enter.native="handleQuery(true)" />
						</el-form-item>
					</el-col>
					<el-col class="mb5" :sm="12" :md="8" :lg="6" :xl="6">
						<el-form-item label="创建时间" prop="createTime">
							<el-date-picker
								type="daterange"
								v-model="state.queryParams.createTimeRange"
								value-format="YYYY-MM-DD HH:mm:ss"
								start-placeholder="开始日期"
								end-placeholder="结束日期"
								:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
							/>
						</el-form-item>
					</el-col>
				</el-row>
			</el-form>
			<el-divider style="height: calc(100% - 5px); margin: 0 10px" direction="vertical" />
			<el-row>
				<el-col>
					<el-button-group>
						<el-button type="primary" icon="ele-Search" @click="handleQuery(true)" v-auth="'sysLogHttp/page'"> 查询 </el-button>
						<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button>
					</el-button-group>
				</el-col>
			</el-row>
		</el-card>

		<el-card class="full-table" shadow="hover" style="margin-top: 5px">
			<vxe-grid ref="xGrid" class="xGrid-style" v-bind="options" v-on="gridEvents">
				<template #toolbar_buttons> </template>
				<template #toolbar_tools></template>
				<template #empty><el-empty :image-size="200" /></template>
				<template #row_record="{ row }"><ModifyRecord :data="row" /></template>
				<template #row_isSuccessStatusCode="{ row, $index }">
					<g-sys-dict v-model="row.isSuccessStatusCode" :code="'YesNoEnum'" />
				</template>
				<template #row_requestUrl="{ row, $index }">
					<el-button v-if="row.requestUrl" class="ml5" icon="ele-CopyDocument" text type="primary" @click="(event: any) => handleCopyUrl(event, row.requestUrl)" />
					{{ row.requestUrl }}
				</template>
				<template #row_requestBody="{ row, $index }">
					{{ row.requestBody }}
					<el-button v-if="row.requestBody" class="ml5" icon="ele-CopyDocument" text type="primary" @click="commonFun.copyText(row.requestBody?.toString())" />
				</template>
				<template #row_responseBody="{ row, $index }">
					{{ row.responseBody }}
					<el-button v-if="row.responseBody" class="ml5" icon="ele-CopyDocument" text type="primary" @click="commonFun.copyText(row.responseBody?.toString())" />
				</template>
				<template #row_exception="{ row, $index }">
					{{ row.exception }}
					<el-button v-if="row.exception" class="ml5" icon="ele-CopyDocument" text type="primary" @click="commonFun.copyText(row.exception?.toString())" />
				</template>
				<template #row_startTime="{ row, $index }">
					{{ commonFun.dateFormatYMDHMS(row, $index, row.startTime) }}
				</template>
				<template #row_endTime="{ row, $index }">
					{{ commonFun.dateFormatYMDHMS(row, $index, row.endTime) }}
				</template>
				<template #row_buttons="{ row }"> </template>
			</vxe-grid>
		</el-card>
		<logDetail ref="logDetailRef"></logDetail>
	</div>
</template>

<!-- 远程请求日志 -->
<script lang="ts" setup name="sysLogHttp">
import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
import { ElMessage } from 'element-plus';
import { Local } from '/@/utils/storage';
import { useVxeTable } from '/@/hooks/useVxeTableOptionsHook';
import { VxeGridInstance, VxeGridListeners, VxeGridPropTypes } from 'vxe-table';
import commonFunction from '/@/utils/commonFunction';
import 'vue-json-pretty/lib/styles.css';

import logDetail from './component/logDetail.vue';
import ModifyRecord from '/@/components/table/modifyRecord.vue';

import { getAPI } from '/@/utils/axios-utils';
import { SysLogHttpApi } from '/@/api-services/system/api';
import { PageLogHttpInput, PageLogHttpOutput } from '/@/api-services/system/models';

const scEcharts = defineAsyncComponent(() => import('/@/components/scEcharts/index.vue'));

const commonFun = commonFunction();
const xGrid = ref<VxeGridInstance>();
const logDetailRef = ref<InstanceType<typeof logDetail>>();
const state = reactive({
	queryParams: {} as PageLogHttpInput,
	localPageParam: {
		pageSize: 20 as number,
		defaultSort: { field: 'id', order: 'asc', descStr: 'asc' },
	},
	visible: false,
	logMaxValue: 1,
	clientNameList: [] as string[],
});
// 本地存储参数
const localPageParamKey = 'localPageParam:sysLogHttp';
// 表格参数配置
const options = useVxeTable<PageLogHttpOutput>(
	{
		id: 'sysLogHttp',
		name: '请求日志',
		columns: [
			// { type: 'checkbox', width: 40, fixed: 'left' },
			{ field: 'seq', type: 'seq', title: '序号', width: 60, fixed: 'left' },
			{ field: 'createTime', title: '创建时间', minWidth: 150, showOverflow: 'tooltip' },
			{ field: 'httpApiDesc', title: '接口描述', minWidth: 150, showOverflow: 'tooltip' },
			{ field: 'httpClientName', title: '客户端', minWidth: 110, showOverflow: 'tooltip' },
			{ field: 'actionName', title: '模块名', minWidth: 110, showOverflow: 'tooltip' },
			{ field: 'httpMethod', title: '请求方式', minWidth: 60, showOverflow: 'tooltip' },
			{ field: 'isSuccessStatusCode', title: '是否成功', minWidth: 60, showOverflow: 'tooltip', slots: { default: 'row_isSuccessStatusCode' } },
			{ field: 'requestUrl', title: '请求地址', minWidth: 150, align: 'left', showOverflow: 'tooltip', slots: { default: 'row_requestUrl' } },
			{ field: 'requestHeaders', title: '请求头', minWidth: 150, showOverflow: 'tooltip' },
			{ field: 'requestBody', title: '请求体', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_requestBody' } },
			{ field: 'statusCode', title: '响应状态码', minWidth: 70, showOverflow: 'tooltip' },
			{ field: 'responseHeaders', title: '响应头', minWidth: 150, showOverflow: 'tooltip' },
			{ field: 'responseBody', title: '响应体', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_responseBody' } },
			{ field: 'exception', title: '异常信息', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_exception' } },
			{ field: 'startTime', title: '开始时间', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_startTime' } },
			{ field: 'endTime', title: '结束时间', minWidth: 150, showOverflow: 'tooltip', slots: { default: 'row_endTime' } },
			{ field: 'elapsed', title: '耗时（毫秒）', minWidth: 90, showOverflow: 'tooltip' },
			{ field: 'createUserName', title: '创建用户', minWidth: 90, showOverflow: 'tooltip' },
		],
	},
	// vxeGrid配置参数(此处可覆写任何参数)，参考vxe-table官方文档
	{
		// 代理配置
		proxyConfig: { autoLoad: true, ajax: { query: ({ page }) => handleQueryApi(page) } },
		// 排序配置
		sortConfig: { defaultSort: Local.get(localPageParamKey)?.defaultSort || state.localPageParam.defaultSort },
		// 分页配置
		pagerConfig: { pageSize: Local.get(localPageParamKey)?.pageSize || state.localPageParam.pageSize },
		// 导入配置
		// importConfig: { remote: true, importMethod: (options: any) => handleImport(options), slots: { top: 'import_sysLogHttp' } },
		// 工具栏配置
		toolbarConfig: { import: false, export: true },
	}
);

// 页面初始化
onMounted(async () => {
	state.clientNameList = await getAPI(SysLogHttpApi)
		.apiSysLogHttpHttpClientNameGet()
		.then((res) => res.data.result ?? []);
	state.localPageParam = Local.get(localPageParamKey) || state.localPageParam;
});

// 查询api
const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams) => {
	await getYearDayStatsData();
	const params = Object.assign(state.queryParams, {
		page: page.currentPage,
		pageSize: page.pageSize,
		field: state.localPageParam.defaultSort.field,
		order: state.localPageParam.defaultSort.order,
		descStr: 'asc',
	}) as PageLogHttpInput;
	return getAPI(SysLogHttpApi).apiSysLogHttpPagePost(params);
};

// 查询操作
const handleQuery = async (reset = false) => {
	options.loading = true;
	reset ? await xGrid.value?.commitProxy('reload') : await xGrid.value?.commitProxy('query');
	options.loading = false;
};

// 复制请求地址操作
const handleCopyUrl = (event: PointerEvent, url: string) => {
	event.stopPropagation(); // 阻止事件冒泡
	commonFun.copyText(url);
};

// 重置操作
const resetQuery = async () => {
	state.queryParams.httpMethod = undefined;
	state.queryParams.isSuccessStatusCode = undefined;
	state.queryParams.requestUrl = undefined;
	state.queryParams.requestBody = undefined;
	state.queryParams.statusCode = undefined;
	state.queryParams.responseBody = undefined;
	state.queryParams.exception = undefined;
	state.queryParams.createTime = undefined;
	await xGrid.value?.commitProxy('reload');
};

// 获取主题颜色变量
const colors = ['--el-color-primary-light-9', '--el-color-primary-light-7', '--el-color-primary-light-5', '--el-color-primary-light-3', '--el-color-primary-light-1', '--el-color-primary'].map(
	(variable) => getComputedStyle(document.documentElement).getPropertyValue(variable).trim()
);
const echartsOption = ref({
	title: {
		top: 30,
		left: 'center',
		text: '日志统计',
		show: false,
	},
	tooltip: {
		formatter: function (p: any) {
			return p.data[1] + ' 数据量：' + p.data[0];
		},
	},
	visualMap: {
		show: true,
		inRange: {
			color: colors,
		},
		outOfRange: {
			color: ['#000000'],
		},
		min: 0,
		max: 1000,
		maxOpen: {
			type: 'piecewise',
		},
		type: 'piecewise',
		orient: 'horizontal',
		left: 'right',
	},
	calendar: {
		top: 30,
		left: 30,
		right: 30,
		bottom: 30,
		cellSize: ['auto', 20],
		range: ['', ''],
		splitLine: true,
		dayLabel: {
			firstDay: 1,
			nameMap: 'ZH',
		},
		itemStyle: {
			color: '#ccc',
			borderWidth: 3,
			borderColor: '#fff',
		},
		monthLabel: {
			nameMap: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
		},
		yearLabel: {
			show: false,
		},
	},
	series: {
		type: 'heatmap',
		coordinateSystem: 'calendar',
		data: [],
	},
});

const clickData = (e: any) => {
	if (e[1] < 1) return ElMessage.warning('没有日志数据');
	state.queryParams.createTimeRange = [];
	state.queryParams.createTimeRange.push(e[0]);
	var today = new Date(e[0]);
	let endTime = today.setDate(today.getDate() + 1);
	state.queryParams.createTimeRange.push(new Date(endTime));
	xGrid.value?.commitProxy('query');
};

// 获取统计日志数据
const getYearDayStatsData = async () => {
	let data = [] as any;
	var res = await getAPI(SysLogHttpApi).apiSysLogHttpYearDayStatsGet();
	res.data.result?.forEach((item: any) => {
		data.push([item.date, item.count]);

		if (item.count > state.logMaxValue) state.logMaxValue = item.count; // 计算最大值
	});
	echartsOption.value.visualMap.max = state.logMaxValue;
	echartsOption.value.series.data = data;
	echartsOption.value.calendar.range = [data[0][0], data[data.length - 1][0]];
};

// 表格事件
const gridEvents: VxeGridListeners<PageLogHttpOutput> = {
	// 只对 pager-config 配置时有效，分页发生改变时会触发该事件
	async pageChange({ pageSize }) {
		state.localPageParam.pageSize = pageSize;
		Local.set(localPageParamKey, state.localPageParam);
	},
	// 当排序条件发生变化时会触发该事件
	async sortChange({ field, order }) {
		state.localPageParam.defaultSort = { field: field, order: order!, descStr: 'desc' };
		Local.set(localPageParamKey, state.localPageParam);
	},
	cellClick({ row, column }) {
		if (['请求地址', '请求头', '请求体', '响应头', '响应体', '异常信息'].includes(column.title)) {
			logDetailRef.value?.openDialog(row);
		}
	},
};
</script>

<style lang="less" scoped></style>
