This commit is contained in:
jiangs 2026-02-10 17:36:03 +08:00
commit a91d2cda9c
5 changed files with 1232 additions and 0 deletions

View File

@ -0,0 +1,46 @@
//参数设置字典
// @ts-ignore
import request from '@/utils/request'
// 查询字典列表
export function liststatsparam(params:any) {
return request({
url: '/statstemp/param/list',
method: 'get',
params
})
}
// 查询字典详细
export function getstatsparam(id:number) {
return request({
url: `/statstemp/param/${id}`,
method: 'get'
})
}
// 新增字典
export function addstatsparam(params:any) {
return request({
url: '/statstemp/param',
method: 'post',
data:params
})
}
// 修改字典
export function updatestatsparam(params:any) {
return request({
url: '/statstemp/param',
method: 'put',
data:params
})
}
// 删除字典
export function delstatsparam(id:any) {
return request({
url: `/statstemp/param/${id}`,
method: 'delete'
})
}

View File

@ -0,0 +1,46 @@
//参数设置字典
// @ts-ignore
import request from '@/utils/request'
// 查询字典列表
export function liststatstemp(params:any) {
return request({
url: '/statstemp/list',
method: 'get',
params
})
}
// 查询字典详细
export function getstatstemp(id:number) {
return request({
url: `/statstemp/${id}`,
method: 'get'
})
}
// 新增字典
export function addstatstemp(params:any) {
return request({
url: '/statstemp',
method: 'post',
data:params
})
}
// 修改字典
export function updatestatstemp(params:any) {
return request({
url: '/statstemp',
method: 'put',
data:params
})
}
// 删除字典
export function delstatstemp(id:any) {
return request({
url: `/statstemp/${id}`,
method: 'delete'
})
}

View File

@ -181,6 +181,41 @@ export const dynamicRoutes = [{
activeMenu: '/tool/gen'
}
}]
},
// ========== 新增:统计模板主路由(若需要侧边栏显示则hidden: false) ==========
{
path: '/liswork/xtwh/statstemplate',
component: Layout,
hidden: false, // 若不需要侧边栏显示则设为true
permissions: ['liswork:xtwh:statstemplate:list'], // 替换为你的实际权限码
meta: {
title: '统计模板',
icon: 'el-icon-menu' // 可选:侧边栏图标
},
children: [
// 统计模板列表页(原页面)
{
path: '', // 空路径表示默认子路由
name: 'Statstemplate',
component: () => import('@/views/liswork/xtwh/statstemplate/index'),
meta: {
title: '模板列表',
noCache: true
}
},
// 要跳转的data页面(核心新增)
{
path: 'data',
name: 'StatstemplateData',
hidden: true, // 作为子页面,不在侧边栏单独显示
component: () => import('@/views/liswork/xtwh/statstemplate/data'),
meta: {
title: '统计模板数据',
noCache: true,
activeMenu: '/liswork/xtwh/statstemplate' // 保持侧边栏高亮父菜单
}
}
]
}
]

View File

