Vue+C#根据配置文件实现动态构建查询条件和动态表格

目录

前端

动态表格的Vue-DynamicTable.Vue

查询条件及表格字段的配置文件

项目区分测试环境和正式环境

还有测试环境

后端

通用控制器-UniversalController

某个表的业务逻辑层(BLL)

某个表的数据访问层(DAL)

某个表的模型(Model)

某个表的表类型


前端

动态表格的Vue-DynamicTable.Vue

html 复制代码
<template>
	<!-- 动态查询和动态表格 -->
	<!-- 10px 20px 20px -->
	<div class="dynamic-table" style="padding: ;">
		<!-- 面包屑 -->
		<el-breadcrumb separator="/">
			<el-breadcrumb-item :to="{ path: '/admin' }">首页</el-breadcrumb-item>
			<el-breadcrumb-item>数据查询</el-breadcrumb-item>
			<el-breadcrumb-item>{{config.description}}</el-breadcrumb-item>
		</el-breadcrumb>

		<!-- 查询条件 -->
		<el-card class="search-card">
			<el-form :model="queryForm" inline>
				<el-form-item v-for="field in config.queryFields" :key="field.prop" :label="field.label">
					<el-input v-if="field.type === 'input'" v-model="queryForm[field.prop]"
						:placeholder="field.placeholder || '请输入'" clearable />
					<el-select v-else-if="field.type === 'select'" v-model="queryForm[field.prop]"
						:placeholder="field.placeholder || '请选择'" clearable style="width: 200px">
						<el-option v-for="opt in field.options" :key="opt.value" :label="opt.label"
							:value="opt.value" />
					</el-select>
					<el-date-picker v-else-if="field.type === 'date'" v-model="queryForm[field.prop]" type="date"
						:placeholder="field.placeholder || '选择日期'" value-format="YYYY-MM-DD" />
				</el-form-item>
				<el-form-item>
					<el-button type="primary" @click="query">查询</el-button>
					<el-button @click="resetQuery">重置</el-button>
				</el-form-item>
			</el-form>
		</el-card>

		<el-card>
			<!-- 操作按钮 -->
			<div style="margin: 15px 0;">
				<el-button type="danger" :disabled="selectedRows.length === 0" @click="batchDelete">
					批量删除({{ selectedRows.length }})
				</el-button>
			</div>
			<el-table ref="tableRef" :data="pagedData" style="width: 100%" v-loading="loading" row-key="id"
				:row-class-name="getRowClass" @selection-change="handleSelectionChange" max-height="500">
				<!-- 多选列 添加 reserve-selection 保留跨页选择-->
				<el-table-column type="selection" width="55" :reserve-selection="true" />
				<!-- 数据列 -->
				<el-table-column v-for="col in config.tableColumns" :key="col.prop" :prop="col.prop" :label="col.label"
					:width="col.width" :min-width="col.minWidth || 120" show-overflow-tooltip>
					<template #default="{ row }" v-if="col.formatter">
						{{ col.formatter(row[col.prop], row) }}
					</template>
				</el-table-column>
				<!-- 删除操作列 -->
				<el-table-column label="操作" width="100" fixed="right" align="center">
					<template #default="{ row }">
						<el-button type="danger" link size="large" @click="deleteRow(row)">
							删除
						</el-button>
					</template>
				</el-table-column>
			</el-table>

			<!-- 分页 -->
			<div style="margin-top: 15px; display: flex; justify-content: flex-end;">
				<el-pagination :current-page="page" :page-size="pageSize" :page-sizes="[10, 20, 50, 100]"
					:total="tableData.length" layout="total, sizes, prev, pager, next, jumper"
					@size-change="handleSizeChange" @current-change="handleCurrentChange" />
			</div>
		</el-card>
	</div>

</template>

