Browse Source

add 添加通用报表组件

Yue 1 month ago
parent
commit
3608f61a0b

+ 87 - 0
UI/VB.VUE/src/components/reports/VbCommonReport.vue

@@ -0,0 +1,87 @@
+<script setup lang="ts">
+import VbDataTable from "@@@/table/VbDataTable.vue"
+const props = withDefaults(
+	defineProps<{
+		columns: any[]
+		columnsFun?: () => any[]
+		width?: string | number
+		title?: string
+		cycleStr?: string
+		cycleType?: "Y" | "Q" | "M" | "D" | "W" | "ALL"
+		tableListFun: (query: any) => Promise<any>
+		genReportFun: (cycle: string) => Promise<any>
+	}>(),
+	{
+		title: "",
+		cycleStr: "",
+		cycleType: "M"
+	}
+)
+const emits = defineEmits<{
+	(e: "update:cycleStr", v: string): void
+}>()
+
+const tableRef = ref()
+const cycleType = "M"
+const cycle = ref()
+const cycleStr = ref()
+
+const queryParams = ref({
+	statCycle: cycle.value
+})
+const boxWidth = computed(() => {
+	if (typeof props.width == "number") {
+		return props.width + "px"
+	}
+	console.log("props.width", props.width)
+	return props.width || "1200px"
+})
+function handleQuery(query?: any) {
+	query = query || tableRef.value?.getQueryParams() || queryParams.value
+	query.statCycle = cycle.value
+	tableRef.value?.query(query)
+}
+
+function genReport() {
+	// 生成报表
+	props.genReportFun(cycle.value).then(() => {
+		handleQuery()
+		message.msgSuccess("生成成功")
+	})
+}
+function init() {
+	handleQuery()
+}
+onMounted(() => {
+	init()
+})
+</script>
+
+<template>
+	<div class="app-container py-5">
+		<div
+			class="w-100 d-flex flex-column align-items-center mx-auto"
+			:style="{ maxWidth: boxWidth }">
+			<div class="header d-flex justify-content-center align-items-center mb-10">
+				<VbCycleSelect
+					v-model="cycle"
+					v-model:cycleStr="cycleStr"
+					:cycle-type="cycleType"></VbCycleSelect>
+				<el-button type="primary" @click="handleQuery()">查询</el-button>
+				<el-button type="success" @click="genReport()">生成</el-button>
+			</div>
+			<h2 class="">{{ cycleStr }}{{ title }}</h2>
+			<VbDataTable
+				ref="tableRef"
+				:table-box-height="600"
+				:columns="columns"
+				:columns-fun="columnsFun"
+				:init-search="false"
+				:query-params="queryParams"
+				:custom-search-fun="handleQuery"
+				:remote-fun="tableListFun"
+				:has-checkbox="false"
+				:show-toolbar="false"></VbDataTable>
+		</div>
+	</div>
+</template>

+ 215 - 0
UI/VB.VUE/src/components/select/VbCycleSelect.vue