@ -0,0 +1,568 @@
<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item :label="menuname + '类别'" prop="paramType">
<el-select
v-model="queryParams.paramType"
:placeholder="`请选择${menuname}类别`"
clearable
style="width: 200px"
@change="handleQuery"
>
<el-option
v-for="item in paramTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="menuname + '编码'" prop="paramCode">
<el-input
v-model="queryParams.paramCode"
:placeholder="`请输入${menuname}编码`"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="paramName">
<el-input
v-model="queryParams.paramName"
:placeholder="`请输入${menuname}名称`"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="状态"
clearable
style="width: 200px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<div class="table-container">
<el-table
v-loading="loading"
:data="regdictList"
@selection-change="handleSelectionChange"
class="param-table"
height="100%"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="`${menuname}编号`" align="center" prop="paramId" v-if="false" />
<el-table-column :label="`${menuname}类别`" align="center" prop="paramType" width="100" show-overflow-tooltip>
<template #default="scope">
<span>
{{ paramTypeOptions.find(item => item.value === scope.row.paramType)?.label || scope.row.paramOptiontype }}
</span>
</template>
</el-table-column>
<el-table-column :label="`${menuname}编码`" align="center" prop="paramCode" show-overflow-tooltip >
</el-table-column>
<el-table-column :label="`${menuname}名称`" align="left" prop="paramName" show-overflow-tooltip />
<el-table-column label="默认值" align="left" prop="paramDefvalue" width="80" show-overflow-tooltip />
<el-table-column label="前置条件" align="left" prop="precondition" width="100" show-overflow-tooltip />
<el-table-column label="筛选条件" align="left" prop="paramSql" width="120" show-overflow-tooltip />
<el-table-column label="筛选类型" align="left" prop="paramOptiontype" width="80" show-overflow-tooltip >
<template #default="scope">
<span>
{{ paramOptiontypeOptions.find(item => item.value === scope.row.paramOptiontype)?.label || scope.row.paramOptiontype }}
</span>
</template>
</el-table-column>
<el-table-column label="值域" align="left" prop="remark" width="100" show-overflow-tooltip />
<el-table-column label="是否隐藏" align="center" prop="paramHide" width="80" >
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.paramHide" />
</template>
</el-table-column>
<el-table-column label="表格排序" align="center" prop="paramSequence" width="80" />
<el-table-column label="排序" align="center" prop="paramSort" width="80" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="150" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 新增/修改对话框 -->
<el-dialog :title="title" v-model="open" width="700px" class="compact-dialog">
<el-form ref="statsparamRef" :model="form" :rules="rules" label-width="150px" class="compact-form">
<el-form-item :label="`${menuname}类别`" prop="paramType">
<el-select
v-model="form.paramType"
:placeholder="`请选择${menuname}类别`"
style="width: 100%"
>
<el-option
v-for="item in paramTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="`${menuname}编码`" prop="paramCode">
<el-input v-model="form.paramCode" :placeholder="`请输入${menuname}编码`" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="paramName">
<el-input v-model="form.paramName" :placeholder="`请输入${menuname}名称`" />
</el-form-item>
<el-form-item :label="`${menuname}默认值`" prop="paramDefvalue">
<el-input v-model="form.paramDefvalue" :placeholder="`请输入${menuname}默认值`" />
</el-form-item>
<el-form-item :label="`${menuname}筛选类型`" prop="paramOptiontype">
<el-select
v-model="form.paramOptiontype"
:placeholder="`请选择${menuname}筛选类型`"
style="width: 100%"
>
<el-option
v-for="item in paramOptiontypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="`${menuname}前置条件`" prop="precondition">
<el-input v-model="form.precondition" type="textarea" placeholder="请输入前置条件" :rows="2" />
</el-form-item>
<!-- 集成封装好的SQL高亮输入框组件 -->
<el-form-item :label="`${menuname}查询语句`" prop="paramSql">
<el-input v-model="form.paramSql" type="textarea" placeholder="请输入查询语句" :rows="5" />
</el-form-item>
<el-form-item label="是否隐藏" prop="paramHide">
<el-radio-group v-model="form.paramHide">
<el-radio
v-for="dict in sys_yes_no"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="表格排序" prop="paramSequence">
<el-input-number v-model="form.paramSequence" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="顺序" prop="paramSort">
<el-input-number v-model="form.paramSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="值域" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" :rows="3" />
</el-form-item>
</el-form>
<!-- 对话框底部按钮 -->
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="statsparameter">
import {
addstatsparam,
delstatsparam,
getstatsparam,
liststatsparam,
updatestatsparam
} from "@/api/liswork/xtwh/statsparameterApi.ts";
const route = useRoute();
// ========== 基础变量声明(避免提前访问) ==========
// 菜单名称
const menuname = ref("参数明细");
const statsCode = ref("1");
// 报表类别选项
const paramTypeOptions = ref([
{ label: "过滤参数", value: "0"},
{ label: "显示列", value: "1"},
{ label: "过滤+显示", value: "2"},
{ label: "汇总栏", value: "3"},
{ label: "子查询", value: "4"},
{ label: "逻辑条件", value: "5"}
]);
// 图表类型选项
const paramOptiontypeOptions = ref([
{ label: "单选框", value: "0", color: "#56BBBD" },
{ label: "下拉框", value: "1", color: "#67C23A" },
{ label: "字典单选", value: "2", color: "#FF443F" },
{ label: "字典多选", value: "3", color: "#F08784" },
{ label: "特殊", value: "4", color: "#909399" },
{ label: "文本框", value: "5", color: "#3282F6" },
{ label: "数字框", value: "6", color: "#507F80" },
{ label: "日期框", value: "7", color: "#7E84F7" },
{ label: "时间框", value: "8", color: "#377D22" },
]);
// ========== 页面状态与数据 ==========
// 获取并缓存proxy
const instance = getCurrentInstance();
const proxy = instance?.proxy || null;
// 字典数据(空值保护)
const sys_normal_disable = proxy?.useDict("sys_normal_disable")?.sys_normal_disable || [];
const sys_yes_no= proxy?.useDict("sys_yes_no")?.sys_yes_no || [];
// 表单数据
const form = ref({
statsCode:statsCode.value,
paramId: undefined,
paramCode: undefined,
paramName: undefined,
paramDefvalue: undefined,
precondition: undefined,
paramType: paramTypeOptions.value[0]?.value || "",
paramOptiontype: paramOptiontypeOptions.value[0]?.value || "",
paramSql: "", // SQL语句(绑定到SqlEditor组件)
paramSequence:0,
paramHide:"",
paramSort: 0,
status: "0",
remark: undefined
});
// 查询参数
const queryParams = ref({
statsCode: statsCode.value,
paramCode: undefined,
paramName: undefined,
paramType: undefined,
status: undefined,
pageNum: 1,
pageSize: 30
});
// 表单校验规则
const rules = ref({
statsCode: [{ required: true, message: `${menuname.value}模板不能为空`, trigger: "blur" }],
paramType: [{ required: true, message: `${menuname.value}类别不能为空`, trigger: "blur" }],
paramName: [{ required: true, message: `${menuname.value}名称不能为空`, trigger: "blur" }],
paramCode: [{ required: true, message: `${menuname.value}编码不能为空`, trigger: "blur" }],
paramSort: [{ required: true, message: `${menuname.value}顺序不能为空`, trigger: "blur" }],
});
// 页面基础状态
const regdictList = ref([]); // 表格数据列表
const open = ref(false); // 对话框显示状态
const loading = ref(true); // 加载状态
const showSearch = ref(true); // 搜索框显示状态
const ids = ref([]); // 选中的ID列表
const single = ref(true); // 是否单选
const multiple = ref(true); // 是否多选
const total = ref(0); // 总条数
const title = ref(""); // 对话框标题
// ========== 工具方法 ==========
// 获取类别颜色
function getparamTypeColor(type) {
const item = paramTypeOptions.value.find(item => item.value === type);
return item?.color || "#909399";
}
// 重置表单
function resetForm() {
form.value = {
paramId: undefined,
paramCode: undefined,
paramName: undefined,
paramDefvalue: undefined,
precondition: undefined,
paramType: paramTypeOptions.value[0]?.value || "",
paramOptiontype: paramOptiontypeOptions.value[0]?.value || "",
paramSequence:0,
paramHide:"",
statsCode:statsCode.value,
paramSql: "",
paramSort: 0,
status: "0",
remark: undefined
};
if (proxy && proxy.resetForm) {
proxy.resetForm("statsparamRef");
}
}
// ========== 核心业务方法 ==========
// 查询列表
function getList() {
loading.value = true;
const params = queryParams.value || { pageNum: 1, pageSize: 30 };
liststatsparam(params)
.then(response => {
regdictList.value = response?.rows || [];
total.value = response?.total || 0;
})
.catch(() => {
regdictList.value = [];
total.value = 0;
proxy && proxy.$modal.msgError("数据加载失败");
})
.finally(() => {
loading.value = false;
});
}
// 搜索
function handleQuery() {
queryParams.value && (queryParams.value.pageNum = 1);
getList();
}
// 重置搜索
function resetQuery() {
proxy && proxy.resetForm && proxy.resetForm("queryRef");
handleQuery();
}
// 选择行变化
function handleSelectionChange(selection) {
ids.value = (selection || []).map(item => item?.paramId).filter(Boolean);
single.value = (selection || []).length !== 1;
multiple.value = !(selection && selection.length);
}
// 新增
function handleAdd() {
resetForm();
open.value = true;
title.value = `添加${menuname.value}`;
}
// 修改
async function handleUpdate(row) {
resetForm();
let paramId = row?.paramId || (ids.value.length > 0 ? ids.value[0] : null);
if (!paramId) {
proxy && proxy.$modal.msgWarning("请选择要修改的数据");
return;
}
try {
const response = await getstatsparam(paramId);
form.value = { ...response?.data };
open.value = true;
title.value = `修改${menuname.value}`;
} catch (error) {
proxy && proxy.$modal.msgError("获取数据失败");
console.error("修改数据失败:", error);
}
}
// 删除
async function handleDelete(row) {
let paramIds = row?.paramId ? [row.paramId] : [...ids.value];
paramIds = paramIds.filter(Boolean);
if (paramIds.length === 0) {
proxy && proxy.$modal.msgWarning("请选择要删除的数据");
return;
}
try {
proxy && await proxy.$modal.confirm(`是否确认删除${menuname.value}编号为"${paramIds.join(',')}"的数据项?`);
await delstatsparam(paramIds);
getList();
proxy && proxy.$modal.msgSuccess("删除成功");
} catch (error) {
error !== "cancel" && console.error("删除数据失败:", error);
}
}
// 导出
function handleExport() {
if (!proxy || !proxy.download) return;
proxy.download("delstatsparam/export", {
...(queryParams.value || {})
}, `报表模板_${new Date().getTime()}.xlsx`);
}
// 提交表单
async function submitForm() {
if (!proxy || !proxy.$refs || !proxy.$refs.statsparamRef) return;
// 表单校验
const valid = await new Promise((resolve) => {
proxy.$refs.statsparamRef.validate((isValid) => resolve(isValid));
});
if (!valid) return;
try {
const formData = { ...form.value };
const isEdit = !!formData.paramId;
const request = isEdit ? updatestatsparam(formData) : addstatsparam(formData);
const response = await request;
if (response?.code === 200) {
proxy && proxy.$modal.msgSuccess(isEdit ? "修改成功" : "新增成功");
open.value = false;
getList();
} else {
proxy && proxy.$modal.msgError(response?.msg || "操作失败");
}
} catch (error) {
proxy && proxy.$modal.msgError("操作失败,请重试");
console.error("提交表单失败:", error);
}
}
// 取消
function cancel() {
open.value = false;
resetForm();
}
getTypes(route.query && route.query.statsCode);
/** 查询字典类型详细 */
function getTypes(statsCode0) {
statsCode.value=statsCode0
queryParams.value.statsCode =statsCode0;
getList();
}
</script>
<style scoped>
/* 基础样式 */
.mb8 {
height: 30px;
margin-bottom: 8px !important;
}
.table-container {
height: calc(100% - 150px);
margin-bottom: 10px;
}
/* 表格样式优化 */
:deep(.param-table .el-table__row) {
height: 30px !important;
line-height: 30px !important;
}
:deep(.param-table .el-table__cell) {
padding: 2px 4px !important;
height: 30px !important;
line-height: 1.2 !important;
vertical-align: middle !important;
}
.param-type-cell {
width: 100%;
height: 100%;
min-height: 26px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
font-size: 12px;
border-radius: 2px;
}
:deep(.param-table .el-button--link) {
padding: 0 4px !important;
font-size: 12px !important;
}
/* 对话框紧凑样式 */
:deep(.compact-dialog) {
--el-dialog-padding-primary: 15px;
}
.compact-form {
--el-form-item-margin-bottom: 8px;
line-height: 1.4;
}
:deep(.compact-form .el-form-item__label) {
padding: 0 8px 0 0;
line-height: 1.4;
}
:deep(.compact-form .el-form-item__content) {
line-height: 1.4;
}
/* 对话框底部按钮区 */
:deep(.compact-dialog .dialog-footer) {
padding: 10px 15px;
text-align: right;
}
/* 备注文本域 */
:deep(.compact-form .el-form-item:last-of-type .el-textarea__inner) {
min-height: 60px;
}
</style>