<script setup lang="ts">
	import { ref, reactive, onMounted, computed } from 'vue'
	import { ElMessage, ElMessageBox } from 'element-plus'
	import axios from 'axios'
	import { useEnvironment } from '@/tools/useEnvironment.js' //引入我们的环境变量

	//表格引用
	const tableRef = ref()

	//props
	const props = defineProps({
		config: {
			type: Object,
			required: true
		}
	})

	// ✅ 关键修复:使用 computed 缓存分页数据
	const pagedData = computed(() => {
		const start = (page.value - 1) * pageSize.value
		const end = page.value * pageSize.value
		return tableData.value.slice(start, end)
	})
	//环境变量对象
	const env = reactive({
		VITE_ENV: '',
		baseUrl: ''
	})

	// 响应式数据
	const queryForm = reactive({}) //查询表单
	const tableData = ref([]) //表格数据

	const selectedRows = ref([])
	const loading = ref(false)
	const page = ref(1)
	const pageSize = ref(20)

	// 根据行数据判断是否选中,返回对应 class
	const getRowClass = ({ row }) => {
		const isSelected = selectedRows.value.some(item => item.id === row.id)
		return isSelected ? 'selected-row' : ''
	}

	//组件挂载时调用
	onMounted(() => {
		console.log('组件挂载 - 说明重新加载了')
		//获取环境变量
		const { VITE_ENV, baseUrl } = useEnvironment()
		env.VITE_ENV = VITE_ENV.value
		env.baseUrl = baseUrl.value
		//初始化查询条件
		props.config.queryFields.forEach(field => {
			queryForm[field.prop] = field.defaultValue || ''
		})
		loadData()
	});

	// 加载数据
	const loadData = () => {
		tableRef.value.clearSelection()  // 清空表格选中状态 // selectedRows 会自动通过 selection-change 事件被清空

		axios.post(`${env.baseUrl}/Universal/list?tableName=` + props.config.api)
			.then(response => {
				if (response.status == 200 && response.data.code == 'S') {
					let data = JSON.parse(response.data.data)
					tableData.value = data
				}
				else {
					console.log(response)
					tableData.value = []
					ElMessage.error('获取失败!')
				}
			}).catch(error => {
				if (error.response != undefined && error.response.data.msg != null && error.response.data.msg != undefined) {
					ElMessage.error('获取失败。' + error.response.data.msg)
				}
				else {
					ElMessage.error('获取失败。' + error.message)
				}
			})
	}

	//page-size 改变时触发
	const handleSizeChange = (newSize) => {
		pageSize.value = newSize;
	}

	//current-page 改变时触发
	const handleCurrentChange = (newPage) => {
		page.value = newPage;
	}

	// 选择变化
	const handleSelectionChange = (rows) => {
		selectedRows.value = rows
	}

	//重置数据
	const resetQuery = () => {
		//初始化查询条件
		props.config.queryFields.forEach(field => {
			queryForm[field.prop] = field.defaultValue || ''
		})
		page.value = 1 //返回第一页
		loadData()
	}

	// 删除单行
	const deleteRow = async (row) => {
		try {
			const isSelected = selectedRows.value.some(item => item.id === row.id)
			if (isSelected) {
				await ElMessageBox.confirm(`确认删除该记录?`, '提示', {
					type: 'warning',
					confirmButtonText: '确定',
					cancelButtonText: '取消'
				})
				axios.delete(`${env.baseUrl}/Universal?tableName=` + props.config.api, {
					data: JSON.stringify([row]),  // ← 放这里!
					headers: { 'Content-Type': 'application/json' }
				}).then(response => {
					if (response.status == 200 && response.data.code == 'S') {
						loadData()
						ElMessage.success(response.data.msg)
					}
					else {
						console.log(response)
						loadData()
						ElMessage.error('删除失败!' + response.data.msg)
					}
				}).catch(error => {
					if (error.response != undefined && error.response.data.msg != null && error.response.data.msg != undefined) {
						ElMessage.error('获取失败。' + error.response.data.msg)
					}
					else {
						ElMessage.error('获取失败。' + error.message)
					}
					loadData()
				})
			} else {
				ElMessage.error('没有选中,无法删除')
			}
		} catch {
			// 取消删除
		}
	}

	// 批量删除
	const batchDelete = async () => {
		const ids = selectedRows.value.map(r => r.id)
		try {
			await ElMessageBox.confirm(`确认删除选中的 ${ids.length} 条记录?`, '提示', {
				type: 'warning',
				confirmButtonText: '确定',
				cancelButtonText: '取消'
			})
			axios.delete(`${env.baseUrl}/Universal?tableName=` + props.config.api, {
				data: JSON.stringify(selectedRows.value),  // ← 放这里!
				headers: { 'Content-Type': 'application/json' }
			}).then(response => {
				if (response.status == 200 && response.data.code == 'S') {
					ElMessage.success('批量删除成功')
					loadData()
				}
				else {
					ElMessage.error('删除失败!' + response.data.msg)
					loadData()
				}
			}).catch(error => {
				if (error.response != undefined && error.response.data.msg != null && error.response.data.msg != undefined) {
					ElMessage.error('获取失败。' + error.response.data.msg)
				}
				else {
					ElMessage.error('获取失败。' + error.message)
				}
				loadData()
			})

		} catch {
			// 取消
		}
	}

	//模糊查询
	const query = () => {
		axios.post(`${env.baseUrl}/Universal/FuzzyQuery?tableName=` + props.config.api, JSON.stringify(queryForm),
			{
				headers: {
					'Content-Type': 'application/json'
				}
			},)
			.then(response => {
				if (response.status == 200 && response.data.code == 'S') {
					let data = JSON.parse(response.data.data)
					tableData.value = data
					ElMessage.success(response.data.msg)
				}
				else {
					tableData.value = []
					ElMessage.error('查询失败!')
				}
			}).catch(error => {
				if (error.response != undefined && error.response.data.msg != null && error.response.data.msg != undefined) {
					ElMessage.error('查询失败。' + error.response.data.msg)
				}
				else {
					ElMessage.error('查询失败。' + error.message)
				}
			})
	}
</script>

<style scoped>
	.search-card {
		margin-top: 20px;
		margin-bottom: 10px;
	}

	/* 穿透到子组件 */
	:deep(.el-form-item) {
		margin-bottom: 10px;
	}

	/* 选中行的背景色 */
	:deep(.selected-row) {
		background-color: #e6f7ff !important;
		/* 浅蓝色 */
	}

	/* 隐藏表头中的全选复选框 */
	:deep(.el-table__header-wrapper .el-checkbox) {
		display: none;
	}