@@ -0,0 +1,215 @@
+<script setup lang="ts">
+import dayjs from "dayjs"
+import weekOfYear from "dayjs/plugin/weekOfYear"
+
+dayjs.extend(weekOfYear)
+
+const props = withDefaults(
+	defineProps<{
+		modelValue: string
+		cycleStr?: string
+		cycleType?: "Y" | "Q" | "M" | "D" | "W" | "ALL"
+	}>(),
+	{
+		modelValue: "",
+		cycleStr: "",
+		cycleType: "M"
+	}
+)
+const emits = defineEmits<{
+	(e: "update:modelValue", v: string): void
+	(e: "update:cycleStr", v: string): void
+}>()
+
+const cycleOptions = computed(() => {
+	const options = []
+	options.push({
+		label: `日`,
+		value: "D"
+	})
+
+	options.push({
+		label: `月`,
+		value: "M"
+	})
+	options.push({
+		label: `季`,
+		value: "Q"
+	})
+	options.push({
+		label: `年`,
+		value: "Y"
+	})
+	options.push({
+		label: `周`,
+		value: "W"
+	})
+	return options
+})
+const yearOptions = computed(() => {
+	const options = []
+	for (let i = 2024; i <= new Date().getFullYear(); i++) {
+		options.push({
+			label: i + "年",
+			value: i
+		})
+	}
+	return options
+})
+const quarterOptions = computed(() => {
+	const options = []
+	for (let i = 1; i <= 4; i++) {
+		options.push({
+			label: `第${i}季度`,
+			value: i
+		})
+	}
+	return options
+})
+const monthOptions = computed(() => {
+	const options = []
+	for (let i = 1; i <= 12; i++) {
+		options.push({
+			label: i + "月",
+			value: i
+		})
+	}
+	return options
+})
+const weekOptions = computed(() => {
+	const options = []
+	for (let i = 1; i <= 53; i++) {
+		options.push({
+			label: i + "周",
+			value: i
+		})
+	}
+	return options
+})
+const dayOptions = computed(() => {
+	const options = []
+	// 计算每月天数的函数
+	const getDaysInMonth = (year: number, month: number) => {
+		// 月份索引从0开始,所以需要减1
+		return new Date(year, month, 0).getDate()
+	}
+	const daysInMonth = getDaysInMonth(year.value, month.value)
+	for (let i = 1; i <= daysInMonth; i++) {
+		options.push({
+			label: i + "日",
+			value: i
+		})
+	}
+	return options
+})
+const defaultYear = dayjs().year()
+// 获取当前的季度quarter
+const defaultQuarter = Math.floor((new Date().getMonth() + 3) / 3)
+const defaultMonth = dayjs().month() + 1
+const defaultWeek = dayjs().week()
+const defaultDay = dayjs().date()
+
+const cycle = ref(props.cycleType == "ALL" ? "M" : props.cycleType)
+const year = ref(defaultYear)
+const quarter = ref(defaultQuarter)
+const month = ref(defaultMonth)
+const week = ref(defaultWeek)
+const day = ref(defaultDay)
+
+function onChange() {
+	nextTick(() => {
+		let val = `${year.value}`,
+			valStr = `${year.value}年`
+		if (cycle.value == "Y") {
+			val = `${year.value}`
+			valStr = `${year.value}年`
+		} else if (cycle.value == "Q") {
+			val = `${year.value}-Q${quarter.value}`
+			valStr = `${year.value}年第${quarter.value}季度`
+		} else if (cycle.value == "M") {
+			val = `${year.value}-M${month.value}`
+			valStr = `${year.value}年${month.value}月`
+		} else if (cycle.value == "D") {
+			val = `${year.value}-${month.value}-${day.value}`
+			valStr = `${year.value}年${month.value}月 ${day.value}日`
+		} else if (cycle.value == "W") {
+			val = `${year.value}-W${week.value}`
+			valStr = `${year.value}年第${week.value}周`
+		}
+		console.log("cycle", val, valStr)
+		emits("update:modelValue", val)
+		emits("update:cycleStr", valStr)
+	})
+}
+
+function init() {
+	onChange()
+}
+
+onMounted(init)
+</script>
+<template>
+	<el-form-item v-if="props.cycleType == 'ALL'" label="周期">
+		<el-select
+			v-model="cycle"
+			placeholder="请选择周期"
+			class="w-100px me-3"
+			@change="
+				() => {
+					year = defaultYear
+					onChange()
+				}
+			">
+			<el-option v-for="(v, i) in cycleOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+	<el-form-item label="年">
+		<el-select
+			v-model="year"
+			placeholder="请选择年份"
+			class="w-100px me-3"
+			@change="
+				() => {
+					month = defaultMonth
+					onChange()
+				}
+			">
+			<el-option v-for="(v, i) in yearOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+	<el-form-item v-if="cycle === 'Q'" label="季度">
+		<el-select v-model="quarter" class="w-100px me-3" placeholder="请选择季度" @change="onChange()">
+			<el-option v-for="(v, i) in quarterOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+	<el-form-item v-if="cycle === 'M' || cycle === 'D'" label="月">
+		<el-select
+			v-model="month"
+			class="w-100px me-3"
+			placeholder="请选择月份"
+			@change="
+				() => {
+					day = defaultDay
+					onChange()
+				}
+			">
+			<el-option v-for="(v, i) in monthOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+	<el-form-item v-if="cycle === 'D'" label="日">
+		<el-select v-model="day" class="w-100px me-3" placeholder="请选择日" @change="onChange()">
+			<el-option v-for="(v, i) in dayOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+	<el-form-item v-if="cycle === 'W'" label="周">
+		<el-select v-model="week" class="w-100px me-3" placeholder="请选择周" @change="onChange()">
+			<el-option v-for="(v, i) in weekOptions" :label="v.label" :value="v.value" :key="i" />
+		</el-select>
+	</el-form-item>
+</template>
+
+<style lang="scss" scoped>
+:global(.el-form-item) {
+	margin-bottom: 0 !important;
+}
+</style>