!107 style(xispeak): 美化发起落实措施收集流程弹窗

* style(xispeak): 美化发起落实措施收集流程弹窗
* fix(xispeak): 移除督办状态筛选默认值,避免页面初始加载时无数据
* fix(xispeak): 对齐督办状态筛选逻辑,设置默认值"未开始"
This commit is contained in:
wsm
2026-07-22 07:13:47 +00:00
parent 321de68e27
commit 61c6fec92b
3 changed files with 454 additions and 112 deletions
@@ -1,82 +1,159 @@
<template>
<j-modal :title="title" :width="720" :visible="visible" @ok="handleOk" @cancel="handleCancel" cancelText="取消">
<a-form :model="formData" :label-col="{ style: { width: '120px' } }" :wrapper-col="{ span: 16 }">
<a-form-item label="发起类型">
<a-radio-group v-model:value="formData.triggerMode">
<a-radio value="immediate">立即发起</a-radio>
<a-radio value="recurring">重复发起</a-radio>
</a-radio-group>
</a-form-item>
<a-modal
:width="600"
:open="visible"
:footer="null"
@cancel="handleCancel"
wrapClassName="flow-schedule-start-modal"
>
<template #title>
<div class="modal-title">
<Icon icon="ant-design:send-outlined" size="20" color="#1890ff" />
<span>{{ title }}</span>
</div>
</template>
<a-form-item v-if="deptOptions.length" label="牵头部门">
<a-select
v-model:value="formData.deptIds"
mode="multiple"
:options="deptOptions"
placeholder="请选择牵头部门"
allow-clear
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
<div class="modal-content">
<a-alert
message="请选择流程发起方式"
description="立即发起将直接启动一条流程,重复发起可按周期自动生成多条流程。"
type="info"
showIcon
style="margin-bottom: 20px"
/>
<a-form-item v-if="showDeadlineField" label="事项截止时间">
<a-date-picker
v-model:value="formData.deadline"
valueFormat="YYYY-MM-DD"
placeholder="请选择事项截止时间"
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
<!-- 发起类型 -->
<div class="section-title">发起类型</div>
<a-radio-group v-model:value="formData.triggerMode" class="trigger-radio-group">
<div
class="trigger-option"
:class="{ active: formData.triggerMode === 'immediate' }"
@click="formData.triggerMode = 'immediate'"
>
<div class="option-radio">
<a-radio value="immediate" />
</div>
<div class="option-body">
<div class="option-title">
<Icon icon="ant-design:thunderbolt-outlined" size="16" />
<span>立即发起</span>
</div>
<div class="option-desc">直接启动一条流程适用于单次任务下发</div>
</div>
</div>
<template v-if="showSuoleaderFields">
<a-form-item label="是否所党委审批">
<j-switch v-model:value="formData.isNeedAppro" />
</a-form-item>
<div
class="trigger-option"
:class="{ active: formData.triggerMode === 'recurring' }"
@click="formData.triggerMode = 'recurring'"
>
<div class="option-radio">
<a-radio value="recurring" />
</div>
<div class="option-body">
<div class="option-title">
<Icon icon="ant-design:sync-outlined" size="16" />
<span>重复发起</span>
</div>
<div class="option-desc">按指定周期自动生成多条流程适用于定期重复任务</div>
</div>
</div>
</a-radio-group>
<a-form-item label="所党委领导">
<a-input
v-model:value="supDeptleaderName"
placeholder="请选择所党委领导"
:disabled="String(formData.isNeedAppro) !== '1'"
readonly
allow-clear
@click="openSdwLeaderModal"
@clear="handleClearSdwLeader"
>
<template #suffix>
<SearchOutlined @click="openSdwLeaderModal" />
</template>
</a-input>
</a-form-item>
</template>
<!-- 表单区域 -->
<div class="form-section">
<div class="section-title">流程参数</div>
<template v-if="formData.triggerMode === 'recurring'">
<a-form-item label="重复周期">
<JDictSelectTag
v-model:value="formData.intervalType"
dictCode="sup_interval_type"
placeholder="重复周期"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
<a-form :model="formData" layout="vertical">
<a-form-item v-if="deptOptions.length" label="牵头部门">
<a-select
v-model:value="formData.deptIds"
mode="multiple"
:options="deptOptions"
placeholder="请选择牵头部门"
allow-clear
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
<a-form-item label="重复次数">
<a-input-number v-model:value="formData.startCount" :min="1" :precision="0" placeholder="重复次数" style="width: 100%" />
</a-form-item>
<a-form-item v-if="showDeadlineField" label="事项截止时间">
<a-date-picker
v-model:value="formData.deadline"
valueFormat="YYYY-MM-DD"
placeholder="请选择事项截止时间"
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
<a-form-item label="重复开始日期">
<a-date-picker
v-model:value="formData.intervalStartTime"
valueFormat="YYYY-MM-DD"
placeholder="重复开始日期"
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
</template>
</a-form>
<template v-if="showSuoleaderFields">
<a-divider style="margin: 12px 0" />
<div class="section-title">所党委审批设置</div>
<a-form-item label="是否所党委审批">
<a-switch v-model:checked="needApproSwitch" checked-children="" un-checked-children="" />
</a-form-item>
<a-form-item label="所党委领导">
<a-input
v-model:value="supDeptleaderName"
placeholder="请选择所党委领导"
:disabled="!needApproSwitch"
readonly
allow-clear
@click="openSdwLeaderModal"
@clear="handleClearSdwLeader"
>
<template #suffix>
<SearchOutlined @click="openSdwLeaderModal" />
</template>
</a-input>
</a-form-item>
</template>
<!-- 重复发起配置 -->
<template v-if="formData.triggerMode === 'recurring'">
<a-divider style="margin: 12px 0" />
<div class="section-title">重复发起配置</div>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="重复周期">
<JDictSelectTag
v-model:value="formData.intervalType"
dictCode="sup_interval_type"
placeholder="重复周期"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="重复次数">
<a-input-number v-model:value="formData.startCount" :min="1" :precision="0" placeholder="重复次数" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="开始日期">
<a-date-picker
v-model:value="formData.intervalStartTime"
valueFormat="YYYY-MM-DD"
placeholder="开始日期"
style="width: 100%"
:getPopupContainer="(node) => node?.parentNode"
/>
</a-form-item>
</a-col>
</a-row>
</template>
</a-form>
</div>
</div>
<div class="modal-footer">
<a-button @click="handleCancel">取消</a-button>
<a-button type="primary" @click="handleOk">发起流程</a-button>
</div>
<SzUserSelectByDeptRoleSecurityModal
v-model:open="sdwLeaderModalOpen"
@@ -86,19 +163,13 @@
:securityValue="sdwLeaderSecurityValue"
@confirm="handleSdwLeaderConfirm"
/>
<template #footer>
<a-button @click="handleCancel">取消</a-button>
<a-button type="primary" @click="handleOk">提交</a-button>
</template>
</j-modal>
</a-modal>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue';
import JModal from '/src/components/Modal/src/JModal/JModal.vue';
import { reactive, ref, watch, computed } from 'vue';
import JDictSelectTag from '/src/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JSwitch from '/src/components/Form/src/jeecg/components/JSwitch.vue';
import Icon from '/@/components/Icon/index';
import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervision';
import SzUserSelectByDeptRoleSecurityModal from '/src/components/semri/userComponent/modal/SzUserSelectByDeptRoleSecurityModal.vue';
import { SearchOutlined } from '@ant-design/icons-vue';
@@ -132,13 +203,30 @@ import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervi
const showSuoleaderFields = ref(false);
const showDeadlineField = ref(false);
// 所党委领导选人弹窗
const sdwLeaderModalOpen = ref(false);
const supDeptleaderName = ref('');
const sdwLeaderDeptId = ref(PARTY_COMMITTEE_DEPT_ID);
const sdwLeaderRoleId = ref(SDW_LEADER_ROLE_ID);
const sdwLeaderSecurityValue = ref(5);
const formData = reactive({
triggerMode: 'immediate',
intervalType: undefined as number | string | undefined,
startCount: undefined as number | undefined,
intervalStartTime: undefined as string | undefined,
deptIds: [] as string[],
isNeedAppro: '0',
supDeptleaderid: '' as string | string[],
deadline: undefined as string | undefined,
});
const needApproSwitch = computed({
get: () => String(formData.isNeedAppro) === '1',
set: (val: boolean) => {
formData.isNeedAppro = val ? '1' : '0';
},
});
function openSdwLeaderModal() {
if (String(formData.isNeedAppro) !== '1') return;
sdwLeaderModalOpen.value = true;
@@ -169,17 +257,6 @@ import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervi
}
}
const formData = reactive({
triggerMode: 'immediate',
intervalType: undefined as number | string | undefined,
startCount: undefined as number | undefined,
intervalStartTime: undefined as string | undefined,
deptIds: [] as string[],
isNeedAppro: '0',
supDeptleaderid: '' as string | string[],
deadline: undefined as string | undefined,
});
function resetForm() {
formData.triggerMode = 'immediate';
formData.intervalType = undefined;
@@ -304,3 +381,121 @@ import { PARTY_COMMITTEE_DEPT_ID, SDW_LEADER_ROLE_ID } from '/@/constant/supervi
open,
});
</script>
<style lang="less" scoped>
.modal-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: 600;
}
.modal-content {
padding: 4px 0;
}
.section-title {
font-size: 13px;
font-weight: 600;
color: #595959;
margin-bottom: 10px;
&::before {
content: '';
display: inline-block;
width: 3px;
height: 14px;
background: #1890ff;
border-radius: 2px;
margin-right: 8px;
vertical-align: -2px;
}
}
.form-section {
margin-top: 20px;
}
.trigger-radio-group {
display: flex;
gap: 12px;
width: 100%;
}
.trigger-option {
flex: 1;
display: flex;
align-items: flex-start;
padding: 14px 16px;
border: 1px solid #e8e8e8;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
&:hover {
border-color: #91d5ff;
background: #f0f8ff;
}
&.active {
border-color: #1890ff;
background: #e6f7ff;
box-shadow: 0 0 0 1px #1890ff inset;
}
}
.option-radio {
margin-top: 2px;
margin-right: 12px;
flex-shrink: 0;
}
.option-body {
flex: 1;
min-width: 0;
}
.option-title {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 500;
color: #262626;
margin-bottom: 4px;
}
.option-desc {
font-size: 12px;
color: #8c8c8c;
line-height: 1.6;
padding-left: 22px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 8px;
}
</style>
<style lang="less">
.flow-schedule-start-modal {
.ant-modal-body {
padding: 20px 24px;
}
.ant-form-item {
margin-bottom: 14px;
.ant-form-item-label > label {
font-weight: 500;
color: #595959;
}
}
}
</style>
+12 -1
View File
@@ -21,7 +21,7 @@
<!-- </a-col>-->
<a-col :lg="6">
<a-form-item name="bpmStatus" label="督办状态">
<a-select v-model:value="queryParam.bpmStatus" placeholder="请选择" allow-clear @change="searchQuery">
<a-select v-model:value="bpmStatusFilter" placeholder="请选择" allow-clear @change="handleBpmStatusChange">
<a-select-option value="1">未开始</a-select-option>
<a-select-option value="2">督办中</a-select-option>
<a-select-option value="3">已完成</a-select-option>
@@ -167,6 +167,7 @@ import { defHttp } from '/@/utils/http/axios';
const feedbackViewModalRef = ref();
const feedbackRightNowModalRef = ref();
const businessProcessListModalRef = ref();
const bpmStatusFilter = ref();
const currentBusinessId = ref('');
const pendingFeedbackRightNow = ref(0);
const statsData = reactive({ notStarted: 0, inProgress: 0, overdue: 0, completed: 0 });
@@ -880,10 +881,20 @@ import { defHttp } from '/@/utils/http/axios';
function searchReset() {
formRef.value?.resetFields();
clearQueryParams();
bpmStatusFilter.value = undefined;
selectedRowKeys.value = [];
reload({ page: 1 });
}
function handleBpmStatusChange(value) {
if (value != null) {
queryParam.value.bpmStatus = value;
} else {
delete queryParam.value.bpmStatus;
}
reload({ page: 1 });
}
/**
* form点击事件(以逗号分割)
*/
@@ -1,30 +1,79 @@
<template>
<JModal
title="发起落实措施收集流程"
:width="480"
:visible="visible"
<a-modal
:width="520"
:open="visible"
:confirmLoading="confirming"
okText="确认"
cancelText="取消"
@ok="handleOk"
:footer="null"
@cancel="handleCancel"
wrapClassName="feedback-right-now-modal"
>
<a-form :label-col="{ style: { width: '100%' } }">
<a-form-item>
<a-radio-group v-model:value="feedbackRightNow">
<a-space direction="vertical">
<a-radio :value="1">落实措施收集流程结束后需要立即反馈</a-radio>
<a-radio :value="0">无需立即反馈</a-radio>
</a-space>
</a-radio-group>
</a-form-item>
</a-form>
</JModal>
<template #title>
<div class="modal-title">
<Icon icon="ant-design:send-outlined" size="20" color="#1890ff" />
<span>发起落实措施收集流程</span>
</div>
</template>
<div class="modal-content">
<a-alert
message="选择反馈方式"
description="发起流程后,系统将根据所选方式决定是否在流程结束时自动生成反馈任务。"
type="info"
showIcon
style="margin-bottom: 16px"
/>
<a-radio-group v-model:value="feedbackRightNow" class="feedback-radio-group">
<div
class="feedback-option"
:class="{ active: feedbackRightNow === 1 }"
@click="feedbackRightNow = 1"
>
<div class="option-radio">
<a-radio :value="1" />
</div>
<div class="option-body">
<div class="option-title">
<Icon icon="ant-design:notification-outlined" size="18" />
<span>流程结束后需要立即反馈</span>
</div>
<div class="option-desc">
流程审批完成后将自动生成反馈任务通知相关人员及时提交落实反馈适用于需快速跟进的场景
</div>
</div>
</div>
<div
class="feedback-option"
:class="{ active: feedbackRightNow === 0 }"
@click="feedbackRightNow = 0"
>
<div class="option-radio">
<a-radio :value="0" />
</div>
<div class="option-body">
<div class="option-title">
<Icon icon="ant-design:clock-circle-outlined" size="18" />
<span>无需立即反馈</span>
</div>
<div class="option-desc">
仅发起流程不自动生成即时反馈任务后续可在台账中手动发起反馈
</div>
</div>
</div>
</a-radio-group>
</div>
<div class="modal-footer">
<a-button @click="handleCancel">取消</a-button>
<a-button type="primary" :loading="confirming" @click="handleOk">确认发起</a-button>
</div>
</a-modal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
import Icon from '/@/components/Icon/index';
const emit = defineEmits(['confirm']);
@@ -53,3 +102,90 @@
defineExpose({ open });
</script>
<style lang="less" scoped>
.modal-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: 600;
}
.modal-content {
padding: 8px 0;
}
.feedback-radio-group {
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
}
.feedback-option {
display: flex;
align-items: flex-start;
padding: 14px 16px;
border: 1px solid #e8e8e8;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
&:hover {
border-color: #91d5ff;
background: #f0f8ff;
}
&.active {
border-color: #1890ff;
background: #e6f7ff;
box-shadow: 0 0 0 1px #1890ff inset;
}
}
.option-radio {
margin-top: 2px;
margin-right: 12px;
flex-shrink: 0;
}
.option-body {
flex: 1;
min-width: 0;
}
.option-title {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 500;
color: #262626;
margin-bottom: 4px;
}
.option-desc {
font-size: 12px;
color: #8c8c8c;
line-height: 1.6;
padding-left: 24px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
margin-top: 4px;
}
</style>
<style lang="less">
.feedback-right-now-modal {
.ant-modal-body {
padding: 20px 24px;
}
}
</style>