</style>

查询条件及表格字段的配置文件

javascript 复制代码
// 表查询的配置文件,所有的数据查询界面的查询字段和表格字段都是从这里配置的

export const tableQueryConfig = {
	//我司交付车型终端销量情况
	dvt: {
	    api: 'dvt',
		description: '我司交付车型终端销量情况',
	    queryFields: [
			{ prop: 'carmaker', label: '车企', type: 'input', placeholder: '请输入车企' },
			{ prop: 'car_model', label: '车型', type: 'input', placeholder: '请输入车型' },
			{ prop: 'hs_proj_num', label: 'HS项目号', type: 'input', placeholder: '请输入HS项目号' },
	    ],
	    tableColumns: [
			{prop:'id',label:'ID'},
			{ prop: 'carmaker', label: '车企', width: 120 },
			{ prop: 'car_model', label: '车型' },
			{ prop: 'hs_proj_num', label: 'HS项目号' },
			{ prop: '‌customer_proj_num‌', label: '客户项目号' },
	    ],
	},
	
	//不同级别乘用车批售量
	dgpvw: {
	    api: 'dgpvw',
		description: '不同级别乘用车批售量',
	    queryFields: [
			{ prop: 'date', label: '日期', type: 'input', placeholder: '请输入日期' },
			{ prop: 'sale_class', label: '销量级', type: 'input', placeholder: '请输入销量级' },
	    ],
	    tableColumns: [
			{prop:'id',label:'ID'},
			{ prop: 'date', label: '日期' },
			{ prop: 'sale_class', label: '销量级' },
			{ prop: 'vehicle_wholesale', label: '乘用车批售量' },
	    ],
	},
	
	//新能源乘用车市场销量表现不同价格段零售量
	npvmr: {
	    api: 'npvmr',
		description: '新能源乘用车市场销量表现不同价格段零售量',
	    queryFields: [
			{ prop: 'pv_year', label: '年份', type: 'input', placeholder: '请输入年份' },
			{ prop: 'pv_month', label: '月份', type: 'input', placeholder: '请输入月份' },
			{ prop: 'price_range', label: '价格段', type: 'input', placeholder: '请输入价格段' },
	    ],
	    tableColumns: [
			{prop:'id',label:'ID'},
			{ prop: 'pv_year', label: '年份' },
			{ prop: 'pv_month', label: '月份' },
			{ prop: 'price_range', label: '价格段' },
			{ prop: 'retail', label: '零售量' },
	    ],
	},
	
	
	//乘用车市场不同价格段零售量
	pvmr: {
	    api: 'pvmr',
		description: '乘用车市场不同价格段零售量',
	    queryFields: [
			{ prop: 'date', label: '日期', type: 'input', placeholder: '请输入日期' },
			{ prop: 'car_model', label: '车型', type: 'input', placeholder: '请输入月份' },
			{ prop: 'price_range', label: '价格段', type: 'input', placeholder: '请输入价格段' },
	    ],
	    tableColumns: [
			{ prop:'id',label:'ID'},
			{ prop: 'date', label: '日期' },
			{ prop: 'car_model', label: '车型' },
			{ prop: 'price_range', label: '价格段' },
			{ prop: 'retail', label: '零售量' },
	    ],
	},
	
	
	//泰国(TAIA)市场销量
	Thai: {
	    api: 'Thai',
		description: '泰国(TAIA)市场销量',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' }
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'elec_car_registration', label: 'BEV电动汽车注册量(Autoliv)' },
	        { prop: 'Thai_new_registration', label: '泰国新车总注册量' },
	        { prop: 'pas_car_production', label: '乘用车产量' },
	        { prop: 'pas_car_domestic', label: '乘用车国内销量' },
	        { prop: 'commercial_car_production', label: '商用车产量' },
	        { prop: 'commercial_car_domestic', label: '商用车国内销量' },
	        { prop: 'total_car_production', label: '汽车总产量(FTI)' },
	        { prop: 'BEVcar_sale', label: 'BEV乘用车销量(FTI)' },
	        { prop: 'PHEVcar_sale', label: 'PHEV乘用车销量(FTI)' },
	        { prop: 'domestic_car_totalsale', label: '国内汽车总销量(FTI)' },
	        { prop: 'permeability', label: '渗透率' },
	    ],
	},
	
	//印度尼西亚(GAIKINDO)市场销量
	Indonesia: {
	    api: 'Indonesia',
		description: '印度尼西亚(GAIKINDO)市场销量',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'BEV_production', label: 'BEV产量' },
	        { prop: 'PHEV_production', label: 'PHEV产量' },
	        { prop: 'vehicle_production', label: 'Vehicle产量' },
	        { prop: 'BEV_sale', label: 'BEV销量' },
	        { prop: 'PHEV_sale', label: 'PHEV销量' },
	        { prop: 'vehicle_wholesale', label: 'Vehicle批售量' },
	        { prop: 'BEV_PHEV_wholesale', label: '新能源(BEV+PHEV)批售量' },
	        { prop: 'permeability_product', label: '渗透率-产量' },
	        { prop: 'permeability_sale', label: '渗透率-销量' },
	    ],
	},
	
	//越南(VAMA)市场销量
	Vietnam: {
	    api: 'Vietnam',
		description: '越南(VAMA)市场销量',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'newcar_total_sale', label: '新车总销量(不含Vinfast)' },
	        { prop: 'passenger_car', label: '乘用车' },
	        { prop: 'commercial_car', label: '商用车' },
	        { prop: 'special_vehicle', label: '专用车' },
	        { prop: 'hybrid_vehicle', label: '混动车' },
	        { prop: 'Vinfast', label: 'Vinfast' },
	    ],
	},
	
	
	//马来西亚(MAA)市场销量
	Malaysia: {
	    api: 'Malaysia',
		description: '马来西亚(MAA)市场销量',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'BEVcar_sale', label: 'BEV汽车销量' },
	        { prop: 'passenger_car_sale', label: '乘用车销量' },
	        { prop: 'newcar_sale', label: '新车销量' },
	        { prop: 'permeability', label: '渗透率' },
	    ],
	},
	
	//欧洲新能源汽车市场情况
	EU: {
	    api: 'EU',
		description: '欧洲新能源汽车市场情况',
	    queryFields: [
	        { prop: 'date', label: '日期', type: 'input', placeholder: '请输入日期' },
	        { prop: 'country', label: '国家', type: 'input', placeholder: '请输入国家' },
	        { prop: 'indicator_name', label: '指标名称', type: 'input', placeholder: '请输入指标名称' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'date', label: '日期' },
	        { prop: 'country', label: '国家' },
	        { prop: 'indicator_name', label: '指标名称' },
	        { prop: 'indicator_number', label: '指标数值' },
	    ],
	},
	
	
	//新能源汽车月度单台平均装车电量
	nma: {
	    api: 'nma',
		description: '新能源汽车月度单台平均装车电量',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	        { prop: 'car_model', label: '车型', type: 'input', placeholder: '请输入车型' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'car_model', label: '车型' },
	        { prop: 'average_electricity', label: '单台平均装车电量(kWh)' },
	    ],
	},
	
	//纯电动乘用车续航里程
	per: {
	    api: 'per',
		description: '纯电动乘用车续航里程',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	        { prop: 'pv_range', label: '乘用车续航里程', type: 'input', placeholder: '请输入乘用车续航里程' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'pv_range', label: '乘用车续航里程' },
	        { prop: 'proportion', label: '占比' },
	    ],
	},

	//国内动力电池企业装车量市场分析
	dbl: {
	    api: 'dbl',
		description: '国内动力电池企业装车量市场分析',
	    queryFields: [
	        { prop: 'year_month', label: '年月', type: 'input', placeholder: '请输入年月' },
	        { prop: 'company', label: '企业名称', type: 'input', placeholder: '请输入企业名称' },
	    ],
	    tableColumns: [
	        { prop: 'id', label: 'ID' },
	        { prop: 'year_month', label: '年月' },
	        { prop: 'company', label: '企业名称' },
	        { prop: 'loading_volume', label: '装车量(Gkh)' },
	        { prop: 'proportion', label: '占比' },
	    ],
	},
	
}

