562 lines
16 KiB
Vue
Raw Normal View History

2025-09-12 11:06:51 +08:00
<template>
<div class="rule-management-container">
<!-- 顶部操作栏 -->
<div class="mb20">
<el-button type="primary" icon="Search" @click="handleQuery"> 查询</el-button>
<el-button type="success" icon="Plus" @click="addgz">新增</el-button>
<el-button type="primary" icon="Select" @click="saveHandle">保存</el-button>
<!-- :disabled="flag" -->
<el-button icon="Plus" @click="addDetail">新增明细</el-button>
</div>
<!-- 左右分栏区域 -->
<div class="content-wrapper">
<!-- 左侧表格 -->
<div class="left-table-area">
<el-table :data="ruleList" @row-click="handleRowClick" border style="width: 100%" highlight-current-row
class="custom-table">
<el-table-column prop="bglqdh" label="规则代号" width="100" />
<el-table-column prop="bglqmc" label="规则名称" width="200" />
<el-table-column prop="bz" label="备注" />
<el-table-column label="操作" align="center" fixed="right" width="100">
<template #default="scope">
<el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 右侧表单与明细表格 -->
<div class="right-form-area">
<el-form :model="currentRule" label-width="80px" class="rule-form">
<el-form-item label="规则代号">
<el-input v-model="currentRule.bglqdh" disabled />
</el-form-item>
<el-form-item label="规则名称">
<el-input v-model="currentRule.bglqmc" @blur="editHandle(currentRule, 'bglqmc')"
@keyup.enter="editHandle(currentRule, 'bglqmc')" />
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="currentRule.bz" :rows="2" @blur="editHandle(currentRule, 'bz')"
@keyup.enter="editHandle(currentRule, 'bz')" />
</el-form-item>
</el-form>
<div class="detail-table-header">
<span>规则明细</span>
</div>
<el-table :data="detailList" border style="width: 100%;" class="detail-table" :cell-class-name="cellClassName">
<el-table-column prop="weekday" label="起始日期" width="100">
2025-09-12 11:06:51 +08:00
<template #default="scope">
<el-select v-model="scope.row.weekday" placeholder="选择星期" size="small" class="week-select"
@change="handleDetailChange(scope.row)">
<el-option v-for="day in weekDays" :key="day.value" :label="day.label" :value="day.value" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="weekday1" label="截止日期" width="100">
2025-09-12 11:06:51 +08:00
<template #default="scope">
<el-select v-model="scope.row.weekday1" placeholder="选择星期" size="small" class="week-select"
@change="handleDetailChange(scope.row)">
<el-option v-for="day in weekDays" :key="day.value" :label="day.label" :value="day.value" />
</el-select>
</template>
</el-table-column>
<el-table-column prop="kssj" label="起始时间" width="100">
<template #default="scope">
<el-input v-model="scope.row.kssj" placeholder="HH:mm" size="small"
@input="handleTimeInput(scope.row, 'kssj')" maxlength="5" class="time-input" @focus="handleInputFocus"
@blur="handleInputBlur(scope.row, 'kssj')" />
</template>
</el-table-column>
<el-table-column prop="jssj" label="截止时间" width="100">
<template #default="scope">
<el-input v-model="scope.row.jssj" placeholder="HH:mm" size="small"
@input="handleTimeInput(scope.row, 'jssj')" maxlength="5" class="time-input" @focus="handleInputFocus"
@blur="handleInputBlur(scope.row, 'jssj')" />
</template>
</el-table-column>
<el-table-column prop="bglqsm" label="报告领取声明">
<template #default="scope">
<el-input v-model="scope.row.bglqsm" size="small" class="statement-input" @focus="handleInputFocus" />
</template>
</el-table-column>
<el-table-column prop="bgxss" label="所需小时数" width="100">
<template #default="scope">
<el-input v-model="scope.row.bgxss" placeholder="0" size="small"
@input="handleNumberInput(scope.row, 'bgxss')" class="number-input" @focus="handleInputFocus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button size="small" type="danger" @click="delDetail(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue'
import { rptgetruleList, rptgetruleadd, rptgetruleUpdate, rptgetruleDel, rptgetruleDetail, rptgetruleDelDetail } from '@/api/mzcx/index';
import { ElMessageBox, ElMessage } from 'element-plus'
// 星期选项数据
const weekDays = [
{ label: '周一', value: '1' },
{ label: '周二', value: '2' },
{ label: '周三', value: '3' },
{ label: '周四', value: '4' },
{ label: '周五', value: '5' },
{ label: '周六', value: '6' },
{ label: '周日', value: '7' }
]
interface Rule {
bglqdh: number,
bglqmc: string,
bz: string,
status: boolean,
originalData: object,
addFlag: boolean
}
// 模拟规则列表数据
const ruleList = ref<Rule[]>([])
// 当前选中的规则数据
const currentRule = ref({
bglqdh: 1,
bglqmc: '',
bz: '',
})
interface Detail {
weekday: string,
weekday1: string,
kssj: string,
jssj: string,
bglqsm: string,
bgxss: number,
bglqdh: number,
xh: number,
detaiFlag: boolean
status: boolean // 新增:标识明细是否被修改
}
const detailList = ref<Detail[]>([])
const rptgetruledetail = ref<Detail[]>([])
// 是否正在编辑输入框
const isEditing = ref(false)
const handleQuery = () => {
getList()
}
// 处理时间输入,限制为HH:mm格式
const handleTimeInput = (row: any, field: string) => {
// 移除非数字和非冒号字符
let value = row[field].replace(/[^0-9:]/g, '')
// 自动添加冒号
if (value.length === 2 && !value.includes(':')) {
value += ':'
}
row[field] = value
}
// 处理时间输入失去焦点时的格式化
const handleInputBlur = (row: any, field: string) => {
isEditing.value = false
let value = row[field]
// 补全时间格式
if (field === 'kssj' || field === 'jssj') {
if (value.length === 1) {
value = `0${value}:00`
} else if (value.length === 2 && !value.includes(':')) {
value += ':00'
} else if (value.length === 3 && value.includes(':')) {
value += '0'
}
// 验证小时和分钟范围
if (value.includes(':')) {
const [hours, minutes] = value.split(':')
const validHours = Math.min(Math.max(parseInt(hours) || 0, 0), 23).toString().padStart(2, '0')
const validMinutes = Math.min(Math.max(parseInt(minutes) || 0, 0), 59).toString().padStart(2, '0')
value = `${validHours}:${validMinutes}`
} else {
value = '00:00'
}
row[field] = value
row.status = true;
}
czList()
}
// 处理数字输入,限制为数字
const handleNumberInput = (row: any, field: string) => {
// 只保留数字和小数点
row[field] = row[field].replace(/[^0-9.]/g, '')
// 确保只有一个小数点
const dotIndex = row[field].indexOf('.')
if (dotIndex !== -1 && row[field].lastIndexOf('.') !== dotIndex) {
row[field] = row[field].slice(0, row[field].lastIndexOf('.'))
row.status = true;
}
czList()
}
// 处理明细变化
const handleDetailChange = (row: any) => {
row.status = true;
czList()
}
// 输入框获得焦点
const handleInputFocus = () => {
isEditing.value = true
}
// 单元格样式类
const cellClassName = () => {
return 'no-edit-cell'
}
// 行点击事件,实现右侧联动
const handleRowClick = (row: any) => {
const { bglqdh, bglqmc, bz } = row
currentRule.value = row
row.originalData = JSON.parse(JSON.stringify(row));
getgzList(row)
}
// 新增规则
2025-09-12 11:06:51 +08:00
const addgz = () => {
ruleList.value.unshift(
{
bglqdh: Math.max(...ruleList.value.map((item: any) => item.bglqdh), 0) + 1,
bglqmc: 'test',
bz: '',
status: true,
originalData: {},
addFlag: true
}
)
currentRule.value = ruleList.value[0]
detailList.value = [
{
bglqdh: Math.max(...ruleList.value.map((item: any) => item.bglqdh), 0),
weekday: '1',
weekday1: '2',
kssj: '09:00',
jssj: '18:00',
bglqsm: '领取声明',
bgxss: 1,
xh: detailList.value.length,
detaiFlag: true,
status: false
}
]
rptgetruledetail.value.push(...detailList.value)
}
// 新增规则明细
2025-09-12 11:06:51 +08:00
const addDetail = () => {
detailList.value.push({
bglqdh: currentRule.value.bglqdh,
weekday: '1',
weekday1: '2',
kssj: '09:00',
jssj: '18:00',
bglqsm: '领取声明',
bgxss: 1,
xh: detailList.value.length + 1,
detaiFlag: false,
status: false
})
ruleList.value.forEach((item: any) => {
if (item.bglqdh == currentRule.value.bglqdh) {
item.status = true
}
});
rptgetruledetail.value.push(...detailList.value)
}
const editHandle = (row: any, field: string) => {
ruleList.value.forEach((item: any) => {
if (item.bglqdh == row.bglqdh) {
item[field] = row[field]
item.status = JSON.stringify(row[field]) !== JSON.stringify(item.originalData[field]);
}
});
czList()
}
const czList = () => {
ruleList.value.forEach((item: any) => {
if (item.bglqdh == currentRule.value.bglqdh) {
item.status = true
}
});
rptgetruledetail.value = rptgetruledetail.value.filter((item: any) => item.bglqdh !== currentRule.value.bglqdh)
rptgetruledetail.value.push(...detailList.value)
}
// 保存
const saveHandle = () => {
const addList = ruleList.value.filter((item: any) => item.addFlag)
const updateList = ruleList.value.filter((item: any) => item.status && !item.addFlag)
const addDetailList = rptgetruledetail.value.filter((item: any) => item.detaiFlag)
const upadteDetailList = rptgetruledetail.value.filter((item: any) => !item.detaiFlag)
// 保存成功后的回调处理
const handleSuccess = () => {
// 重置规则的新增/修改状态
ruleList.value.forEach(item => {
item.addFlag = false;
item.status = false;
});
// 重置明细的新增/修改状态
detailList.value.forEach(item => {
item.detaiFlag = false;
item.status = false;
});
ElMessage.success('保存成功');
};
if (updateList.length > 0) {
rptgetruleUpdate({ ruleList: updateList, ruleDetailList: upadteDetailList }).then((res: any) => {
if (res.code == 0) {
handleSuccess()
}
})
} if (addList.length > 0) {
rptgetruleadd({ ruleList: addList, ruleDetailList: addDetailList }).then((res: any) => {
if (res.code == 0) {
handleSuccess()
}
})
}
}
// 删除规则
const handleDelete = (row: any) => {
ElMessageBox.confirm(
`确定删除${row.bglqdh}数据吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
const handleSueess = () => {
ruleList.value = ruleList.value.filter((item: any) => item.bglqdh !== row.bglqdh)
handleRowClick(ruleList.value[0])
};
if (row.addFlag) {
handleSueess()
2025-09-12 11:06:51 +08:00
} else {
rptgetruleDel({ bglqdh: row.bglqdh }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功');
handleSueess()
}
})
2025-09-12 11:06:51 +08:00
}
})
.catch(() => {
})
2025-09-12 11:06:51 +08:00
};
// 删除规则明细
const delDetail = (row: any) => {
ElMessageBox.confirm(
`确定删除该项数据吗?`, "提示",
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
const handleSueess = () => {
detailList.value = detailList.value.filter((item: any) => item.xh !== row.xh)
};
if (row.detaiFlag) {
handleSueess()
2025-09-12 11:06:51 +08:00
} else {
rptgetruleDelDetail({ bglqdh: row.bglqdh, xh: row.xh }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功');
handleSueess()
}
})
2025-09-12 11:06:51 +08:00
}
})
.catch(() => {
})
2025-09-12 11:06:51 +08:00
};
const getList = () => {
rptgetruleList().then((res: any) => {
if (res.code == 0) {
ruleList.value = res.data
ruleList.value.forEach((item: any) => {
item.originalData = {}
item.status = false
})
handleRowClick(ruleList.value[0])
getgzList(res.data[0])
}
})
}
const getgzList = (info: any) => {
if (info.status) {
detailList.value = rptgetruledetail.value.filter((item: any) => item.bglqdh == info.bglqdh)
} else {
rptgetruleDetail({ bglqdh: info.bglqdh }).then((res: any) => {
if (res.code == 0) {
detailList.value = res.data
}
})
}
}
getList()
// 初始化默认选中第一行
onMounted(() => {
})
// 替换原flag的定义,改为计算属性
const flag = computed(() => {
// 检查是否有新增规则
const hasNewRule = ruleList.value.some(item => item.addFlag);
// 检查是否有修改的规则
const hasUpdatedRule = ruleList.value.some(item => item.status);
// 检查是否有新增明细
const hasNewDetail = detailList.value.some(item => item.detaiFlag);
// 检查是否有修改的明细
const hasUpdatedDetail = detailList.value.some(item => item.status);
// 当存在任何新增或修改时,按钮可点击(返回false),否则禁用(返回true)
return !(hasNewRule || hasUpdatedRule || hasNewDetail || hasUpdatedDetail);
});
</script>
<style scoped>
.rule-management-container {
height: 90vh;
/* display: flex;
flex-direction: column; */
padding: 10px;
box-sizing: border-box;
/* background-color: #f0f2f5; */
}
.top-toolbar {
padding: 8px 15px;
background-color: #FFF;
border-radius: 4px;
margin-bottom: 10px;
}
/* ::v-deep .top-toolbar .el-button {
margin-right: 8px;
} */
.content-wrapper {
flex: 1;
display: flex;
gap: 10px;
height: calc(100% - 100px);
}
.left-table-area {
width: 50%;
background-color: #fff;
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 5px;
display: flex;
flex-direction: column;
}
.right-form-area {
width: 50%;
background-color: #e6f7ff;
border: 1px solid #91d5ff;
border-radius: 4px;
padding: 15px;
display: flex;
flex-direction: column;
}
.rule-form {
background-color: #fff;
padding: 15px;
border-radius: 4px;
border: 1px solid #d9d9d9;
margin-bottom: 15px;
}
.detail-table-header {
padding: 8px 0;
font-weight: 500;
color: #1890ff;
border-bottom: 1px solid #91d5ff;
margin-bottom: 5px;
}
::v-deep .custom-table th {
background-color: #f5f7fa;
}
::v-deep .detail-table th {
background-color: #f0faff;
}
::v-deep .week-select {
width: 100%;
}
::v-deep .el-table .el-table__cell {
padding: 5px 0;
}
::v-deep .el-input__inner {
padding: 5px 10px;
height: 32px;
}
/* 禁用单元格点击效果 */
/* ::v-deep .no-edit-cell {
pointer-events: none;
} */
/* 让输入框可以被点击 */
::v-deep .no-edit-cell .el-input,
::v-deep .no-edit-cell .el-select {
pointer-events: auto;
}
::v-deep .time-input,
::v-deep .number-input {
width: 100%;
}
::v-deep .statement-input {
width: 100%;
}
</style>