2025-11-11 18:17:47 +08:00

554 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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 text 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"
height="48vh">
<el-table-column prop="weekday" label="起始日期" width="100">
<template #default="scope">
<el-select v-model="scope.row.weekday" class="full-width-input" placeholder="选择星期" size="small"
@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">
<template #default="scope">
<el-select v-model="scope.row.weekday1" placeholder="选择星期" size="small" class="full-width-input"
@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="full-width-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="full-width-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="full-width-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="full-width-input" @focus="handleInputFocus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button type="danger" text @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)
}
// 新增规则
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)
}
// 新增规则明细
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()
} else {
rptgetruleDel({ bglqdh: row.bglqdh }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功');
handleSueess()
}
})
}
})
.catch(() => {
})
};
// 删除规则明细
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()
} else {
rptgetruleDelDetail({ bglqdh: row.bglqdh, xh: row.xh }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功');
handleSueess()
}
})
}
})
.catch(() => {
})
};
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% - 3.75rem);
}
.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: 10px;
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: 10px;
}
::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;
}
</style>