项目区分测试环境和正式环境

VITE_ENV = 'development'

VITE_API_URL = 'https://localhost:7235'

还有测试环境

VITE_ENV = 'test'

VITE_API_URL = 'https://192.168.3.227:44333'

javascript 复制代码
import {
	ref
} from "vue";

const baseUrl = ref('') //请求地址
const VITE_ENV = ref('') //环境
export function useEnvironment() {
	// 判断环境
	if (import.meta.env.VITE_ENV === 'development') {
		VITE_ENV.value = import.meta.env.VITE_ENV
		baseUrl.value = import.meta.env.VITE_API_URL
	} else if (import.meta.env.VITE_ENV === 'test') {
		VITE_ENV.value = import.meta.env.VITE_ENV
		baseUrl.value = import.meta.env.VITE_API_URL
	} else {
		VITE_ENV.value = import.meta.env.VITE_ENV
		baseUrl.value = import.meta.env.VITE_API_URL
	}
	return {
		VITE_ENV,
		baseUrl
	}
}

后端

通用控制器-UniversalController

cs 复制代码
using HS_Marketing_Department_BI_Backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Text.Json;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace HS_Marketing_Department_BI_Backend.Controllers
{
    /// <summary>
    /// 通用控制器(动态表的查询和删除)
    /// </summary>
    [Route("[controller]")]
    [ApiController]
    public class UniversalController : ControllerBase
    {
        //日志
        private readonly ILogger<UniversalController> _logger;

        public UniversalController(ILogger<UniversalController> logger)
        {
            _logger = logger;
        }

        // 表名简称和全称的映射表。前端简称 → 真实表名
        private static readonly Dictionary<string, string> TableMap = new()
        {
            ["dvt"] = "delivery_vehicle_terminal",      // 我司交付车型终端销量情况
            ["dgpvw"] = "difgrad_pv_wholesale",         // 不同级别乘用车批售量
            ["npvmr"] = "NEPV_MS_retail",               // 新能源乘用车市场销量表现不同价格段零售量
            ["pvmr"] = "PV_market_retail",              // 乘用车市场不同价格段零售量
            ["Thai"] = "Thai_sales_volume",             // 泰国(TAIA)市场销量
            ["Indonesia"] = "Indonesia_sales_volume",   // 印度尼西亚(GAIKINDO)市场销量
            ["Vietnam"] = "Vietnam_sales_volume",       // 越南(VAMA)市场销量
            ["Malaysia"] = "Malaysia_sales_volume",     // 马来西亚(MAA)市场销量
            ["EU"] = "EU_NEV_Market",                   // 欧洲新能源汽车市场情况
            ["nma"] = "new_monthly_average",            // 新能源汽车月度单台平均装车电量
            ["per"] = "pure_elec_range",                // 纯电动乘用车续航里程
            ["dbl"] = "domestic_battery_loading"        // 国内动力电池企业装车量市场分析
        };

        /// <summary>
        /// 获取列表,全部查询:/Universal/list?tableName=dvt
        /// </summary>
        /// <param name="tableName">表名(简称)</param>
        /// <returns></returns>
        [HttpPost("list")]
        public IActionResult GetList([FromQuery] string tableName)
        {
            // bll类的命名空间
            string currentNamespace = "HS_Marketing_Department_BI_Backend.Models";
            try
            {
                // 1. 简称转全名
                if (!TableMap.ContainsKey(tableName))
                    return BadRequest($"未知表别名: {tableName}");
                var fullName = TableMap[tableName];  // "dvt" → "delivery_vehicle_terminal"

                // 2. 直接 new 创建BLL实例(不用DI!)
                var bllType = Type.GetType($"{currentNamespace}.{fullName}_BLL");
                if (bllType == null) 
                    return BadRequest($"表{tableName}的BLL不存在");
                var bll = Activator.CreateInstance(bllType);  // ← 相当于 new XXX_BLL()

                // 3、查询BLL的GetList方法
                var getListMethod = bllType.GetMethod("GetList");

                // 4. 调用方法,object result = method.Invoke(instance, new object[] { 参数1, 参数2 });
                object result = getListMethod.Invoke(bll, new object[] { });

                // 安全转换,失败返回 null 不报错
                ReturnData returnData = result as ReturnData;
                string return_json;

                if (returnData == null)
                {
                    return BadRequest("返回类型不是 ReturnData");
                }
                return_json = JsonConvert.SerializeObject(returnData);
                _logger.LogInformation(return_json);
                return Ok(new { code = returnData.code, msg = returnData.msg, data = returnData.data });
            }
            catch (Exception ex)
            {
                _logger.LogError(Convert.ToString(ex));
                return BadRequest(ex);
                throw;
            }
        }


        /// <summary>
        /// 模糊查询
        /// </summary>
        /// <param name="tableName">表名(简称)</param>
        /// <param name="whereJson">where查询条件的json</param>
        /// <example>请求体:{"carmaker":"car","car_model":"22342","hs_proj_num":"hs"}</example>
        /// <returns></returns>
        [HttpPost("FuzzyQuery")]
        public IActionResult FuzzyQuery([FromQuery] string tableName, [FromBody] JsonElement whereJson)
        {
            // bll类的命名空间
            string currentNamespace = "HS_Marketing_Department_BI_Backend.Models";
            try
            {
                // 1. 简称转全名
                if (!TableMap.ContainsKey(tableName))
                    return BadRequest($"未知表别名: {tableName}");
                var fullName = TableMap[tableName];  // "dvt" → "delivery_vehicle_terminal"

                // 2. 直接 new 创建BLL实例(不用DI!)
                var bllType = Type.GetType($"{currentNamespace}.{fullName}_BLL");
                if (bllType == null)
                    return BadRequest($"表{tableName}的BLL不存在");
                var bll = Activator.CreateInstance(bllType);  // ← 相当于 new XXX_BLL()

                // 3、查询BLL的FuzzyQuery方法
                var getListMethod = bllType.GetMethod("FuzzyQuery");

                // 4. 调用方法,object result = method.Invoke(instance, new object[] { 参数1, 参数2 });
                object result = getListMethod.Invoke(bll, new object[] { whereJson });

                // 安全转换,失败返回 null 不报错
                ReturnData returnData = result as ReturnData;
                string return_json;

                if (returnData == null)
                {
                    return BadRequest("返回类型不是 ReturnData");
                }
                return_json = JsonConvert.SerializeObject(returnData);
                _logger.LogInformation(return_json);
                return Ok(new { code = returnData.code, msg = returnData.msg, data = returnData.data });
            }
            catch (Exception ex)
            {
                _logger.LogError(Convert.ToString(ex));
                return BadRequest(ex);
                throw;
            }
        }


        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="tableData"></param>
        /// <example>请求体:[{"id":28,"carmaker":"car","car_model":"hs","hs_proj_num":"cu"}]</example>
        [HttpDelete]
        public IActionResult Delete([FromQuery] string tableName, [FromBody] JsonElement tableData)
        {
            // bll类的命名空间
            string currentNamespace = "HS_Marketing_Department_BI_Backend.Models";
            try
            {
                // 1. 简称转全名
                if (!TableMap.ContainsKey(tableName))
                    return BadRequest($"未知表别名: {tableName}");
                var fullName = TableMap[tableName];  // "dvt" → "delivery_vehicle_terminal"

                // 2. 直接 new 创建BLL实例(不用DI!)
                var bllType = Type.GetType($"{currentNamespace}.{fullName}_BLL");
                if (bllType == null)
                    return BadRequest($"表{tableName}的BLL不存在");
                var bll = Activator.CreateInstance(bllType);  // ← 相当于 new XXX_BLL()

                // 3、查询BLL的Delete方法
                var getListMethod = bllType.GetMethod("Delete");

                // 4. 调用方法,object result = method.Invoke(instance, new object[] { 参数1, 参数2 });
                object result = getListMethod.Invoke(bll, new object[] { tableData });

                // 安全转换,失败返回 null 不报错
                ReturnData returnData = result as ReturnData;
                string return_json;

                if (returnData == null)
                {
                    return BadRequest("返回类型不是 ReturnData");
                }
                return_json = JsonConvert.SerializeObject(returnData);
                _logger.LogInformation(return_json);
                return Ok(new { code = returnData.code, msg = returnData.msg, data = returnData.data });
            }
            catch (Exception ex)
            {
                _logger.LogError(Convert.ToString(ex));
                return BadRequest(ex);
                throw;
            }
        }
    }

}