View File

@ -0,0 +1,537 @@
<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item :label="menuname + '类别'" prop="statsType">
<el-select
v-model="queryParams.statsType"
:placeholder="`请选择${menuname}类别`"
clearable
style="width: 200px"
@change="handleQuery"
>
<el-option
v-for="item in statsTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="menuname + '编码'" prop="statsCode">
<el-input
v-model="queryParams.statsCode"
:placeholder="`请输入${menuname}编码`"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="statsName">
<el-input
v-model="queryParams.statsName"
:placeholder="`请输入${menuname}名称`"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="状态"
clearable
style="width: 200px"
>
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<div class="table-container">
<el-table
v-loading="loading"
:data="regdictList"
@selection-change="handleSelectionChange"
class="stats-table"
height="100%"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="`${menuname}编号`" align="center" prop="statsId" v-if="false" />
<el-table-column :label="`${menuname}类别`" align="center" prop="statsType" width="100" show-overflow-tooltip>
<template #default="scope">
<span
class="stats-type-cell"
:style="{
backgroundColor: getstatsTypeColor(scope.row.statsType),
color: '#fff'
}"
>
{{ statsTypeOptions.find(item => item.value === scope.row.statsType)?.label || scope.row.statsType }}
</span>
</template>
</el-table-column>
<el-table-column :label="`${menuname}编码`" align="center" prop="statsCode" show-overflow-tooltip >
<template #default="scope">
<router-link :to="`/liswork/xtwh/statstemplate/data?statsCode=${scope.row.statsCode}`" class="link-type">
<span>{{ scope.row.statsCode }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column :label="`${menuname}名称`" align="left" prop="statsName" show-overflow-tooltip />
<el-table-column label="表头" align="left" prop="statsTitle" width="150" show-overflow-tooltip />
<el-table-column label="图表类型" align="left" prop="statsGraph" width="80" show-overflow-tooltip >
<template #default="scope">
<span>
{{ statsGraphOptions.find(item => item.value === scope.row.statsGraph)?.label || scope.row.statsGraph }}
</span>
</template>
</el-table-column>
<el-table-column label="备注" align="left" prop="remark" width="100" show-overflow-tooltip />
<el-table-column label="排序" align="center" prop="statsSort" width="80" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="150" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 新增/修改对话框 -->
<el-dialog :title="title" v-model="open" width="700px" class="compact-dialog">
<el-form ref="statstempRef" :model="form" :rules="rules" label-width="150px" class="compact-form">
<el-form-item :label="`${menuname}类别`" prop="statsType">
<el-select
v-model="form.statsType"
:placeholder="`请选择${menuname}类别`"
style="width: 100%"
>
<el-option
v-for="item in statsTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="`${menuname}编码`" prop="statsCode">
<el-input v-model="form.statsCode" :placeholder="`请输入${menuname}编码`" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="statsName">
<el-input v-model="form.statsName" :placeholder="`请输入${menuname}名称`" />
</el-form-item>
<el-form-item :label="`${menuname}表头`" prop="statsTitle">
<el-input v-model="form.statsTitle" :placeholder="`请输入${menuname}表头`" />
</el-form-item>
<el-form-item :label="`${menuname}图形类型`" prop="statsOptiontype">
<el-select
v-model="form.statsGraph"
:placeholder="`请选择${menuname}图形类型`"
style="width: 100%"
>
<el-option
v-for="item in statsGraphOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<!-- 集成封装好的SQL高亮输入框组件 -->
<el-form-item :label="`${menuname}查询语句`" prop="statsSql">
<el-input v-model="form.statsSql" type="textarea" placeholder="请输入查询语句" :rows="10" />
</el-form-item>
<el-form-item label="顺序" prop="statsSort">
<el-input-number v-model="form.statsSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" :rows="3" />
</el-form-item>
</el-form>
<!-- 对话框底部按钮 -->
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="statstemplate">
import {
addstatstemp,
delstatstemp,
getstatstemp,
liststatstemp,
updatestatstemp
} from "@/api/liswork/xtwh/StatstemplateApi.ts";
// ========== 基础变量声明(避免提前访问) ==========
// 菜单名称
const menuname = ref("报表模板");
// 报表类别选项
const statsTypeOptions = ref([
{ label: "统计表", value: "0", color: "#3282F6" },
{ label: "查询表", value: "1", color: "#67C23A" },
{ label: "图表", value: "2", color: "#FF443F" },
{ label: "仪表盘", value: "3", color: "#7E84F7" },
{ label: "混合", value: "4", color: "#909399" }
]);
// 图表类型选项
const statsGraphOptions = ref([
{ label: "无", value: "0" },
{ label: "折线图", value: "1" },
{ label: "柱状图", value: "2" },
{ label: "饼图", value: "3" }
]);
// ========== 页面状态与数据 ==========
// 获取并缓存proxy
const instance = getCurrentInstance();
const proxy = instance?.proxy || null;
// 字典数据(空值保护)
const sys_normal_disable = proxy?.useDict("sys_normal_disable")?.sys_normal_disable || [];
// 表单数据
const form = ref({
statsId: undefined,
statsCode: undefined,
statsName: undefined,
statsTitle: undefined,
statsType: statsTypeOptions.value[0]?.value || "",
statsGraph: statsGraphOptions.value[0]?.value || "",
statsSql: "",
statsSort: 0,
status: "0",
remark: undefined
});
// 查询参数
const queryParams = ref({
statsCode: undefined,
statsName: undefined,
statsType: undefined,
status: undefined,
pageNum: 1,
pageSize: 30
});
// 表单校验规则
const rules = ref({
statsType: [{ required: true, message: `${menuname.value}类别不能为空`, trigger: "blur" }],
statsName: [{ required: true, message: `${menuname.value}名称不能为空`, trigger: "blur" }],
statsCode: [{ required: true, message: `${menuname.value}编码不能为空`, trigger: "blur" }],
statsSort: [{ required: true, message: `${menuname.value}顺序不能为空`, trigger: "blur" }],
});
// 页面基础状态
const regdictList = ref([]); // 表格数据列表
const open = ref(false); // 对话框显示状态
const loading = ref(true); // 加载状态
const showSearch = ref(true); // 搜索框显示状态
const ids = ref([]); // 选中的ID列表
const single = ref(true); // 是否单选
const multiple = ref(true); // 是否多选
const total = ref(0); // 总条数
const title = ref(""); // 对话框标题
// ========== 工具方法 ==========
// 获取类别颜色
function getstatsTypeColor(type) {
const item = statsTypeOptions.value.find(item => item.value === type);
return item?.color || "#909399";
}
// 重置表单
function resetForm() {
form.value = {
statsId: undefined,
statsCode: undefined,
statsName: undefined,
statsTitle: undefined,
statsType: statsTypeOptions.value[0]?.value || "",
statsGraph: statsGraphOptions.value[0]?.value || "",
statsSql: "",
statsSort: 0,
status: "0",
remark: undefined
};
if (proxy && proxy.resetForm) {
proxy.resetForm("statstempRef");
}
}
// ========== 核心业务方法 ==========
// 查询列表
function getList() {
loading.value = true;
const params = queryParams.value || { pageNum: 1, pageSize: 30 };
liststatstemp(params)
.then(response => {
regdictList.value = response?.rows || [];
total.value = response?.total || 0;
})
.catch(() => {
regdictList.value = [];
total.value = 0;
proxy && proxy.$modal.msgError("数据加载失败");
})
.finally(() => {
loading.value = false;
});
}
// 搜索
function handleQuery() {
queryParams.value && (queryParams.value.pageNum = 1);
getList();
}
// 重置搜索
function resetQuery() {
proxy && proxy.resetForm && proxy.resetForm("queryRef");
handleQuery();
}
// 选择行变化
function handleSelectionChange(selection) {
ids.value = (selection || []).map(item => item?.statsId).filter(Boolean);
single.value = (selection || []).length !== 1;
multiple.value = !(selection && selection.length);
}
// 新增
function handleAdd() {
resetForm();
open.value = true;
title.value = `添加${menuname.value}`;
}
// 修改
async function handleUpdate(row) {
resetForm();
let statsId = row?.statsId || (ids.value.length > 0 ? ids.value[0] : null);
if (!statsId) {
proxy && proxy.$modal.msgWarning("请选择要修改的数据");
return;
}
try {
const response = await getstatstemp(statsId);
form.value = { ...response?.data };
open.value = true;
title.value = `修改${menuname.value}`;
} catch (error) {
proxy && proxy.$modal.msgError("获取数据失败");
console.error("修改数据失败:", error);
}
}
// 删除
async function handleDelete(row) {
let statsIds = row?.statsId ? [row.statsId] : [...ids.value];
statsIds = statsIds.filter(Boolean);
if (statsIds.length === 0) {
proxy && proxy.$modal.msgWarning("请选择要删除的数据");
return;
}
try {
proxy && await proxy.$modal.confirm(`是否确认删除${menuname.value}编号为"${statsIds.join(',')}"的数据项?`);
await delstatstemp(statsIds);
getList();
proxy && proxy.$modal.msgSuccess("删除成功");
} catch (error) {
error !== "cancel" && console.error("删除数据失败:", error);
}
}
// 导出
function handleExport() {
if (!proxy || !proxy.download) return;
proxy.download("delstatstemp/export", {
...(queryParams.value || {})
}, `报表模板_${new Date().getTime()}.xlsx`);
}
// 提交表单
async function submitForm() {
if (!proxy || !proxy.$refs || !proxy.$refs.statstempRef) return;
// 表单校验
const valid = await new Promise((resolve) => {
proxy.$refs.statstempRef.validate((isValid) => resolve(isValid));
});
if (!valid) return;
try {
const formData = { ...form.value };
const isEdit = !!formData.statsId;
const request = isEdit ? updatestatstemp(formData) : addstatstemp(formData);
const response = await request;
if (response?.code === 200) {
proxy && proxy.$modal.msgSuccess(isEdit ? "修改成功" : "新增成功");
open.value = false;
getList();
} else {
proxy && proxy.$modal.msgError(response?.msg || "操作失败");
}
} catch (error) {
proxy && proxy.$modal.msgError("操作失败,请重试");
console.error("提交表单失败:", error);
}
}
// 取消
function cancel() {
open.value = false;
resetForm();
}
// ========== 初始化 ==========
// 初始化加载列表
getList();
</script>
<style scoped>
/* 基础样式 */
.mb8 {
height: 30px;
margin-bottom: 8px !important;
}
.table-container {
height: calc(100% - 150px);
margin-bottom: 10px;
}
/* 表格样式优化 */
:deep(.stats-table .el-table__row) {
height: 30px !important;
line-height: 30px !important;
}
:deep(.stats-table .el-table__cell) {
padding: 2px 4px !important;
height: 30px !important;
line-height: 1.2 !important;
vertical-align: middle !important;
}
.stats-type-cell {
width: 100%;
height: 100%;
min-height: 26px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
font-size: 12px;
border-radius: 2px;
}
:deep(.stats-table .el-button--link) {
padding: 0 4px !important;
font-size: 12px !important;
}
/* 对话框紧凑样式 */
:deep(.compact-dialog) {
--el-dialog-padding-primary: 15px;
}
.compact-form {
--el-form-item-margin-bottom: 8px;
line-height: 1.4;
}
:deep(.compact-form .el-form-item__label) {
padding: 0 8px 0 0;
line-height: 1.4;
}
:deep(.compact-form .el-form-item__content) {
line-height: 1.4;
}
/* 对话框底部按钮区 */
:deep(.compact-dialog .dialog-footer) {
padding: 10px 15px;
text-align: right;
}
/* 备注文本域 */
:deep(.compact-form .el-form-item:last-of-type .el-textarea__inner) {
min-height: 60px;
}
</style>