diff --git a/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql b/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql index 41600f82..0dc1e16f 100644 --- a/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql +++ b/script/sql/zfjd-refactoring-v1/013-计划任务表设计.sql @@ -24,7 +24,7 @@ CREATE TABLE `efcode_cp_plan` `is_union` tinyint NOT NULL DEFAULT 1 COMMENT '是否联合执法:1=是,0=否', `union_bureau_dept_names` varchar(500) DEFAULT NULL COMMENT '联合执法单位(多个逗号分隔)', - `reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态:0=草稿,1=待预约(未发起联合),2=预约中,3=预约完成,4=重新预约中,5=待预约(还有位置可以加入),6=待预约(人数已满)', + `reserve_status` tinyint NOT NULL DEFAULT 0 COMMENT '预约状态:0=草稿,1=待预约(未发起联合),2=预约中,3=预约完成,4=重新预约中,5=待预约(还有位置可以加入),6=待预约(人数已满),7=预约完成(人数已满)', `task_id` varchar(50) NULL DEFAULT '' COMMENT '任务id:空串表示还没生成任务', `system_reserved` tinyint NOT NULL DEFAULT 0 COMMENT '是否已经经过系统推荐预约:1=是,0=否', diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpPlanVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpPlanVo.java index b8006d4a..26cd18b2 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpPlanVo.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpPlanVo.java @@ -236,5 +236,11 @@ public class EfcodeCpPlanVo implements Serializable { @com.baomidou.mybatisplus.annotation.TableField(exist = false) private Boolean canReserve; + /** + * 关联的预约记录列表(非数据库字段,后置填充) + */ + @com.baomidou.mybatisplus.annotation.TableField(exist = false) + private java.util.List reserves; + } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java index 9095a4b4..285b3989 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EfcodeCpReserveVo.java @@ -96,6 +96,16 @@ public class EfcodeCpReserveVo implements Serializable { @ExcelProperty(value = "来自:系统匹配=1,手动匹配=0") private Long resFrom; + /** + * 发送者用户ID + */ + private String senderId; + + /** + * 接收者用户ID + */ + private String receiverId; + // ===== 计划关联字段(非数据库映射,由服务层填充) ===== /** 计划日期 */ @@ -116,5 +126,8 @@ public class EfcodeCpReserveVo implements Serializable { /** 执法人员姓名 */ private String enforceUserNames; + /** 执法人员电话号码 */ + private String enforceUserTels; + } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java index 0e8e2dd1..005a228d 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpPlanServiceImpl.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.zdxt.enforcementcode.domain.bo.EfcodeCpPlanBo; import com.zdxt.enforcementcode.domain.vo.EfcodeCpPlanVo; +import com.zdxt.enforcementcode.domain.vo.EfcodeCpReserveVo; import com.zdxt.enforcementcode.domain.EfcodeCpPlan; import com.zdxt.enforcementcode.domain.EfcodeCpPlanUsers; import com.zdxt.enforcementcode.mapper.EfcodeCpPlanMapper; @@ -81,6 +82,8 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); // 后置计算 editEnable computeEditEnable(result.getRecords()); + // 后置填充关联预约记录 + fillReserves(result.getRecords()); return TableDataInfo.build(result); } @@ -162,6 +165,109 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { } } + /** + * 后置填充关联预约记录:通过plan_group_id查询同组的其他计划信息,组装为1:N结构 + *

展示逻辑:对于我的每条计划,找到同一plan_group_id下的其他计划,将对方的单位/人员/电话/执法事项填充到reserve VO中

+ */ + private void fillReserves(List records) { + if (records == null || records.isEmpty()) { + return; + } + List myPlanIds = records.stream().map(EfcodeCpPlanVo::getId).collect(Collectors.toList()); + if (myPlanIds.isEmpty()) { + return; + } + + // 1. 查询我的计划关联的预约记录,获取plan_group_id + List myReserves = efcodeCpReserveMapper.selectList( + Wrappers.lambdaQuery() + .in(EfcodeCpReserve::getPlanId, myPlanIds) + ); + if (myReserves.isEmpty()) { + records.forEach(vo -> vo.setReserves(new ArrayList<>())); + return; + } + + // 2. 建立 我的planId → plan_group_id 的映射 + Map planToGroupMap = new HashMap<>(); + Set groupIds = new HashSet<>(); + for (EfcodeCpReserve r : myReserves) { + if (StringUtils.isNotBlank(r.getPlanGroupId())) { + planToGroupMap.put(r.getPlanId(), r.getPlanGroupId()); + groupIds.add(r.getPlanGroupId()); + } + } + + if (groupIds.isEmpty()) { + records.forEach(vo -> vo.setReserves(new ArrayList<>())); + return; + } + + // 3. 查询同组的其他预约记录(plan_id不是我的计划) + List otherReserves = efcodeCpReserveMapper.selectList( + Wrappers.lambdaQuery() + .in(EfcodeCpReserve::getPlanGroupId, groupIds) + .notIn(EfcodeCpReserve::getPlanId, myPlanIds) + .orderByDesc(EfcodeCpReserve::getReserveTime) + ); + + // 4. 查询其他计划的详情(单位、人员、电话、执法事项) + Set otherPlanIds = otherReserves.stream() + .map(EfcodeCpReserve::getPlanId) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + Map otherPlanMap = new HashMap<>(); + if (!otherPlanIds.isEmpty()) { + List otherPlans = baseMapper.selectByIds(new ArrayList<>(otherPlanIds)); + for (EfcodeCpPlan p : otherPlans) { + otherPlanMap.put(p.getId(), p); + } + } + + // 5. 按plan_group_id分组其他预约记录 + Map> groupToOtherReserves = otherReserves.stream() + .collect(Collectors.groupingBy(EfcodeCpReserve::getPlanGroupId)); + + // 6. 填充到每条计划VO + for (EfcodeCpPlanVo vo : records) { + String groupId = planToGroupMap.get(vo.getId()); + if (StringUtils.isBlank(groupId)) { + vo.setReserves(new ArrayList<>()); + continue; + } + List others = groupToOtherReserves.getOrDefault(groupId, new ArrayList<>()); + List voList = others.stream().map(r -> { + EfcodeCpReserveVo rv = new EfcodeCpReserveVo(); + rv.setId(r.getId()); + rv.setPlanId(r.getPlanId()); + rv.setPlanGroupId(r.getPlanGroupId()); + rv.setReserveTime(r.getReserveTime()); + rv.setOpStatus(r.getOpStatus()); + rv.setOpOrder(r.getOpOrder()); + rv.setOpTime(r.getOpTime()); + rv.setOpMessage(r.getOpMessage()); + rv.setOpSetDate(r.getOpSetDate()); + rv.setOpSetTime(r.getOpSetTime()); + rv.setResFrom(r.getResFrom()); + rv.setSenderId(r.getSenderId()); + rv.setReceiverId(r.getReceiverId()); + // 填充对方计划详情 + EfcodeCpPlan otherPlan = otherPlanMap.get(r.getPlanId()); + if (otherPlan != null) { + rv.setBureauDeptName(otherPlan.getBureauDeptName()); + rv.setEnforceUserNames(otherPlan.getEnforceUserNames()); + rv.setEnforceUserTels(otherPlan.getEnforceUserTels()); + rv.setEnforceContent(otherPlan.getEnforceContent()); + rv.setPlanDate(otherPlan.getPlanDate()); + rv.setPlanTime(otherPlan.getPlanTime()); + rv.setEnterpriseName(otherPlan.getEnterpriseName()); + } + return rv; + }).collect(Collectors.toList()); + vo.setReserves(voList); + } + } + private LambdaQueryWrapper buildQueryWrapper(EfcodeCpPlanBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); @@ -327,7 +433,7 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { * @throws ServiceException 如果存在重复记录则抛出 */ private void checkDuplicate(EfcodeCpPlanBo bo) { - if (bo.getPlanType() == null || bo.getPlanDate() == null || bo.getPlanTime() == null + if (bo.getPlanDate() == null || bo.getPlanTime() == null || StringUtils.isBlank(bo.getEnterpriseId())) { return; } @@ -336,9 +442,8 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { if (StringUtils.isBlank(currentUserId) || "null".equals(currentUserId)) { return; } - // 1) 查找同计划类型+同日期+同时段+同企业的已有计划 + // 1) 查找同日期+同时段+同企业的已有计划(不限制计划类型) LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(EfcodeCpPlan::getPlanType, bo.getPlanType()); lqw.eq(EfcodeCpPlan::getPlanDate, bo.getPlanDate()); lqw.eq(EfcodeCpPlan::getPlanTime, bo.getPlanTime()); lqw.eq(EfcodeCpPlan::getEnterpriseId, bo.getEnterpriseId()); @@ -360,7 +465,7 @@ public class EfcodeCpPlanServiceImpl implements IEfcodeCpPlanService { .eq(EfcodeCpPlanUsers::getUserId, currentUserId) ); if (count > 0) { - throw new ServiceException("您在该日期该时段对该企业已有同类型执法计划,不可重复提交"); + throw new ServiceException("您在该日期该时段对该企业已有执法计划,不可重复提交"); } } diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java index d1253830..ae99dbfd 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java +++ b/zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpReserveServiceImpl.java @@ -167,7 +167,7 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { } /** - * 预约前置检查 + * 预约前置检查(包含所有前置校验逻辑) */ @Override public R checkCanReserve(String targetPlanId) { @@ -177,11 +177,48 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { if (targetPlan == null) { return R.fail("目标计划不存在"); } + // 1.1 校验目标计划状态:只有待预约(1)、已取消(4)、预约中可加入(5)的计划才允许预约 + Long reserveStatus = targetPlan.getReserveStatus(); + if (reserveStatus == null || !Arrays.asList(1L, 4L, 5L).contains(reserveStatus)) { + return R.fail("该计划当前状态不允许预约"); + } // 2. 判断当前用户是否有同一时间+同一时段+同一企业的计划 EfcodeCpPlan myPlan = findMyMatchingPlan(targetPlan, currentUserId); if (myPlan == null) { return R.fail("请先添加我的计划再进行预约"); } + // 2.1 校验我的计划状态:只有待预约(1)、已取消(4)、预约中可加入(5)的计划才允许发起预约 + Long myReserveStatus = myPlan.getReserveStatus(); + if (myReserveStatus == null || !Arrays.asList(1L, 4L, 5L).contains(myReserveStatus)) { + return R.fail("您的计划当前状态不允许发起预约"); + } + // 2.2 我的计划在efcode_cp_reserve只能存在一条op_status为3的记录 + long pendingCount = baseMapper.selectCount( + Wrappers.lambdaQuery() + .eq(EfcodeCpReserve::getPlanId, myPlan.getId()) + .eq(EfcodeCpReserve::getOpStatus, 3L) + ); + if (pendingCount > 0) { + return R.fail("您的这条计划已有一条待确认的预约记录,请等待对方处理后再发起新预约"); + } + // 2.3 如果我的计划已经作为plan_group_id而存在,则不允许发起预约,除非其他的所有记录的op_status都是2或4 + String myPlanId = myPlan.getId(); + long groupCount = baseMapper.selectCount( + Wrappers.lambdaQuery() + .eq(EfcodeCpReserve::getPlanGroupId, myPlanId) + ); + if (groupCount > 0) { + List otherReserves = baseMapper.selectList( + Wrappers.lambdaQuery() + .eq(EfcodeCpReserve::getPlanGroupId, myPlanId) + .ne(EfcodeCpReserve::getPlanId, myPlanId) + ); + boolean allRejectedOrCancelled = otherReserves.stream() + .allMatch(r -> r.getOpStatus() != null && (r.getOpStatus() == 2L || r.getOpStatus() == 4L)); + if (!allRejectedOrCancelled) { + return R.fail("您的计划已有进行中的预约分组,无法再发起新预约"); + } + } // 3. 判断 plan_group_id 人数是否已达上限 String planGroupId = findExistingPlanGroupId(targetPlanId); if (planGroupId != null) { @@ -205,17 +242,16 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { @Transactional(rollbackFor = Exception.class) @Override public R doReserve(String targetPlanId, String opMessage) { + // 前置校验(与 checkCanReserve 一致) + R checkResult = checkCanReserve(targetPlanId); + if (checkResult.getCode() != 200) { + return checkResult; + } + Long currentUserId = LoginHelper.getUserId(); - // 1. 查询目标计划 EfcodeCpPlan targetPlan = cpPlanMapper.selectById(targetPlanId); - if (targetPlan == null) { - return R.fail("目标计划不存在"); - } - // 2. 查找当前用户匹配的计划 EfcodeCpPlan myPlan = findMyMatchingPlan(targetPlan, currentUserId); - if (myPlan == null) { - return R.fail("请先添加我的计划再进行预约"); - } + // 3. 判断目标计划在reserve表中是否已存在 String planGroupId = findExistingPlanGroupId(targetPlanId); int maxUnionUnit = cpSettingService.getMaxUnionUnit(); @@ -229,9 +265,9 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { String senderIdStr = String.valueOf(currentUserId); String receiverIdStr = String.valueOf(targetPlan.getCreateBy()); // 目标计划记录 - insertReserveRecord(targetPlanId, planGroupId, "", targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, senderIdStr, receiverIdStr); + insertReserveRecord(targetPlanId, planGroupId, "", targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, 1L, "manual_system_sender", receiverIdStr); // 我的计划记录 - insertReserveRecord(myPlan.getId(), planGroupId, opMessage, targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, senderIdStr, receiverIdStr); + insertReserveRecord(myPlan.getId(), planGroupId, opMessage, targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, 3L, senderIdStr, receiverIdStr); } else { // 已存在:检查人数上限 long activeCount = countActiveReserves(planGroupId); @@ -244,7 +280,7 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { return R.fail("您已经预约过该计划"); } // 插入1条记录 - insertReserveRecord(myPlan.getId(), planGroupId, opMessage, targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, String.valueOf(currentUserId), String.valueOf(targetPlan.getCreateBy())); + insertReserveRecord(myPlan.getId(), planGroupId, opMessage, targetPlan.getPlanDate(), targetPlan.getPlanTime(), 0L, 3L, String.valueOf(currentUserId), String.valueOf(targetPlan.getCreateBy())); } // ===== 插入预约记录后:更新两个计划的 reserve_status ===== @@ -323,16 +359,17 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { /** * 插入一条预约记录 * + * @param opStatus 操作状态:1=同意,2=拒绝,3=待确认,4=超期取消 * @param senderId 发送者用户ID * @param receiverId 接收者用户ID */ private void insertReserveRecord(String planId, String planGroupId, String opMessage, Date opSetDate, Long opSetTime, Long resFrom, - String senderId, String receiverId) { + Long opStatus, String senderId, String receiverId) { EfcodeCpReserve record = new EfcodeCpReserve(); record.setPlanId(planId); record.setPlanGroupId(planGroupId); record.setReserveTime(new Date()); - record.setOpStatus(3L); // 待确认 + record.setOpStatus(opStatus); record.setOpOrder(0L); record.setOpMessage(opMessage); record.setOpSetDate(opSetDate); @@ -389,6 +426,17 @@ public class EfcodeCpReserveServiceImpl implements IEfcodeCpReserveService { */ private void afterOperate(EfcodeCpReserve reserve, String action) { log.info("预约记录[{}]执行{}操作后置处理, planGroupId={}", reserve.getId(), action, reserve.getPlanGroupId()); + + // 同步更新对应计划的 reserve_status:同意→3(预约完成),拒绝→4(重新预约中) + if (StringUtils.isNotBlank(reserve.getPlanId())) { + Long newPlanStatus = "approve".equals(action) ? 3L : 4L; + EfcodeCpPlan planUpdate = new EfcodeCpPlan(); + planUpdate.setId(reserve.getPlanId()); + planUpdate.setReserveStatus(newPlanStatus); + cpPlanMapper.updateById(planUpdate); + log.info("[预约后置] 计划[{}] reserve_status 更新为 {}", reserve.getPlanId(), newPlanStatus); + } + // 同意操作后:检查同一 planGroupId 已同意数量是否达到最大联合单位数 if ("approve".equals(action) && StringUtils.isNotBlank(reserve.getPlanGroupId())) { int maxUnionUnit = cpSettingService.getMaxUnionUnit(); diff --git a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml index f517a5f3..f2d02061 100644 --- a/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml +++ b/zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeCpReserveMapper.xml @@ -23,10 +23,12 @@ p.enterprise_name, p.enforce_content, p.bureau_dept_name, - p.enforce_user_names + p.enforce_user_names, + p.enforce_user_tels FROM efcode_cp_reserve r LEFT JOIN efcode_cp_plan p ON r.plan_id = p.id + r.sender_id != 'manual_system_sender' AND r.res_from = #{resFrom} diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/task.js b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/task.js new file mode 100644 index 00000000..4b42f453 --- /dev/null +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/task.js @@ -0,0 +1,16 @@ +import { _get } from "@/http/index"; + +// region 任务管理接口 + +const taskBaseUrl = "/app-enf/cpTask"; + +// 我的任务列表(指定日期) +export const getMyTaskList = (params, success, error) => _get(taskBaseUrl + "/myList", params, success, error); + +// 指定月份中有任务的日期列表(日历打点) +export const getMyTaskDates = (yearMonth, success, error) => _get(taskBaseUrl + "/myTaskDates", { yearMonth }, success, error); + +// 我的任务详情(通过 planId 查询) +export const getMyTaskDetail = (planId, success, error) => _get(taskBaseUrl + "/myDetail", { planId }, success, error); + +// endregion diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_list.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_list.vue index 3be25f55..afd3bfa1 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_list.vue +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_list.vue @@ -25,8 +25,8 @@ - -
+ +
diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue index c0e39875..299933f9 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue @@ -39,7 +39,11 @@ v-for="(item, index) in planList" :key="item.id" class="plan-card normal-card" - :class="{ 'pending-card': item.reserveStatus === 1 }" + :class="{ + 'pending-card': item.reserveStatus === 1, + 'expanded-card': expandedId === item.id + }" + @click="onToggleExpand(item)" >
{{ item.isUnion === 1 ? '联合执法' : '非联合执法' }}
@@ -74,11 +78,53 @@
{{ item.enterpriseName }}
+ +
+
关联预约信息
+
+
+ 状态: + {{ getOpStatusText(rv.opStatus) }} +
+
+ 对方单位: + {{ rv.bureauDeptName }} +
+
+ 执法人员: + {{ rv.enforceUserNames }} +
+
+ 联系电话: + {{ rv.enforceUserTels }} +
+
+ 执法事项: + {{ rv.enforceContent }} +
+
+ 留言: + {{ rv.opMessage }} +
+
+ 来源: + {{ rv.resFrom === 1 ? '系统匹配' : '手动预约' }} +
+
+
+
+
暂无关联预约记录
+
+
编辑 @@ -86,7 +132,7 @@
删除 @@ -239,10 +285,16 @@ const finished = ref(false); const refreshing = ref(false); const pageNum = ref(1); const pageSize = 10; +const expandedId = ref(null); // 当前展开的卡片ID + +// 切换展开/收起 +const onToggleExpand = (item) => { + expandedId.value = expandedId.value === item.id ? null : item.id; +}; // 状态文本映射 const getStatusText = (status) => { - const map = { 0: '草稿', 1: '待预约', 2: '预约中', 3: '预约完成' }; + const map = { 0: '草稿', 1: '待预约(未发起联合)', 2: '预约中', 3: '预约完成', 4: '重新预约中', 5: '待预约(还有位置可以加入)', 6: '待预约(人数已满)', 7: '预约完成(人数已满)' }; return map[status] || '待确认'; }; @@ -258,6 +310,18 @@ const getPersonList = (item) => { return item.enforceUserNames.split(','); }; +// 预约操作状态文本 +const getOpStatusText = (status) => { + const map = { 1: '已同意', 2: '已拒绝', 3: '待确认', 4: '超期取消' }; + return map[status] || '未知'; +}; + +// 格式化日期时间 +const formatDateTime = (dateStr) => { + if (!dateStr) return '-'; + return String(dateStr).substring(0, 16).replace('T', ' '); +}; + // 加载数据 const onLoad = () => { fetchList(); @@ -500,6 +564,103 @@ const onDeletePlan = (item) => { border: 1.5px solid rgba(35, 130, 207, 0.35); } +/* 展开状态卡片:深蓝渐变背景(同预约处理选中效果) */ +.expanded-card { + background: radial-gradient(circle at 78% 5%, rgba(65, 188, 255, 0.75) 0, rgba(65, 188, 255, 0.25) 20%, transparent 42%), + linear-gradient(135deg, #064ec6 0%, #0b63d9 48%, #268ee5 100%) !important; + border-color: transparent; + box-shadow: 0 6px 20px rgba(6, 78, 198, 0.25) !important; + + .card-type { + background: rgba(255, 255, 255, 0.15) !important; + color: rgba(255, 255, 255, 0.9) !important; + } + + .plan-title { + color: #fff !important; + } + + .label { + color: #fff !important; + } + + .value { + color: rgba(255, 255, 255, 0.7) !important; + } + + .status { + color: #f0b66c !important; + } + + .card-actions { + border-top-color: rgba(255, 255, 255, 0.18); + } + + .action-item { + color: rgba(255, 255, 255, 0.85); + } +} + +/* 预约信息展开区域 */ +.reserve-section { + margin-top: 14px; + padding-top: 12px; + border-top: 1px dashed rgba(255, 255, 255, 0.25); + + .reserve-section-title { + font-size: 14px; + font-weight: 600; + color: rgba(255, 255, 255, 0.9); + margin-bottom: 10px; + } + + .reserve-empty { + font-size: 13px; + color: rgba(255, 255, 255, 0.6); + text-align: center; + padding: 8px 0; + } +} + +.reserve-item { + background: rgba(255, 255, 255, 0.12); + border-radius: 10px; + padding: 10px 12px; + margin-bottom: 8px; + + &:last-child { + margin-bottom: 0; + } +} + +.reserve-row { + display: flex; + align-items: center; + margin-bottom: 4px; + font-size: 13px; + + &:last-child { + margin-bottom: 0; + } + + .reserve-label { + width: 70px; + flex-shrink: 0; + color: rgba(255, 255, 255, 0.75); + font-weight: 500; + } + + .reserve-value { + flex: 1; + color: rgba(255, 255, 255, 0.85); + } + + .op-status-1 { color: #7dffaa; font-weight: 500; } + .op-status-2 { color: #ff8a8a; font-weight: 500; } + .op-status-3 { color: #f0b66c; font-weight: 500; } + .op-status-4 { color: rgba(255, 255, 255, 0.5); font-weight: 500; } +} + /* 普通卡片 */ .normal-card { background: #fff; diff --git a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue index 556e717b..6ec22915 100644 --- a/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue +++ b/zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/reserve/cp_reserve_manual.vue @@ -44,7 +44,17 @@
计划时间:
-
{{ item.planDate || '-' }} {{ getPlanTimeText(item.planTime) }}
+
{{ formatPlanDate(item.planDate) }} {{ getPlanTimeText(item.planTime) }}
+
+ +
+
执法人员:
+
{{ item.enforceUserNames || '-' }}
+
+ +
+
联系电话:
+
{{ item.enforceUserTels || '-' }}
@@ -124,6 +134,12 @@ const getPlanTimeText = (time) => { return map[time] || ''; }; +// 格式化计划日期(只取年月日,去掉时分秒) +const formatPlanDate = (dateStr) => { + if (!dateStr) return '-'; + return String(dateStr).substring(0, 10); +}; + // 格式化日期 const formatDate = (dateStr) => { if (!dateStr) return '-';