某个表的业务逻辑层(BLL)

cs 复制代码
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;
using System.Text.Json;

namespace HS_Marketing_Department_BI_Backend.Models
{
    /// <summary>
    /// 我司交付车型终端销量情况的业务逻辑层
    /// </summary>
    public class delivery_vehicle_terminal_BLL
    {
        /// <summary>
        /// 保存文件
        /// </summary>
        /// <param name="objArray"></param>
        /// <returns></returns>
        public static ReturnData SaveTable(dynamic objArray)
        {
            delivery_vehicle_terminal_Table delivery_Vehicle_TerminalTable = new delivery_vehicle_terminal_Table();
            // 转换为JArray
            JArray jArray = JsonConvert.DeserializeObject<JArray>(Convert.ToString(objArray));
            foreach (JObject item in jArray)
            {
                DataRow dr = delivery_Vehicle_TerminalTable.NewRow();
                //遍历所有字段(适合字段不固定)
                foreach (var property in item.Properties())
                {
                    // 获取列的数据类型
                    Type columnType = dr.Table.Columns[property.Name].DataType;
                    //列的值
                    JToken token = property.Value;
                    //列的名称
                    string colName = property.Name; 

                    //处理null
                    if (token == null || token.Type == JTokenType.Null)
                    {
                        //如果是字符型
                        if (columnType == typeof(string) )
                        {
                            dr[colName] = string.Empty;
                        }
                        else
                        {
                            //动态创建类型的实例
                            dr[colName] =  Activator.CreateInstance(columnType);
                        }
                        continue;
                    }

                    // 数值型统一处理
                    if (IsNumericType(columnType))
                    {
                        dr[colName] = Convert.ChangeType(token.ToObject<object>(), columnType);
                    }
                    else
                    {
                        dr[colName] = token.ToObject(columnType);
                    }
                    
                }
                delivery_Vehicle_TerminalTable.Rows.Add(dr);
            }

            return delivery_vehicle_terminal_DAL.SaveTable(delivery_Vehicle_TerminalTable);
        }

