Files
dy_web/src/views/backOfficeSystem/service/taskPage/CustomTaskPackage/editAddFormDialog.vue
2025-12-17 19:46:14 +08:00

423 lines
12 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>
<div v-if="dialogFormVisible" class="dialog">
<div class="head_box">
<span class="title">{{ title }}</span>
<div>
<el-button v-if="!infoActive" type="primary" size="small" @click="submit" :loading="btnLoading">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="dialogWrapper">
<div class="label">任务包基本信息</div>
<el-descriptions class="margin-top" :column="3" border>
<!-- <template #extra>-->
<!-- <el-button type="primary">Operation</el-button>-->
<!-- </template>-->
<el-descriptions-item label="方格名称">
{{ form?.fgMc }}
</el-descriptions-item>
<el-descriptions-item label="预警等级">
<dict-tag :options="D_ZDXL_FGXLRW_YJDJ" :value="form?.fgYjdj" :tag="false" />
</el-descriptions-item>
<el-descriptions-item label="警情数量">
{{ form?.fgYjjqsl }}
</el-descriptions-item>
<el-descriptions-item label="高发时段">
{{ form?.fgYjgfsd }}
</el-descriptions-item>
<el-descriptions-item label="高发类型">
{{ form?.fgJqtjLx }}
</el-descriptions-item>
<el-descriptions-item label="任务日期">
{{ form?.rwRq }}
</el-descriptions-item>
<el-descriptions-item label="小时统计">
{{ form?.fgJqtjXsLabel }}
</el-descriptions-item>
</el-descriptions>
<div class="label" style="margin-top: 1rem">任务包下发编辑信息</div>
<el-form ref="formRef" :model="form" :rules="rules" :inline="true">
<el-form-item prop="xlghSc" label="巡逻时长:">
<el-input-number style="width: 80%" min="0" :disabled="disabled" placeholder="请填写巡逻时长"
v-model="form.xlghSc"></el-input-number>
<el-tag size="small" type="warning">分钟</el-tag>
</el-form-item>
<el-form-item prop="xlghPcRy" label="盘查人员:">
<el-input placeholder="请填写盘查人员" clearable :disabled="disabled" v-model="form.xlghPcRy"></el-input>
</el-form-item>
<el-form-item prop="xlghPcCl" label="盘查车辆:">
<el-input placeholder="请填写盘查车辆" clearable :disabled="disabled" v-model="form.xlghPcCl"></el-input>
</el-form-item>
<el-form-item prop="xlghXllc" label="巡逻里程:">
<el-input-number style="width: 80%" min="0" :disabled="disabled" placeholder="请填写巡逻里程"
v-model="form.xlghXllc"></el-input-number>
<el-tag size="small" type="warning">公里</el-tag>
</el-form-item>
<el-form-item label="下发巡组:">
<el-input placeholder="请填写下发巡组" clearable :disabled="disabled" v-model="form.xfbbName"
@click="visible = true" readonly></el-input>
</el-form-item>
<div v-if="form?.rwZt !== '01'" style="flex: 1; display: flex; justify-content: flex-end">
<el-button :disabled="isButtonDisabled" @click="checkInCardOpen">追加打卡</el-button>
</div>
<el-row style="width: 100%">
<el-col>
<MyTable :tableData="form?.bddList" :tableColumn="pageData.tableColumn"
:tableConfiger="pageData.tableConfiger" @chooseData="handleChooseDataChange" :selectable="selectable">
<template #xlghDkcs="{ row, $index }">
<div class="validation-container">
<el-input-number style="width: 30%" :placeholder="`输入打卡点${$index + 1}需打卡次数`" clearable min="0"
:disabled="!selectable(row)" v-model="row.xlghDkcs" :class="{ 'is-error': hasError($index) }"
@blur="validateField($index)" />
<!-- 展示错误信息 -->
<span v-if="hasError($index)" class="error-message">
{{ getError($index) }}
</span>
</div>
</template>
</MyTable>
<div style="display: none">
<template v-for="(item, index) in form?.bddList" :key="index">
<el-form-item :prop="`bddList[${index}].xlghDkcs`" :label="item?.bddMc" :rules="checkPointRules">
<el-input-number style="width: 100%" :placeholder="`输入打卡点${index + 1}需打卡次数`" clearable
v-model="item.xlghDkcs" />
</el-form-item>
</template>
</div>
</el-col>
</el-row>
</el-form>
</div>
</div>
<distribute-patrol-team-dialog v-model="visible" @selection-change="handleChange" />
<add-check-in-card ref="addCheckInCardRef" :disabledIds="disabledIds" :bddList="form?.bddList"
v-model="checkInCardVisible" @change="handleSelectChange" />
</div>
</template>
<script setup>
import { ref, reactive, getCurrentInstance, computed, watch } from "vue";
import { updateData } from "@/api/service/dailyTaskPackage";
import DictTag from "@/components/DictTag/index.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import DistributePatrolTeamDialog from "@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/components/DistributePatrolTeamDialog.vue";
import AddCheckInCard from "@/views/backOfficeSystem/service/taskPage/dailyTaskPackage/components/addCheckInCard.vue";
const { proxy } = getCurrentInstance();
const { D_ZDXL_FGXLRW_YJDJ } = proxy.$dict("D_ZDXL_FGXLRW_YJDJ");
const btnLoading = ref(false); //按钮截流
const title = ref("修改");
const formRef = ref(null);
const addCheckInCardRef = ref(null);
const infoActive = ref(true);
const visible = ref(false);
const checkInCardVisible = ref(false);
const pageData = reactive({
tableConfiger: {
rowKey: "bddId",
rowHieght: 61,
haveControls: false,
showSelectType: "checkBox",
defaultSelectKeys: [],
loading: false
},
total: 0,
selectCheckList: [],
tableColumn: [
{
label: "必到点",
prop: "bddMc"
},
{
label: "打卡次数",
prop: "xlghDkcs",
showSolt: true
}
]
});
//级联选择器配置
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
});
const emits = defineEmits(["update:modelValue", "ok"]);
const dialogFormVisible = computed({
get() {
return props.modelValue;
},
set(val) {
emits("update:modelValue", val);
}
});
//表单数据
const form = ref({
bddList: [{ xlghDkcs: 1 }, { xlghDkcs: "" }]
});
const isButtonDisabled = computed(() => {
// const target = new Date('2025-09-18')
const target = new Date(form.value?.rwRq);
const now = new Date();
// 只比较日期,忽略时间
return target.setHours(0, 0, 0, 0) < now.setHours(0, 0, 0, 0);
});
const disabled = computed(() => {
// const targetDate = new Date(form.value?.rwRq);
// const today = new Date();
return form.value?.rwZt === "03" || isButtonDisabled.value;
});
// 打卡点验证规则
const checkPointRules = [
{ required: true, message: "请输入打卡次数", trigger: "change" },
{
validator: (rule, value, callback) => {
if (value < 1) {
callback(new Error("打卡次数必须大于0"));
} else {
callback();
}
},
trigger: "change"
}
];
//表单验证
const rules = reactive({
xlghXllc: [
{
required: true,
message: "请填写巡逻里程",
trigger: "change"
}
],
xlghSc: [
{
required: true,
message: "请填写巡逻时长",
trigger: "change"
}
],
xlghPcRy: [
{
required: true,
message: "请填写盘查人员",
trigger: "change"
}
],
xlghPcCl: [
{
required: true,
message: "请填写盘查车辆",
trigger: "change"
}
]
});
//新增
function open(row = {}, type) {
infoActive.value = type === "view";
form.value = { ...row, xfbbName: row?.xfxz };
form.value?.bddList?.forEach((item, index) => {
item.index = index; // 直接添加index属性
});
pageData.tableConfiger.defaultSelectKeys = form.value?.bddList?.map((i) => {
if (i?.selected) return i?.bddId;
});
title.value = type === "view" ? "查看详情" : "编辑信息";
dialogFormVisible.value = true;
}
//关闭弹窗
function close() {
formRef.value.resetFields();
dialogFormVisible.value = false;
}
const handleChange = (val) => {
form.value.xfbbId = val?.id;
form.value.xfbbQwJlId = val?.xfbbQwJlId?.[0];
form.value.xfbbName = val?.xfbbName;
};
const selectList = ref([]);
const handleChooseDataChange = (event) => {
selectList.value = [...event];
};
// 保存原始bddList的ID用于对比
const disabledIds = ref(new Set());
const updateDisabledIds = () => {
disabledIds.value = new Set(form.value?.bddList?.map((i) => i.bddId));
};
const selectable = (row) => {
return !disabledIds.value.has(row.bddId);
};
const handleSelectChange = (selection) => {
pageData.selectCheckList = selection;
// 添加新项目
const newItems = selection.filter(
(item) => !disabledIds.value.has(item.bddId)
);
form.value.bddList = [...form.value.bddList, ...newItems];
// 更新禁用ID集合
updateDisabledIds();
emits("ok", false);
};
// 监听form.bddList的变化确保禁用集合同步更新
watch(
() => form.value.bddList,
() => {
updateDisabledIds();
},
{ deep: true }
);
const checkInCardOpen = () => {
addCheckInCardRef.value?.open(form.value);
};
const fieldErrors = ref({});
// 检查指定索引是否有错误
const hasError = (index) => {
const propPath = `bddList[${index}].xlghDkcs`;
return !!fieldErrors.value[propPath];
};
// 获取指定索引的错误信息
const getError = (index) => {
const propPath = `bddList[${index}].xlghDkcs`;
return fieldErrors.value[propPath] || "";
};
// 验证单个字段
const validateField = async (propPath) => {
return new Promise((resolve) => {
formRef.value.validateField(propPath, (errorMessage) => {
fieldErrors.value[propPath] = errorMessage;
resolve(!errorMessage);
});
});
};
const validateAllCheckpoints = async () => {
if (!form.value.bddList) return true;
const validations =
form.value?.bddList?.map((_, index) =>
validateField(`bddList[${index}].xlghDkcs`)
) || [];
const results = await Promise.all(validations);
return results.every((result) => result);
};
//提交
const submit = async () => {
try {
await validateAllCheckpoints();
await formRef.value.validate();
await updateData({ ...form.value, bddList: selectList.value || [] });
proxy.$message({
type: "success",
message: "修改成功"
});
dialogFormVisible.value = false;
emits("ok");
} catch (error) {
console.log(error);
}
};
defineExpose({ open });
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
.dialog {
::v-deep {
.el-table__header-wrapper .el-checkbox {
display: none;
}
.el-checkbox__input.is-disabled .el-checkbox__inner,
.el-checkbox__input.is-checked .el-checkbox__inner {
background-color: var(--el-checkbox-checked-bg-color);
border-color: var(--el-checkbox-checked-input-border-color);
}
.el-checkbox__input.is-disabled .el-checkbox__inner,
.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after {
border: 1px solid var(--el-checkbox-checked-icon-color);
border-left: 0;
border-top: 0;
}
}
.dialogWrapper {
margin: 20px 20px 0 20px;
.el-form--inline {
padding: 0 0 0rem 0;
}
}
}
.label {
margin-bottom: 1rem;
}
.validation-container {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
min-height: 60px;
/* 预留错误信息空间 */
}
.error-message {
color: #f56c6c;
font-size: 12px;
line-height: 1;
padding: 2px 0;
display: block;
}
.is-error .el-input-number__inner {
border-color: #f56c6c;
}
/* 确保表格行高度适应错误信息 */
.el-table .cell {
min-height: 40px;
display: flex;
flex-direction: column;
justify-content: center;
}
</style>