        /// <summary>
        /// 获取列表,全部查询
        /// </summary>
        /// <returns></returns>

        public static ReturnData GetList()
        {
            return delivery_vehicle_terminal_DAL.GetList();
        }

        /// <summary>
        /// 模糊查询
        /// </summary>
        /// <returns></returns>
        public static ReturnData FuzzyQuery(JsonElement whereJson)
        {
            return delivery_vehicle_terminal_DAL.FuzzyQuery(whereJson);
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="tableData"></param>
        /// <returns></returns>
        public static ReturnData Delete(JsonElement tableData)
        {
            delivery_vehicle_terminal_Table delivery_Vehicle_TerminalTable = new delivery_vehicle_terminal_Table();
            // 转换为JArray
            JArray jArray = JsonConvert.DeserializeObject<JArray>(tableData.GetRawText());
            foreach (JObject item in jArray)
            {
                DataRow dr = delivery_Vehicle_TerminalTable.NewRow();
                //遍历所有字段(适合字段不固定)
                foreach (var property in item.Properties())
                {
                    dr[property.Name] = property.Value?.ToString() ?? string.Empty;
                }
                delivery_Vehicle_TerminalTable.Rows.Add(dr);
            }
            return delivery_vehicle_terminal_DAL.Delete(delivery_Vehicle_TerminalTable);
        }


        // 辅助方法:判断是否为数值类型
        private static bool IsNumericType(Type type)
        {
            return type == typeof(int) ||
                   type == typeof(long) ||
                   type == typeof(short) ||
                   type == typeof(byte) ||
                   type == typeof(float) ||
                   type == typeof(double) ||
                   type == typeof(decimal) ||
                   type == typeof(uint) ||
                   type == typeof(ulong) ||
                   type == typeof(ushort) ||
                   type == typeof(sbyte) ||
                   (type != null && type.IsEnum); // 枚举底层也是数值
        }

    }
}

某个表的数据访问层(DAL)

cs 复制代码
using Newtonsoft.Json;
using System.Data.SqlClient;
using System.Data;
using System.Text.Json;
using System.Text;

namespace HS_Marketing_Department_BI_Backend.Models
{
    /// <summary>
    /// 我司交付车型终端销量情况的数据访问层
    /// </summary>
    public class delivery_vehicle_terminal_DAL
    {
        /// <summary>
        /// 保存我司交付车型终端销量情况表的数据
        /// </summary>
        /// <param name="delivery_Vehicle_TerminalTable"></param>
        /// <returns></returns>
        public static ReturnData SaveTable(delivery_vehicle_terminal_Table delivery_Vehicle_TerminalTable)
        {
            string connStr = DataBaseSetting.ConnStr;
            string status;
            string infor;
            string tableStr;
            SqlConnection con = new SqlConnection(connStr);
            con.Close();
            con.Open();
            SqlCommand cmd = new SqlCommand("delivery_vehicle_terminal_OperateSP", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@delivery_vehicle_terminal_Table", SqlDbType.Structured).Value = delivery_Vehicle_TerminalTable;
            cmd.Parameters.Add("@flag", SqlDbType.Int).Value = 1;
            cmd.Parameters.Add("@status", SqlDbType.NVarChar, 10).Direction = ParameterDirection.Output;
            cmd.Parameters.Add("@infor", SqlDbType.NVarChar, 500).Direction = ParameterDirection.Output;
            cmd.ExecuteNonQuery();
            status = cmd.Parameters["@status"].Value.ToString().Trim();
            infor = cmd.Parameters["@infor"].Value.ToString().Trim();
            con.Close();
            ReturnData returnData = new ReturnData();
            returnData.code = status;
            returnData.msg = infor;
            tableStr = JsonConvert.SerializeObject(delivery_Vehicle_TerminalTable);
            returnData.data = tableStr;
            //返回
            return returnData;
        }

        /// <summary>
        /// 获取列表,全部查询
        /// </summary>
        /// <returns></returns>

        public static ReturnData GetList()
        {
            ReturnData returnData = new ReturnData();
            string connStr = DataBaseSetting.ConnStr;
            string sqlStr; //sql字符串
            DataSet ds = new DataSet();
            sqlStr = "SELECT top 2000 id,carmaker,car_model,hs_proj_num ,customer_proj_num FROM delivery_vehicle_terminal";
            using (SqlConnection con = new SqlConnection(connStr))
            {
                using (SqlDataAdapter command = new SqlDataAdapter(sqlStr, con))
                {
                    try
                    {
                        con.Open();
                        command.Fill(ds, "ds");
                    }
                    catch (SqlException ex)
                    {
                        con.Close();
                        throw new Exception(ex.Message);
                    }
                }
            }
            if (ds.Tables[0].Rows.Count != 0)
            {
                returnData.code = "S";
                returnData.msg = "获取成功";
                returnData.data = JsonConvert.SerializeObject(ds.Tables[0]);
            }
            else
            {
                returnData.code = "E";
                returnData.msg = "获取失败";
            }
            return returnData;
        }



        /// <summary>
        /// 模糊查询
        /// </summary>
        /// <returns></returns>
        public static ReturnData FuzzyQuery(JsonElement whereJson)
        {
            ReturnData returnData = new ReturnData();
            string connStr = DataBaseSetting.ConnStr;
            DataSet ds = new DataSet();

            //解析where子句的查询条件

            var carmaker = whereJson.GetProperty("carmaker").GetString();
            var car_model = whereJson.GetProperty("car_model").GetString();
            var hs_proj_num = whereJson.GetProperty("hs_proj_num").ToString();

            // 构建 SQL
            var sb = new StringBuilder("SELECT id,carmaker,car_model,hs_proj_num ,customer_proj_num FROM delivery_vehicle_terminal WHERE 1=1");

            //如果不为空,添加where条件
            if (!string.IsNullOrEmpty(carmaker))
                sb.Append(" AND carmaker LIKE @carmaker");
            if (!string.IsNullOrEmpty(car_model))
                sb.Append(" AND car_model LIKE @car_model");
            if (!string.IsNullOrEmpty(hs_proj_num))
                sb.Append(" AND hs_proj_num LIKE @hs_proj_num");

            using (SqlConnection con = new SqlConnection(connStr))
            {
                using (var cmd = new SqlCommand(sb.ToString(), con))
                {
                    try
                    {
                        con.Open();
                        // 参数化。@carmaker是参数名,$"%{carmaker}%"是值(拼接的字符串)
                        if (!string.IsNullOrEmpty(carmaker))
                            cmd.Parameters.AddWithValue("@carmaker", $"%{carmaker}%");
                        if (!string.IsNullOrEmpty(car_model))
                            cmd.Parameters.AddWithValue("@car_model", $"%{car_model}%");
                        if (!string.IsNullOrEmpty(hs_proj_num))
                            cmd.Parameters.AddWithValue("@hs_proj_num", $"%{hs_proj_num}%");
                        var adapter = new SqlDataAdapter(cmd);
                        adapter.Fill(ds);
                    }
                    catch (SqlException ex)
                    {
                        con.Close();
                        throw new Exception(ex.Message);
                    }
                }
            }
            if (ds.Tables[0].Rows.Count != 0)
            {
                returnData.code = "S";
                returnData.msg = "查询成功";
                returnData.data = JsonConvert.SerializeObject(ds.Tables[0]);
            }
            else
            {
                returnData.code = "E";
                returnData.msg = "查询失败,未查询到任何数据";
            }
            return returnData;
        }



        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="delivery_Vehicle_TerminalTable"></param>
        /// <returns></returns>
        public static ReturnData Delete(delivery_vehicle_terminal_Table delivery_Vehicle_TerminalTable)
        {
            string connStr = DataBaseSetting.ConnStr;
            string status;
            string infor;
            string tableStr;
            SqlConnection con = new SqlConnection(connStr);
            con.Close();
            con.Open();
            SqlCommand cmd = new SqlCommand("delivery_vehicle_terminal_OperateSP", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@delivery_vehicle_terminal_Table", SqlDbType.Structured).Value = delivery_Vehicle_TerminalTable;
            cmd.Parameters.Add("@flag", SqlDbType.Int).Value = 2;
            cmd.Parameters.Add("@status", SqlDbType.NVarChar, 10).Direction = ParameterDirection.Output;
            cmd.Parameters.Add("@infor", SqlDbType.NVarChar, 500).Direction = ParameterDirection.Output;
            cmd.ExecuteNonQuery();
            status = cmd.Parameters["@status"].Value.ToString().Trim();
            infor = cmd.Parameters["@infor"].Value.ToString().Trim();
            con.Close();
            ReturnData returnData = new ReturnData();
            returnData.code = status;
            returnData.msg = infor;
            tableStr = JsonConvert.SerializeObject(delivery_Vehicle_TerminalTable);
            returnData.data = tableStr;
            //返回
            return returnData;
        }
    }
}

某个表的模型(Model)

cs 复制代码
namespace HS_Marketing_Department_BI_Backend.Models
{
    /// <summary>
    /// 我司交付车型终端销量情况的模型层
    /// </summary>
    public class delivery_vehicle_terminal_Model
    {
        private int id;                     //id
        private string? carmaker‌;           //车企
        private string? car_model;          //车型
        private string? hs_proj_num;        //HS项目号
        private string? customer_proj_num;  //客户项目号

        public string? Carmaker { get => carmaker; set => carmaker = value; }
        public string? Car_model { get => car_model; set => car_model = value; }
        public string? Hs_proj_num { get => hs_proj_num; set => hs_proj_num = value; }
        public string? Customer_proj_num { get => customer_proj_num; set => customer_proj_num = value; }
        public int Id { get => id; set => id = value; }
    }
}

某个表的表类型

cs 复制代码
using System.Data;

namespace HS_Marketing_Department_BI_Backend.Models
{
    /// <summary>
    /// 我司交付车型终端销量情况表
    /// </summary>
    public class delivery_vehicle_terminal_Table : DataTable
    {
        public delivery_vehicle_terminal_Table()
        {
            Columns.Add("id", typeof(int));                     //id
            Columns.Add("carmaker", typeof(string));            //车企
            Columns.Add("car_model", typeof(string));           //车型
            Columns.Add("hs_proj_num", typeof(string));         //HS项目号
            Columns.Add("customer_proj_num", typeof(string));   //客户项目号
        }
    }
}
相关推荐
SuperEugene1 小时前
Vue3 前端配置驱动避坑:配置冗余、渲染性能、扩展性问题解决|配置驱动开发实战篇
前端·javascript·vue.js·驱动开发·前端框架
叫我黎大侠2 小时前
.NET 实战:调用千问视觉模型实现 OCR(车票识别完整教程)
阿里云·ai·c#·ocr·asp.net·.net·.netcore
唐青枫2 小时前
C#.NET ValueTaskSource 深入解析:零分配异步、ManualResetValueTaskSourceCore 与使用边界
c#·.net
小李子呢02112 小时前
前端八股---脚手架工具Vue CLI(Webpack) vs Vite
前端·vue.js·webpack
公子小六2 小时前
基于.NET的Windows窗体编程之WinForms事件简介
windows·microsoft·c#·.net
gCode Teacher 格码致知2 小时前
Javascript提高:Math.round 详解-由Deepseek产生
开发语言·javascript
织_网2 小时前
Nest.js:Node.js后端开发的现代企业级解决方案,赋能AI全栈开发
javascript·人工智能·node.js
kyriewen2 小时前
可选链 `?.`——再也不用写一长串 `&&` 了!
前端·javascript·ecmascript 6
AnalogElectronic2 小时前
html+js+css实现七龙珠神龙召唤特效
javascript·css·html