Browse Source

Merge remote-tracking branch 'origin/dev' into dev

dev-V1.0.1
庄锐波 6 months ago
parent
commit
cff90df956
  1. 20
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java
  2. 8
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEnterpriseComplaintController.java
  3. 27
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEnterpriseMineController.java
  4. 37
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/UpdatePhoneBo.java
  5. 12
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EnterpriseUserVo.java
  6. 10
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EnterpriseUserRefMapper.java
  7. 2
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/enterprise/AppEnterpriseComplaintMapper.java
  8. 9
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseUserService.java
  9. 23
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/IAppEnterpriseMineService.java
  10. 14
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppEnterpriseComplaintServiceImpl.java
  11. 40
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppEnterpriseMineServiceImpl.java
  12. 10
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppLawEnforcementCaseServiceImpl.java
  13. 18
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseEvaluateServiceImpl.java
  14. 55
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseUserServiceImpl.java
  15. 19
      zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EnterpriseUserRefMapper.xml
  16. 14
      zdxt-web-client/zdxt-efcode-enterprise-app/src/api/enterprise/index.js
  17. 70
      zdxt-web-client/zdxt-efcode-enterprise-app/src/components/complaint/ComplaintItemPicker.vue
  18. 22
      zdxt-web-client/zdxt-efcode-enterprise-app/src/components/enterprise/footerNav.vue
  19. 7
      zdxt-web-client/zdxt-efcode-enterprise-app/src/router/enterprise-app/ent-main-router.js
  20. 35
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/auth/login.vue
  21. 19
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementEvaluate.vue
  22. 43
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementEvaluateDetail.vue
  23. 10
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/home/enterpriseHomeV2.vue
  24. 312
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawQuery.vue
  25. 110
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawServiceDetail.vue
  26. 28
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawServiceList.vue
  27. 85
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/message/messageCenter.vue
  28. 82
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/complaintDetail.vue
  29. 177
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/complaintSuggestion.vue
  30. 18
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/settings.vue
  31. 44
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/qr/qrCode.vue
  32. 30
      zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml
  33. 1
      zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml

20
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEntEnterpriseInformationController.java

@ -72,7 +72,6 @@ public class AppEntEnterpriseInformationController {
* 查询企业最新的有效二维码记录,返回二维码URL、企业名称、生成时间
* </p>
*
* @param enterpriseNumber 企业纳税识别号
* @return 二维码信息(qrCodeUrl, enterpriseName, generateTime)
*/
@SaIgnore
@ -116,23 +115,26 @@ public class AppEntEnterpriseInformationController {
* 返回新二维码URL、企业名称、生成时间
* </p>
*
* @param enterpriseNumber 企业纳税识别号
* @return 二维码信息(qrCodeUrl, enterpriseName, generateTime)
*/
@SaIgnore
@GetMapping("/forceGenerateQrCode/{enterpriseNumber}")
public R<Map<String, Object>> forceGenerateQrCode(@PathVariable String enterpriseNumber) {
if (enterpriseNumber == null || enterpriseNumber.trim().isEmpty()) {
return R.fail("企业纳税识别号不能为空");
}
@GetMapping("/forceGenerateQrCode")
public R<Map<String, Object>> forceGenerateQrCode() {
//根据当前登录用户部门ID 查询企业统一信用代码
LambdaQueryWrapper<EnterpriseInformation> lqw = Wrappers.lambdaQuery();
lqw.eq(EnterpriseInformation::getDeptId, LoginHelper.getDeptId());
EnterpriseInformation enterpriseInformation = enterpriseInformationMapper.selectOne(lqw);
if(enterpriseInformation == null){
return R.fail("企业纳税识别号不存在");
}
// 1. 强制生成二维码(跳过历史记录检查)
QrCodeGenerateHistoryVo qrCodeVo = enterpriseInformationService.forceGenerateQrCode(
"", enterpriseNumber, "app.enterprise", "强制重新生成二维码");
"", enterpriseInformation.getEnterpriseNumber(), "app.enterprise", "强制重新生成二维码");
// 2. 查询企业名称
String enterpriseName = "";
EnterpriseInformationVo enterpriseInfo = enterpriseInformationService.queryByEnterpriseNumber(enterpriseNumber);
EnterpriseInformationVo enterpriseInfo = enterpriseInformationService.queryByEnterpriseNumber(enterpriseInformation.getEnterpriseNumber());
if (enterpriseInfo != null) {
enterpriseName = enterpriseInfo.getEnterpriseName();
}

8
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEnterpriseComplaintController.java

@ -76,8 +76,12 @@ public class AppEnterpriseComplaintController extends BaseController {
* @return 分页结果
*/
@ApiResponse(description = "投诉建议-行政和非行政未被投诉列表")
@GetMapping("/listNotComplaint")
public TableDataInfo<AppEnforcementRegistrationVo> listNotComplaint(@ModelAttribute AppEnterpriseComplaintBo bo, PageQuery pageQuery) {
@PostMapping("/listNotComplaint")
public TableDataInfo<AppEnforcementRegistrationVo> listNotComplaint(@ModelAttribute AppEnterpriseComplaintBo bo, @ModelAttribute PageQuery pageQuery) {
// 添加调试日志
//log.info("接收到分页参数: pageNum={}, pageSize={}", pageQuery.getPageNum(), pageQuery.getPageSize());
//log.info("接收到查询条件: {}", bo);
// 校验企业信用代码
TableDataInfo<AppEnforcementRegistrationVo> list = appEnterpriseComplaintService.getAllCheckList(bo, pageQuery);
return list;

27
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enterprise/AppEnterpriseMineController.java

@ -1,15 +1,19 @@
package com.zdxt.enforcementcode.controller.app.enterprise;
import com.zdxt.enforcementcode.service.enterprise.IAppEnterpriseMineService;
import com.zdxt.enforcementcode.domain.bo.UpdatePhoneBo;
import com.zdxt.enforcementcode.domain.vo.EnterpriseUserVo;
import com.zdxt.enforcementcode.domain.vo.enterprise.EnforcementRegistrationDetailVo;
import com.zdxt.enforcementcode.service.IEnterpriseUserService;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.common.core.domain.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -25,23 +29,32 @@ public class AppEnterpriseMineController {
@Autowired
private IAppEnterpriseMineService appEnterpriseMineService;
private IEnterpriseUserService enterpriseUserService;
/**
* 企业端-查询用户信息
*/
@ApiResponse(description = "企业端-查询用户信息")
@GetMapping("/userMine")
public SysUserVo userMine(String userId) {
return appEnterpriseMineService.queryLoginUserId(userId);
public R<EnterpriseUserVo> userMine(Long userId) {
EnterpriseUserVo enterpriseUserVo = enterpriseUserService.queryById(userId);
return R.ok(enterpriseUserVo);
}
/**
* 企业端-修改联系电话
* @param updatePhoneBo 修改手机号码请求对象
* @return
*/
@ApiResponse(description = "企业端-修改用户联系电话")
@PostMapping("/updatePhone")
public int updatePhone(String userId, String phone) {
return appEnterpriseMineService.updateUserPhone(userId, phone);
public R<String> updatePhone(@RequestBody @Validated UpdatePhoneBo updatePhoneBo) {
boolean flag = enterpriseUserService.updatePhoneNumber(updatePhoneBo.getUserId(), updatePhoneBo.getPhoneNumber());
if (flag) {
return R.ok("修改成功");
} else {
return R.fail("修改失败");
}
}
}

37
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/bo/UpdatePhoneBo.java

@ -0,0 +1,37 @@
package com.zdxt.enforcementcode.domain.bo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 企业用户修改手机号码业务对象
*
* @author Lion Li
* @date 2026-05-16
*/
@Data
@Schema(description = "企业用户修改手机号码请求对象")
public class UpdatePhoneBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
@Schema(description = "用户ID")
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 新手机号码
*/
@Schema(description = "新手机号码")
@NotBlank(message = "手机号码不能为空")
private String phoneNumber;
}

12
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EnterpriseUserVo.java

@ -3,6 +3,7 @@ package com.zdxt.enforcementcode.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.zdxt.enforcementcode.domain.EnterpriseUser;
@ -96,6 +97,7 @@ public class EnterpriseUserVo implements Serializable {
/**
* 密码
*/
@JsonIgnore
@ExcelProperty(value = "密码")
private String password;
@ -121,6 +123,7 @@ public class EnterpriseUserVo implements Serializable {
/**
* 盐加密
*/
@JsonIgnore
@ExcelProperty(value = "盐加密")
private String salt;
@ -130,5 +133,14 @@ public class EnterpriseUserVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
/**
* 部门名称
*/
private String deptName;
/**
* 部门名称
*/
private String headUrl;
}

10
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/EnterpriseUserRefMapper.java

@ -3,8 +3,11 @@ package com.zdxt.enforcementcode.mapper;
import com.zdxt.enforcementcode.domain.EnterpriseUserRef;
import com.zdxt.enforcementcode.domain.vo.EnterpriseUserRefVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 企业用户与企业的关联Mapper接口
*
@ -14,4 +17,11 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@Mapper
public interface EnterpriseUserRefMapper extends BaseMapperPlus<EnterpriseUserRef, EnterpriseUserRefVo> {
/**
* 根据用户ID查询企业关联信息
*
* @param userId 用户ID
* @return 企业用户关联信息列表
*/
List<EnterpriseUserRefVo> selectByUserId(@Param("userId") Long userId);
}

2
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/mapper/enterprise/AppEnterpriseComplaintMapper.java

@ -29,7 +29,7 @@ public interface AppEnterpriseComplaintMapper extends BaseMapperPlus<EnterpriseC
@Param("beginTime") Date beginTime,
@Param("endTime") Date endTime,
@Param("deptList") List<String> deptList,
Page<AppEnforcementRegistrationVo> page
@Param("page") Page<AppEnforcementRegistrationVo> page
);
/**

9
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseUserService.java

@ -74,4 +74,13 @@ public interface IEnterpriseUserService {
EnterpriseUserVo queryByUserName(String userName);
EnterpriseUserVo queryByLoginName(String loginName);
/**
* 修改企业用户手机号码
*
* @param userId 用户ID
* @param phoneNumber 新手机号码
* @return 是否修改成功
*/
Boolean updatePhoneNumber(Long userId, String phoneNumber);
}

23
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/IAppEnterpriseMineService.java

@ -1,23 +0,0 @@
package com.zdxt.enforcementcode.service.enterprise;
import org.dromara.system.domain.vo.SysUserVo;
/**
* 企业执法-我的Service接口
*/
public interface IAppEnterpriseMineService {
/**
* 企业端-根据用户ID查询用户信息
*
* @param userId 用户ID
* @return 用户信息
*/
SysUserVo queryLoginUserId(String userId);
/**
* 企业端-修改用户联系电话
*/
int updateUserPhone(String userId, String phone);
}

14
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppEnterpriseComplaintServiceImpl.java

@ -239,7 +239,19 @@ public class AppEnterpriseComplaintServiceImpl implements IAppEnterpriseComplain
page
);
return TableDataInfo.build(list);
// 5. 设置总数
Long total = baseMapper.countAllCheckList(
bo.getEnterpriseNumber(),
bo.getSearchValue(),
checkCategoryCode,
bo.getBeginTime(),
bo.getEndTime(),
deptList
);
page.setRecords(list);
page.setTotal(total);
return TableDataInfo.build(page);
}
/**

40
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppEnterpriseMineServiceImpl.java

@ -1,40 +0,0 @@
package com.zdxt.enforcementcode.service.enterprise.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zdxt.enforcementcode.mapper.enterprise.AppEnterpriseMineMapper;
import com.zdxt.enforcementcode.service.enterprise.IAppEnterpriseMineService;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AppEnterpriseMineServiceImpl implements IAppEnterpriseMineService {
@Autowired
private AppEnterpriseMineMapper appEnterpriseMineMapper;
/**
* 企业端-获取用户信息
* @param userId 用户ID
* @return
*/
@Override
public SysUserVo queryLoginUserId(String userId) {
SysUserVo sysUserVo = appEnterpriseMineMapper.queryLoginUserId(userId);
return sysUserVo;
}
/**
* 企业端-修改用户联系电话
* @param userId
* @param phone
* @return
*/
@Override
public int updateUserPhone(String userId, String phone) {
LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(SysUser::getUserId, Long.parseLong(userId))
.set(SysUser::getPhonenumber, phone);
return appEnterpriseMineMapper.update(null, updateWrapper);
}
}

10
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/enterprise/impl/AppLawEnforcementCaseServiceImpl.java

@ -7,14 +7,17 @@ import com.zdxt.enforcementcode.common.commonenum.LawTypeEnum;
import com.zdxt.enforcementcode.domain.EnforcementRegistration;
import com.zdxt.enforcementcode.domain.ZdxtFile;
import com.zdxt.enforcementcode.domain.bo.enterprise.AppLawEnforcementCaseBo;
import com.zdxt.enforcementcode.domain.vo.EnterpriseInformationVo;
import com.zdxt.enforcementcode.domain.vo.enterprise.AppEnforcementRegistrationVo;
import com.zdxt.enforcementcode.domain.vo.enterprise.AppLawEnforcementCaseVo;
import com.zdxt.enforcementcode.mapper.ZdxtFileMapper;
import com.zdxt.enforcementcode.mapper.enterprise.AppEnforcementRegistrationMapper;
import com.zdxt.enforcementcode.mapper.enterprise.AppLawEnforcementCaseMapper;
import com.zdxt.enforcementcode.service.IEnterpriseInformationService;
import com.zdxt.enforcementcode.service.enterprise.IAppLawEnforcementCaseService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -31,6 +34,10 @@ public class AppLawEnforcementCaseServiceImpl implements IAppLawEnforcementCaseS
@Autowired
private ZdxtFileMapper zdxtFileMapper;
@Autowired
private IEnterpriseInformationService enterpriseInformationService;
/**
* 企业端-查询案件列表
* @param bo
@ -39,6 +46,9 @@ public class AppLawEnforcementCaseServiceImpl implements IAppLawEnforcementCaseS
*/
@Override
public TableDataInfo<AppLawEnforcementCaseVo> selectAppLawEnforcementCaseList(AppLawEnforcementCaseBo bo, PageQuery pageQuery) {
String deptId = LoginHelper.getDeptId();//企业ID
EnterpriseInformationVo enterpriseInformationVo = enterpriseInformationService.queryById(deptId);
bo.setIdNumber(enterpriseInformationVo.getEnterpriseNumber());
Page<AppLawEnforcementCaseVo> page = pageQuery.build();
IPage<AppLawEnforcementCaseVo> result = appLawEnforcementCaseMapper.selectAppLawEnforcementCaseList(bo, page);
return TableDataInfo.build(result);

18
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseEvaluateServiceImpl.java

@ -115,7 +115,7 @@ public class EnterpriseEvaluateServiceImpl implements IEnterpriseEvaluateService
@Override
public Boolean insertByBo(EnterpriseEvaluateBo bo) {
EnterpriseEvaluate add = MapstructUtils.convert(bo, EnterpriseEvaluate.class);
validEntityBeforeSave(add);
validEntityBeforeSave(add, true); // 新增时需要校验重复评价
boolean flag =false;
flag= baseMapper.insert(add) > 0;
@ -140,15 +140,25 @@ public class EnterpriseEvaluateServiceImpl implements IEnterpriseEvaluateService
@Override
public Boolean updateByBo(EnterpriseEvaluateBo bo) {
EnterpriseEvaluate update = MapstructUtils.convert(bo, EnterpriseEvaluate.class);
validEntityBeforeSave(update);
validEntityBeforeSave(update, false); // 更新时不需要校验重复评价
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
* @param entity 待保存的实体
* @param isNew 是否为新增操作
*/
private void validEntityBeforeSave(EnterpriseEvaluate entity){
//TODO 做一些数据校验,如唯一约束
private void validEntityBeforeSave(EnterpriseEvaluate entity, boolean isNew){
// 仅在新增时校验enforcementId是否已存在评价记录,防止重复评价
if (isNew && StringUtils.isNotBlank(entity.getEnforcementId())) {
LambdaQueryWrapper<EnterpriseEvaluate> lqw = Wrappers.lambdaQuery();
lqw.eq(EnterpriseEvaluate::getEnforcementId, entity.getEnforcementId());
long count = baseMapper.selectCount(lqw);
if (count > 0) {
throw new RuntimeException("该执法案件已评价过,不支持二次评价");
}
}
}
/**

55
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseUserServiceImpl.java

@ -1,8 +1,11 @@
package com.zdxt.enforcementcode.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zdxt.enforcementcode.domain.EnterpriseUser;
import com.zdxt.enforcementcode.domain.bo.EnterpriseUserBo;
import com.zdxt.enforcementcode.domain.vo.EnterpriseUserRefVo;
import com.zdxt.enforcementcode.domain.vo.EnterpriseUserVo;
import com.zdxt.enforcementcode.mapper.EnterpriseUserMapper;
import com.zdxt.enforcementcode.mapper.EnterpriseUserRefMapper;
import com.zdxt.enforcementcode.service.IEnterpriseUserService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
@ -32,6 +35,9 @@ public class EnterpriseUserServiceImpl implements IEnterpriseUserService {
private final EnterpriseUserMapper baseMapper;
private final EnterpriseUserRefMapper enterpriseUserRefMapper;
/**
* 查询企业用户信息
*
@ -40,7 +46,15 @@ public class EnterpriseUserServiceImpl implements IEnterpriseUserService {
*/
@Override
public EnterpriseUserVo queryById(Long userId){
return baseMapper.selectVoById(userId);
EnterpriseUserVo enterpriseUserVo = new EnterpriseUserVo();
List<EnterpriseUserRefVo> enterpriseUserRefVo = enterpriseUserRefMapper.selectByUserId(userId);
if(enterpriseUserRefVo.size()>0){
EnterpriseUserRefVo enterpriseUserRefVo1 = enterpriseUserRefVo.get(0);
enterpriseUserVo = baseMapper.selectVoById(userId);
enterpriseUserVo.setDeptName(enterpriseUserRefVo1.getEnterpriseName());
enterpriseUserVo.setDeptId(enterpriseUserRefVo1.getEnterpriseId());
}
return enterpriseUserVo;
}
/**
@ -161,4 +175,43 @@ public class EnterpriseUserServiceImpl implements IEnterpriseUserService {
lqw.eq(EnterpriseUser::getLoginName, loginName);
return baseMapper.selectVoOne(lqw);
}
/**
* 修改企业用户手机号码
*
* @param userId 用户ID
* @param phoneNumber 新手机号码
* @return 是否修改成功
*/
@Override
public Boolean updatePhoneNumber(Long userId, String phoneNumber) {
if (userId == null || StringUtils.isBlank(phoneNumber)) {
log.warn("修改手机号码失败:用户ID或手机号码为空");
return false;
}
// 验证手机号格式
// if (!phoneNumber.matches("^1[3-9]\\d{9}$")) {
// log.warn("修改手机号码失败:手机号格式不正确,phoneNumber={}", phoneNumber);
// return false;
// }
//
try {
LambdaUpdateWrapper<EnterpriseUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EnterpriseUser::getUserId, userId)
.set(EnterpriseUser::getPhonenumber, phoneNumber);
int result = baseMapper.update(null, updateWrapper);
if (result > 0) {
log.info("成功修改用户[{}]的手机号码为[{}]", userId, phoneNumber);
return true;
} else {
log.warn("修改用户[{}]的手机号码失败,用户不存在", userId);
return false;
}
} catch (Exception e) {
log.error("修改用户[{}]的手机号码时发生异常", userId, e);
return false;
}
}
}

19
zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EnterpriseUserRefMapper.xml

@ -3,4 +3,23 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zdxt.enforcementcode.mapper.EnterpriseUserRefMapper">
<!-- 根据用户ID查询企业关联信息 -->
<select id="selectByUserId" resultType="com.zdxt.enforcementcode.domain.vo.EnterpriseUserRefVo">
SELECT
ref_id AS refId,
user_id AS userId,
user_name AS userName,
enterprise_id AS enterpriseId,
enterprise_name AS enterpriseName,
enterprise_number AS enterpriseNumber,
create_dept AS createDept,
create_by AS createBy,
create_time AS createTime,
update_by AS updateBy,
update_time AS updateTime,
remark AS remark
FROM enterprise_user_ref
WHERE user_id = #{userId}
</select>
</mapper>

14
zdxt-web-client/zdxt-efcode-enterprise-app/src/api/enterprise/index.js

@ -16,7 +16,7 @@ export const getUserRefEnterpriseInfo = (params, success, error) => _get(enterpr
export const getEnterpriseMerchantAuthorization = (params, success, error) => _get(enterpriseAppBaseUrl + "/authorization/queryList",params,success,error);
//查询企业二维码
export const queryEnterpriseInformationQrCode = (enterpriseNumber, success, error) => _get(enterpriseAppBaseUrl+"/enterpriseInfo/getQrCode/"+enterpriseNumber,null,success,error)
export const queryEnterpriseInformationQrCode = (params, success, error) => _get(enterpriseAppBaseUrl+"/enterpriseInfo/getQrCode",params,success,error)
//查询企业执法登记列表-企业端(含投诉标记、字典翻译、超时计算等)
export const getEnterpriseEnforcementRegistrationList = (params, success, error) => _get(enterpriseAppBaseUrl+"/lawEnforcementCase/list",params,success,error)
@ -73,13 +73,13 @@ export const getComplaintDisposalProgress = (params, success, error) => _get(ent
export const addComplaint = (params, success, error) => _post(enterpriseAppBaseUrl+"/complaint/add",params,success,error)
//查询字典数据(公共)
export const queryDict = (params, success, error) => _get(enterpriseAppBaseUrl +"/common/dict/queryDict",params,success,error)
export const queryDict = (params, success, error) => _get("/common/dict/queryDict",params,success,error)
//执法单位(部门)列表
export const getDeptList = (params, success, error) => _get(enterpriseAppBaseUrl +"/enforcementcode/virtualUnit/list",params,success,error)
export const getDeptList = (params, success, error) => _get("/enforcementcode/virtualUnit/list",params,success,error)
//投诉事项列表
export const getComplaintItemList = (params, success, error) => _get(enterpriseAppBaseUrl +"/complaint/listNotComplaint",params,success,error)
export const getComplaintItemList = (params, success, error) => _post(enterpriseAppBaseUrl +"/complaint/listNotComplaint",params,success,error)
//深i企登录-暂时没有环境调通
export const getSiqLoginAuth = (params, success, error) => _post(enterpriseAppBaseUrl +"/thirdLogin/siqLogin",params,success,error);
@ -87,4 +87,10 @@ export const getSiqLoginAuth = (params, success, error) => _post(enterpriseAppBa
//深i企模拟登录(通过userId模拟)
export const getSiqLoginAuthMock = (params, success, error) => _post(enterpriseAppBaseUrl +"/thirdLogin/siqLoginMock",params,success,error);
//强制生成二维码
export const forceGenerateQrCode = (params, success, error) => _get(enterpriseAppBaseUrl+"/enterpriseInfo/forceGenerateQrCode",params,success,error)
//消息数据统计接口(未读数量)
export const getMessageUnreadCount = (params, success, error) => _get(enterpriseAppBaseUrl +"/enterprise/todoitem/statisticsUnReadCount",params,success,error);
// endregion

70
zdxt-web-client/zdxt-efcode-enterprise-app/src/components/complaint/ComplaintItemPicker.vue

@ -30,29 +30,37 @@
</div>
<!-- 列表 -->
<div class="complaint-item-list">
<div class="complaint-item-list" ref="listRef" @scroll="onScroll">
<div v-for="item in filteredList" :key="item.id" class="complaint-item-card" @click="onSelect(item)">
<div v-if="item.time" class="item-time">执法时间:{{ item.time }}</div>
<div v-if="item.enforcementTime" class="item-time">执法时间:{{ item.enforcementTime }}</div>
<div class="item-title">{{ item.title }}</div>
<div v-if="item.subName && item.subName !== item.title" class="item-info">{{ item.subName }}</div>
<div v-if="item.unit" class="item-info">执法单位:{{ item.unit }}</div>
<div v-if="item.personnel && item.personnel.length" class="item-info">执法人员:{{ item.personnel.join('、') }}</div>
<div v-if="item.category" class="item-info">执法类别:{{ item.category }}</div>
<div v-if="item.bureauDeptName" class="item-info">执法单位:{{ item.bureauDeptName }}</div>
<div v-if="item.lawEnforcer" class="item-info items-center">
<div>执法人员:</div>
<div>
<div>{{ item.lawEnforcer }}{{ item.lawEnforcerId }}</div>
<div>{{ item.lawEnforcerOther }}{{ item.lawEnforcerOtherId }}</div>
</div>
</div>
<!-- <div v-if="item.lawEnforcementType" class="item-info">执法类别:{{ item.lawEnforcementType }}</div> -->
<div v-if="item.lawEnforcementType" class="item-info">执法类别:{{ getDictText('check_category',item.lawEnforcementType)}}</div>
</div>
<div class="no-more">没有更多了</div>
<div v-if="loading" class="loading-more">加载中...</div>
<div v-if="finished && filteredList.length > 0" class="no-more">没有更多了</div>
</div>
</div>
</van-popup>
<!-- 开始日期选择弹窗 -->
<van-popup v-model:show="showStartPicker" position="bottom">
<van-date-picker v-model="currentStartDate" title="选择开始日期" @confirm="onStartConfirm"
<van-date-picker v-model="currentStartDate" title="选择开始日期" :min-date="minDate" @confirm="onStartConfirm"
@cancel="showStartPicker = false" />
</van-popup>
<!-- 结束日期选择弹窗 -->
<van-popup v-model:show="showEndPicker" position="bottom">
<van-date-picker v-model="currentEndDate" title="选择结束日期" @confirm="onEndConfirm"
<van-date-picker v-model="currentEndDate" title="选择结束日期" :min-date="minDate" @confirm="onEndConfirm"
@cancel="showEndPicker = false" />
</van-popup>
</template>
@ -60,13 +68,15 @@
<script setup name="ComplaintItemPicker">
import { showToast } from 'vant';
import 'vant/es/toast/style';
import { loadDict, getDictText } from '@/util/dictUtil';
const props = defineProps({
show: { type: Boolean, default: false },
list: { type: Array, default: () => [] }
list: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
finished: { type: Boolean, default: false }
});
const emit = defineEmits(['update:show', 'select']);
const emit = defineEmits(['update:show', 'select', 'loadMore', 'search']);
const startDate = ref('');
const endDate = ref('');
@ -76,7 +86,11 @@ const showEndPicker = ref(false);
const currentStartDate = ref([]);
const currentEndDate = ref([]);
const filteredList = ref([...props.list]);
const listRef = ref(null);
const minDate = new Date(2025, 0, 1); // 最小可选日期:2025年1月1日
// 执法类别字典(用于翻译 item.lawEnforcementType)
const checkCategoryLoaded = ref(false);
loadDict('check_category', () => { checkCategoryLoaded.value = true; });
const formatDate = (dateArr) => {
const [year, month, day] = dateArr;
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
@ -123,7 +137,12 @@ watch(searchKey, () => {
const onSearch = () => {
clearTimeout(searchTimer);
doFilter();
// 触发搜索事件,传递搜索参数
emit('search', {
beginTime: startDate.value,
endTime: endDate.value,
searchValue: searchKey.value
});
};
const onStartConfirm = ({ selectedValues }) => {
@ -135,7 +154,6 @@ const onStartConfirm = ({ selectedValues }) => {
}
startDate.value = date;
showStartPicker.value = false;
doFilter();
};
const onEndConfirm = ({ selectedValues }) => {
@ -147,7 +165,6 @@ const onEndConfirm = ({ selectedValues }) => {
}
endDate.value = date;
showEndPicker.value = false;
doFilter();
};
const onSelect = (item) => {
@ -155,6 +172,16 @@ const onSelect = (item) => {
emit('update:show', false);
};
const onScroll = () => {
if (props.loading || props.finished) return;
const listEl = listRef.value;
if (!listEl) return;
const { scrollTop, scrollHeight, clientHeight } = listEl;
if (scrollTop + clientHeight >= scrollHeight - 50) {
emit('loadMore');
}
};
const onUpdateShow = (val) => {
emit('update:show', val);
};
@ -169,6 +196,7 @@ watch(() => props.show, (val) => {
startDate.value = '';
endDate.value = '';
filteredList.value = [...props.list];
console.log('filteredList', filteredList.value);
}
});
@ -293,6 +321,11 @@ watch(() => props.list, () => {
color: #666;
line-height: 1.6;
}
.items-center {
display: flex;
align-items: center;
}
}
.no-more {
@ -301,5 +334,12 @@ watch(() => props.list, () => {
color: #999;
padding: 0.3rem 0;
}
.loading-more {
text-align: center;
font-size: 0.28rem;
color: #999;
padding: 0.3rem 0;
}
}
</style>

22
zdxt-web-client/zdxt-efcode-enterprise-app/src/components/enterprise/footerNav.vue

@ -1,10 +1,10 @@
<template>
<div class="footer_nav">
<van-tabbar class="footer-bar" v-model="data.footerActive" :route="true" safe-area-inset-bottom>
<van-tabbar class="footer-bar" v-model="data.footerActive" :route="true" safe-area-inset-bottom @change="onTabChange">
<van-tabbar-item name="Home" replace icon="wap-home" to="/enterprise/enterpriseHome">{{
$t("common.lang_home")
}}</van-tabbar-item>
<van-tabbar-item name="Classify" replace icon="bell" to="/enterprise/lawServiceList">
<van-tabbar-item name="Classify" replace icon="bell" to="/enterprise/lawQuery">
法律查询
</van-tabbar-item>
<van-tabbar-item name="Message" replace icon="todo-list" to="/enterprise/messageCenter" :badge="useCommon.unreadMessageCount > 0 ? useCommon.unreadMessageCount : undefined">
@ -21,6 +21,7 @@
</template>
<script setup name="footerNav">
import { getMessageUnreadCount } from '@/api/enterprise';
const { useCommon } = $globalStore
@ -29,6 +30,23 @@ let data = reactive({
dot: false,
});
// ========== tabbar切换时调用消息数量接口 ==========
const onTabChange = (name) => {
fetchMessageUnreadCount();
};
// ========== 获取消息未读数量 ==========
const fetchMessageUnreadCount = () => {
getMessageUnreadCount({}, (res) => {
if (res && res.code === 200 && res.data) {
const totalCount = Number(res.data.totalCount) || 0;
useCommon.SET_UNREAD_MESSAGE_COUNT(totalCount);
}
}, () => {
// 接口调用失败不处理
});
};
</script>
<style lang="less" scoped>
.footer_body{

7
zdxt-web-client/zdxt-efcode-enterprise-app/src/router/enterprise-app/ent-main-router.js

@ -55,6 +55,13 @@ const routes = [
meta: { title: "消息中心" },
component: () => import("@/views/enterprise/message/messageCenter.vue"),
},
// 法律查询
{
path: "/enterprise/lawQuery",
name: "lawQuery",
meta: { title: "法律查询" },
component: () => import("@/views/enterprise/law/lawQuery.vue"),
},
// 普法服务列表
{
path: "/enterprise/lawServiceList",

35
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/auth/login.vue

@ -79,23 +79,24 @@
useCommon.SET_TOKEN(response.data.token);
//debugger;
console.log("message",useCommon.userId);
// 分离调用:获取关联的企业信息
getUserRefEnterpriseInfo({userId: response.data.userId}, res => {
console.log("getUserRefEnterpriseInfo", res);
if (res.code === 200 && res.data && Array.isArray(res.data) && res.data.length > 0) {
const firstEnterprise = res.data[0];
useCommon.SET_USER_ENTERPRISE_NUMBER(firstEnterprise.enterpriseNumber || "未找到企业信用代码");
useCommon.SET_USER_ENTERPRISE_NAME(firstEnterprise.enterpriseName || "未找到企业名称");
useCommon.SET_USER_ENTERPRISE_ID(firstEnterprise.enterpriseId || "未找到企业ID");
if (res.data.length > 1) {
showToast('您关联了多个企业,已默认选择企业:' + (firstEnterprise.enterpriseName || ''));
}
}
router.push({name: "enterpriseHome"});
}, () => {
// 获取企业信息失败也照常跳转
showFailToast("获取企业信息失败!");
});
// 暂时不调用获取关联企业信息接口
// getUserRefEnterpriseInfo({userId: response.data.userId}, res => {
// console.log("getUserRefEnterpriseInfo", res);
// if (res.code === 200 && res.data && Array.isArray(res.data) && res.data.length > 0) {
// const firstEnterprise = res.data[0];
// useCommon.SET_USER_ENTERPRISE_NUMBER(firstEnterprise.enterpriseNumber || "未找到企业信用代码");
// useCommon.SET_USER_ENTERPRISE_NAME(firstEnterprise.enterpriseName || "未找到企业名称");
// useCommon.SET_USER_ENTERPRISE_ID(firstEnterprise.enterpriseId || "未找到企业ID");
// if (res.data.length > 1) {
// showToast('您关联了多个企业,已默认选择企业:' + (firstEnterprise.enterpriseName || ''));
// }
// }
// router.push({name: "enterpriseHome"});
// }, () => {
// // 获取企业信息失败也照常跳转
// showFailToast("获取企业信息失败!");
// });
router.push({name: "enterpriseHome"});
} else {
showFailToast(response.msg || "登录失败");
}

19
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementEvaluate.vue

@ -15,7 +15,7 @@
<van-tab title="待评价">
<template #title>
<span>待评价</span>
<span class="tab-badge">{{ pendingCount }}</span>
<span class="tab-badge" v-if="pendingCount > 0">{{ pendingCount }}</span>
</template>
<!-- 待评价列表 -->
<van-pull-refresh v-model="pendingRefreshing" @refresh="onPendingRefresh">
@ -100,6 +100,14 @@ const router = useRouter();
// ========== Tab 状态 ==========
const activeTab = ref(0);
// 返回时保持tab状态的key
const TAB_KEY = 'EVALUATE_TAB_INDEX';
// 监听tab切换,保存到sessionStorage
watch(activeTab, (val) => {
sessionStorage.setItem(TAB_KEY, String(val));
});
// ========== 分页配置 ==========
const PAGE_SIZE = 10;
@ -279,6 +287,15 @@ const toEvaluateDetail = (item, hasEvaluate) => {
query: { id: item.id, hasEvaluate },
});
};
// ========== 页面初始化 ==========
onMounted(() => {
// 从sessionStorage恢复tab状态
const savedTab = sessionStorage.getItem(TAB_KEY);
if (savedTab !== null) {
activeTab.value = parseInt(savedTab, 10);
}
});
</script>
<style lang="less" scoped>

43
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementEvaluateDetail.vue

@ -92,21 +92,21 @@
<!-- 表情选择 -->
<div class="emoji-section">
<div class="emoji-item" :class="{ active: evaluateForm.satisfaction === '满意', disabled: readonly }"
@click="!readonly && (evaluateForm.satisfaction = '满意')">
<img class="emoji-img" :src="evaluateForm.satisfaction === '满意' ? veryGoodImg : veryGoodDisImg"
<div class="emoji-item" :class="{ active: evaluateForm.satisfactionLevel === 3, disabled: readonly }"
@click="!readonly && (evaluateForm.satisfactionLevel = 3)">
<img class="emoji-img" :src="evaluateForm.satisfactionLevel === 3 ? veryGoodImg : veryGoodDisImg"
alt="满意" />
<span class="emoji-label">满意</span>
</div>
<div class="emoji-item" :class="{ active: evaluateForm.satisfaction === '较满意', disabled: readonly }"
@click="!readonly && (evaluateForm.satisfaction = '较满意')">
<img class="emoji-img" :src="evaluateForm.satisfaction === '较满意' ? goodImg : goodDisImg"
<div class="emoji-item" :class="{ active: evaluateForm.satisfactionLevel === 2, disabled: readonly }"
@click="!readonly && (evaluateForm.satisfactionLevel = 2)">
<img class="emoji-img" :src="evaluateForm.satisfactionLevel === 2 ? goodImg : goodDisImg"
alt="较满意" />
<span class="emoji-label">较满意</span>
</div>
<div class="emoji-item" :class="{ active: evaluateForm.satisfaction === '不满意', disabled: readonly }"
@click="!readonly && (evaluateForm.satisfaction = '不满意')">
<img class="emoji-img" :src="evaluateForm.satisfaction === '不满意' ? badImg : badDisImg"
<div class="emoji-item" :class="{ active: evaluateForm.satisfactionLevel === 1, disabled: readonly }"
@click="!readonly && (evaluateForm.satisfactionLevel = 1)">
<img class="emoji-img" :src="evaluateForm.satisfactionLevel === 1 ? badImg : badDisImg"
alt="不满意" />
<span class="emoji-label">不满意</span>
</div>
@ -236,9 +236,10 @@ const detail = ref({
attachments: [],
});
// ========== 评价表单(默认值:满意 / 5 星 / 其他问题打开)==========
// ========== 评价表单(默认值:满意=3 / 5 星 / 其他问题打开)==========
// 满意度数值:1=不满意,2=较满意,3=满意
const evaluateForm = ref({
satisfaction: '满意',
satisfactionLevel: 3,
civility: 5,
efficiency: 5,
attitude: 5,
@ -299,26 +300,10 @@ const fetchRegistrationDetail = () => {
});
};
// satisfaction 文字 <-> 数字 映射:不满意=1、较满意=2、非常满意(满意)=3
const SATISFACTION_LIST = [
{ num: 1, text: '不满意' },
{ num: 2, text: '较满意' },
{ num: 3, text: '满意', alias: ['非常满意'] },
];
const SATISFACTION_TO_NUM = SATISFACTION_LIST.reduce((map, it) => {
map[it.text] = it.num;
(it.alias || []).forEach(a => { map[a] = it.num; });
return map;
}, {});
const SATISFACTION_TO_TEXT = SATISFACTION_LIST.reduce((map, it) => {
map[it.num] = it.text;
return map;
}, {});
// 将后端 enterpriseEvaluateInfoVo 回填到表单/问题列表
const fillEvaluateFormFromInfo = (info) => {
evaluateForm.value = {
satisfaction: SATISFACTION_TO_TEXT[Number(info.satisfaction)] || evaluateForm.value.satisfaction,
satisfactionLevel: Number(info.satisfactionLevel) || evaluateForm.value.satisfactionLevel,
civility: Number(info.serviceExperience) || 0,
efficiency: Number(info.checkQuality) || 0,
attitude: Number(info.checkAttitude) || 0,
@ -360,7 +345,7 @@ const onSubmit = () => {
}).then(() => {
const params = {
enforcementId: id,
satisfaction: SATISFACTION_TO_NUM[evaluateForm.value.satisfaction] || 3,
satisfactionLevel: evaluateForm.value.satisfactionLevel,
serviceExperience: evaluateForm.value.civility,
checkAttitude: evaluateForm.value.attitude,
checkQuality: evaluateForm.value.efficiency,

10
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/home/enterpriseHomeV2.vue

@ -94,9 +94,9 @@ const fetchBannerList = () => {
const rows = res?.rows || res?.data?.rows || res?.data || [];
if (!Array.isArray(rows)) return;
bannerList.value = rows.map(item => ({
title: item.title || item.name || '',
image: item.image || item.imageUrl || item.picUrl || item.url || item.fileUrl || '',
link: item.link || item.url || item.jumpUrl || '',
title: item.title || '',
image: (import.meta.env.VITE_FILE_URL || '') + (item.imageUrl || ''),
link: item.linkUrl || '',
raw: item,
}));
}, () => { });
@ -119,7 +119,7 @@ const fetchNoticeList = () => {
if (!Array.isArray(rows)) return;
noticeList.value = rows.map(item => ({
id: item.noticeId || item.id || '',
title: item.noticeTitle || item.title || item.content || '',
title: item.noticeTitle || item.title || item.noticeContent || '',
type: item.noticeType || item.type || '',
createTime: item.createTime || item.publishTime || '',
raw: item,
@ -432,7 +432,7 @@ onMounted(() => {
/* 通知滚动 */
.notice-scroll {
flex: 1;
height: auto !important;
height: 20px !important;
line-height: 1.4 !important;
padding: 0 !important;
font-size: 14px;

312
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawQuery.vue

@ -0,0 +1,312 @@
<template>
<div class="law-query-page">
<!-- 顶部导航栏 -->
<van-nav-bar title="法律查询" left-text="关闭" left-arrow @click-left="onClickLeft">
</van-nav-bar>
<!-- 内容区域 -->
<div class="content-area">
<!-- 搜索框 -->
<div class="search-section">
<van-search
v-model="searchKeyword"
placeholder="请输入关键词搜索"
show-action
@search="onSearch"
>
<template #action>
<van-button size="small" type="primary" @click="onSearch">搜索</van-button>
</template>
</van-search>
</div>
<!-- 法律分类 -->
<div class="category-section">
<div class="section-title">法律分类</div>
<div class="category-grid">
<div
class="category-item"
v-for="(item, index) in categoryList"
:key="index"
@click="onCategoryClick(item)"
>
<div class="category-icon" :class="item.iconBg">
<img :src="item.icon" alt="" />
</div>
<div class="category-name">{{ item.name }}</div>
</div>
</div>
</div>
<!-- 常用法律 -->
<div class="law-section">
<div class="section-title">常用法律</div>
<van-cell-group>
<van-cell
v-for="(law, index) in lawList"
:key="index"
:title="law.title"
:label="law.desc"
is-link
@click="onLawClick(law)"
/>
</van-cell-group>
</div>
<!-- 法律知识问答 -->
<div class="qa-section">
<div class="section-title">法律知识问答</div>
<div class="qa-list">
<div
class="qa-item"
v-for="(qa, index) in qaList"
:key="index"
@click="onQaClick(qa)"
>
<div class="qa-question">{{ qa.question }}</div>
<div class="qa-answer">{{ qa.answer }}</div>
</div>
</div>
</div>
</div>
<!-- 底部导航栏 -->
<div class="footer_body">
<footer-nav></footer-nav>
</div>
</div>
</template>
<script setup name="lawQuery">
import { ref } from 'vue';
import { showToast } from 'vant';
import 'vant/es/toast/style';
const router = useRouter();
// 搜索关键词
const searchKeyword = ref('');
// 法律分类列表
const categoryList = ref([
{ name: '宪法', icon: '', iconBg: 'icon-red' },
{ name: '民法', icon: '', iconBg: 'icon-blue' },
{ name: '刑法', icon: '', iconBg: 'icon-green' },
{ name: '行政法', icon: '', iconBg: 'icon-orange' },
{ name: '经济法', icon: '', iconBg: 'icon-purple' },
{ name: '劳动法', icon: '', iconBg: 'icon-yellow' },
{ name: '商法', icon: '', iconBg: 'icon-pink' },
{ name: '诉讼法', icon: '', iconBg: 'icon-cyan' },
]);
// 常用法律列表
const lawList = ref([
{ title: '中华人民共和国宪法', desc: '国家根本大法' },
{ title: '中华人民共和国民法典', desc: '社会生活的百科全书' },
{ title: '中华人民共和国刑法', desc: '规定犯罪与刑罚' },
{ title: '中华人民共和国行政法', desc: '规范行政行为' },
{ title: '中华人民共和国劳动法', desc: '保护劳动者权益' },
]);
// 法律知识问答列表
const qaList = ref([
{
question: '什么是行政处罚?',
answer: '行政处罚是指行政机关依法对违反行政管理秩序的公民、法人或者其他组织,以减损权益或者增加义务的方式予以惩戒的行为。'
},
{
question: '企业需要遵守哪些法律法规?',
answer: '企业需要遵守公司法、劳动法、税法、环境保护法、安全生产法等相关法律法规。'
},
{
question: '什么是行政复议?',
answer: '行政复议是指公民、法人或者其他组织认为具体行政行为侵犯其合法权益,向行政机关提出行政复议申请,行政机关受理并作出决定的活动。'
},
]);
// 返回上一页
const onClickLeft = () => {
router.back();
};
// 搜索
const onSearch = () => {
if (!searchKeyword.value.trim()) {
showToast('请输入搜索关键词');
return;
}
showToast(`搜索:${searchKeyword.value}`);
};
// 点击分类
const onCategoryClick = (item) => {
showToast(`选择分类:${item.name}`);
};
// 点击法律
const onLawClick = (law) => {
showToast(`查看:${law.title}`);
};
// 点击问答
const onQaClick = (qa) => {
showToast('查看详情');
};
</script>
<style lang="less" scoped>
.law-query-page {
display: flex;
flex-direction: column;
height: 100%;
background: #f5f7fa;
}
.content-area {
flex: 1;
overflow-y: auto;
padding: 0.27rem;
padding-bottom: 1.5rem;
}
/* ===== 搜索区域 ===== */
.search-section {
background: #fff;
border-radius: 0.2rem;
padding: 0.2rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
/* ===== 分类区域 ===== */
.category-section {
background: #fff;
border-radius: 0.2rem;
padding: 0.3rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.section-title {
font-size: 0.37rem;
font-weight: 600;
color: #333;
margin-bottom: 0.25rem;
padding-left: 0.1rem;
}
.category-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.2rem;
}
.category-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.25rem 0;
}
.category-icon {
width: 1.2rem;
height: 1.2rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.15rem;
background: #f0f0f0;
}
.category-icon img {
width: 0.6rem;
height: 0.6rem;
}
.icon-red { background: #ffebee; }
.icon-blue { background: #e3f2fd; }
.icon-green { background: #e8f5e9; }
.icon-orange { background: #fff3e0; }
.icon-purple { background: #f3e5f5; }
.icon-yellow { background: #fffde7; }
.icon-pink { background: #fce4ec; }
.icon-cyan { background: #e0f7fa; }
.category-name {
font-size: 0.28rem;
color: #666;
text-align: center;
}
/* ===== 法律列表 ===== */
.law-section {
background: #fff;
border-radius: 0.2rem;
padding: 0.3rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
:deep(.van-cell) {
font-size: 0.32rem;
padding: 0.25rem 0;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
}
:deep(.van-cell__title) {
font-size: 0.34rem;
color: #333;
}
:deep(.van-cell__label) {
font-size: 0.28rem;
color: #999;
}
/* ===== 问答区域 ===== */
.qa-section {
background: #fff;
border-radius: 0.2rem;
padding: 0.3rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.qa-list {
.qa-item {
padding: 0.25rem 0;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
}
}
.qa-question {
font-size: 0.34rem;
color: #333;
font-weight: 500;
margin-bottom: 0.1rem;
}
.qa-answer {
font-size: 0.3rem;
color: #999;
line-height: 1.6;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* ===== 底部导航 ===== */
.footer_body {
flex-shrink: 0;
}
</style>

110
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawServiceDetail.vue

@ -24,23 +24,34 @@
<span class="detail-time">{{ detail.time }}</span>
</div>
<!-- 正文 -->
<div class="detail-body">
<p v-for="(paragraph, index) in detail.content" :key="index">
{{ paragraph }}
</p>
</div>
<!-- 文本内容 (contentType == 1) -->
<template v-if="detail.contentType !== 2">
<!-- 正文 -->
<div class="detail-body" v-html="detail.content"></div>
<!-- 图片 -->
<div class="detail-images" v-if="detail.images && detail.images.length">
<img
v-for="(img, index) in detail.images"
:key="index"
:src="img"
alt=""
@click="previewImage(index)"
/>
</div>
<!-- 图片 -->
<div class="detail-images" v-if="detail.images && detail.images.length">
<img
v-for="(img, index) in detail.images"
:key="index"
:src="img"
alt=""
@click="previewImage(index)"
/>
</div>
</template>
<!-- 链接内容 (contentType == 2) -->
<template v-else>
<div class="detail-iframe-wrap">
<iframe
:src="detail.content"
class="detail-iframe"
frameborder="0"
sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>
</div>
</template>
</div>
</div>
</template>
@ -60,6 +71,7 @@ const detail = ref({
title: '',
source: '',
time: '',
contentType: 1, // 1: 文本详情, 2: 超链接
content: [],
images: [],
});
@ -86,7 +98,8 @@ const fetchDetail = () => {
title: res.data.title || '',
source: res.data.source || '',
time: res.data.time || '',
content: res.data.content ? (Array.isArray(res.data.content) ? res.data.content : [res.data.content]) : [],
contentType: res.data.contentType || 1, // 1: 文本详情, 2: 超链接
content: res.data.content || '',
images: res.data.images || [],
};
} else {
@ -190,13 +203,55 @@ const previewImage = (index) => {
}
.detail-body {
font-size: 0.37rem;
color: #333;
line-height: 1.8;
p {
font-size: 0.37rem;
color: #333;
line-height: 1.8;
text-indent: 2em;
margin-bottom: 0.3rem;
}
h1, h2, h3, h4, h5, h6 {
font-weight: bold;
margin-top: 0.4rem;
margin-bottom: 0.2rem;
color: #1a1a1a;
}
h1 { font-size: 0.5rem; }
h2 { font-size: 0.45rem; }
h3 { font-size: 0.4rem; }
h4, h5, h6 { font-size: 0.37rem; }
ul, ol {
padding-left: 0.5rem;
margin-bottom: 0.3rem;
}
li {
margin-bottom: 0.15rem;
}
img {
max-width: 100%;
height: auto;
border-radius: 0.15rem;
margin: 0.2rem 0;
}
a {
color: #2d94fa;
text-decoration: underline;
}
blockquote {
border-left: 4px solid #2d94fa;
padding-left: 0.3rem;
margin: 0.3rem 0;
color: #666;
font-style: italic;
}
}
.detail-images {
@ -209,4 +264,19 @@ const previewImage = (index) => {
display: block;
}
}
/* ===== iframe 样式 ===== */
.detail-iframe-wrap {
width: 100%;
margin-top: 0.2rem;
border-radius: 0.15rem;
overflow: hidden;
background: #f5f5f5;
}
.detail-iframe {
width: 100%;
height: 500px;
background: #fff;
}
</style>

28
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/law/lawServiceList.vue

@ -37,18 +37,19 @@
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z"/>
</svg>
<span v-if="item.isRead === 0" class="unread-dot"></span>
</div>
<div class="item-title">{{ item.title || '-' }}</div>
</div>
<!-- 摘要 -->
<div class="item-summary">{{ item.summary || item.content || '' }}</div>
<div class="item-summary">{{ stripHtml(item.summary || item.content || '') }}</div>
<!-- 底部信息 -->
<div class="item-footer">
<span class="item-time">{{ formatTime(item.createTime || item.time) }}</span>
<span class="item-action">
查看
{{ item.contentType === 2 ? '查看' : '查看' }}
<van-icon name="arrow" />
</span>
</div>
@ -88,6 +89,15 @@ const formatTime = (val) => {
return `${y}-${m}-${day} ${h}:${mi}:${s}`;
};
// ========== 移除HTML标签 ==========
const stripHtml = (html) => {
if (!html) return '';
// 移除HTML标签
const text = html.replace(/<[^>]*>/g, '');
// 移除多余的空白字符
return text.replace(/\s+/g, ' ').trim();
};
// ========== 加载数据 ==========
const fetchList = () => {
const params = {
@ -157,6 +167,8 @@ const onSearchClick = () => {
// ========== 跳转详情 ==========
const toDetail = (item) => {
// 无论 contentType 是多少,都跳转到详情页
// 详情页会根据 contentType 决定是显示文本还是 iframe
router.push({
path: '/enterprise/lawServiceDetail',
query: { id: item.id },
@ -222,11 +234,23 @@ const toDetail = (item) => {
display: flex;
align-items: center;
justify-content: center;
position: relative;
svg {
width: 100%;
height: 100%;
}
.unread-dot {
position: absolute;
top: -0.05rem;
right: -0.05rem;
width: 0.12rem;
height: 0.12rem;
min-width: 0.12rem;
background-color: #ee0a24;
border-radius: 50%;
}
}
.item-title {

85
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/message/messageCenter.vue

@ -82,17 +82,19 @@
import { showToast } from 'vant';
import 'vant/es/toast/style';
import * as w6s from 'szient-js-sdk';
import { getMessageUnreadCount } from '@/api/enterprise';
const { useCommon } = $globalStore;
const router = useRouter();
// ========== Tab 状态 ==========
const activeTab = ref(0);
const route = useRoute();
// ========== 消息列表状态 ==========
const messageList = ref([]);
const messageLoading = ref(false);
const messageFinished = ref(false);
const messageFinished = ref(true); // 默认已完成,不需要加载更多
const messageRefreshing = ref(false);
const messagePageNum = ref(1);
const messagePageSize = ref(10);
@ -100,14 +102,42 @@ const messagePageSize = ref(10);
// ========== 待办列表状态 ==========
const todoList = ref([]);
const todoLoading = ref(false);
const todoFinished = ref(false);
const todoFinished = ref(true); // 默认已完成,不需要加载更多
const todoRefreshing = ref(false);
const todoPageNum = ref(1);
const todoPageSize = ref(10);
// ========== 生成消息假数据 ==========
const generateMessageMockData = () => {
return [
// ========== 消息统计数据 ==========
const messageStats = ref({
pffwCount: 0, // 普法服务未读数量
zfpjcount: 0, // 执法评价未读数量
zfygCount: 0, // 执法预告未读数量
totalCount: 0, // 未读总数
});
// ========== 获取消息未读数量 ==========
const fetchMessageStats = () => {
getMessageUnreadCount({}, (res) => {
if (res && res.code === 200 && res.data) {
messageStats.value = {
pffwCount: Number(res.data.pffwCount) || 0,
zfpjcount: Number(res.data.zfpjcount) || 0,
zfygCount: Number(res.data.zfygCount) || 0,
totalCount: Number(res.data.totalCount) || 0,
};
// 更新消息列表和待办列表的未读数量
initMessageList();
initTodoList();
updateUnreadCount();
}
}, () => {
// 如果接口调用失败,保持默认数据
});
};
// ========== 初始化默认消息列表 ==========
const initMessageList = () => {
messageList.value = [
{
id: 1,
title: '普法服务',
@ -115,31 +145,31 @@ const generateMessageMockData = () => {
time: '2026-04-15 10:07',
icon: 'law',
iconBg: 'icon-blue',
unreadCount: 1,
unreadCount: messageStats.value.pffwCount,
},
];
};
// ========== 生成待办假数据 ==========
const generateTodoMockData = () => {
return [
// ========== 初始化默认待办列表 ==========
const initTodoList = () => {
todoList.value = [
{
id: 101,
title: '执法预告',
desc: '您有一条执法预告,请及时查看',
desc: messageStats.value.zfygCount > 0 ? `您有${messageStats.value.zfygCount}条执法预告,请及时查看` : '暂无执法预告',
time: '2026-04-15 09:30',
icon: 'check',
iconBg: 'icon-red',
unreadCount: 3,
unreadCount: messageStats.value.zfygCount,
},
{
id: 102,
title: '待评价执法',
desc: '您有2条执法记录待评价',
desc: messageStats.value.zfpjcount > 0 ? `您有${messageStats.value.zfpjcount}条执法记录待评价` : '暂无待评价执法',
time: '2026-04-14 15:00',
icon: 'check',
iconBg: 'icon-orange',
unreadCount: 2,
unreadCount: messageStats.value.zfpjcount,
},
];
};
@ -221,6 +251,8 @@ const onTodoRefresh = () => {
// ========== 消息点击 ==========
const onMessageClick = (item) => {
if (item.title === '普法服务') {
// 点击普法服务,返回时显示消息tab页(0)
sessionStorage.setItem('messageReturnTab', '0');
router.push({
path: '/enterprise/lawServiceList',
});
@ -232,10 +264,14 @@ const onMessageClick = (item) => {
// ========== 待办点击 ==========
const onTodoClick = (item) => {
if (item.title === '执法预告') {
// 点击执法预告,返回时显示待办tab页(1)
sessionStorage.setItem('messageReturnTab', '1');
router.push({
path: '/enterprise/enforcementNoticeList',
});
} else if (item.title === '待评价执法') {
// 点击待评价执法,返回时显示待办tab页(1)
sessionStorage.setItem('messageReturnTab', '1');
router.push({
path: '/enterprise/enforcementEvaluate',
});
@ -254,6 +290,29 @@ onMounted(() => {
w6s.ready(() => {
w6s.header.setTitle('消息中心');
});
// 优先从sessionStorage获取返回时要显示的tab页(用于页面返回时定位)
const returnTab = sessionStorage.getItem('messageReturnTab');
if (returnTab === '1') {
activeTab.value = 1;
sessionStorage.removeItem('messageReturnTab');
} else if (returnTab === '0') {
activeTab.value = 0;
sessionStorage.removeItem('messageReturnTab');
} else {
// 从路由参数获取要显示的tab页(0=消息,1=待办)
const tab = route.query.tab;
if (tab === 'todo' || tab === '1') {
activeTab.value = 1;
} else {
activeTab.value = 0;
}
}
// 立即初始化列表数据(不需要等待接口)
initMessageList();
initTodoList();
updateUnreadCount();
// 后台异步获取最新统计数据(不阻塞页面显示)
fetchMessageStats();
});
</script>

82
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/complaintDetail.vue

@ -18,7 +18,7 @@
</div>
<div class="detail-row">
<span class="detail-label">投诉类型</span>
<span class="detail-value">{{ detail.complaintType==0?'默认':'联合检查' }}</span>
<span class="detail-value">{{ getComplaintTypeText(detail.enforceType) }}</span>
</div>
<div class="detail-row">
<span class="detail-label">投诉事项</span>
@ -59,7 +59,7 @@
<div class="detail-card">
<div class="detail-row">
<span class="detail-label">联系人</span>
<span class="detail-value">{{ detail.linkman ||'' }}</span>
<span class="detail-value">{{ detail.linkman || '' }}</span>
</div>
<div class="detail-row">
<span class="detail-label">联系电话</span>
@ -71,7 +71,7 @@
<div class="detail-card">
<div class="detail-row">
<span class="detail-label">是否授权</span>
<span class="detail-value">{{ detail.authorized ? '同意' : '不同意' }}</span>
<span class="detail-value">{{ detail.authorized ? '是' : '否' }}</span>
</div>
</div>
</div>
@ -82,12 +82,8 @@
<van-empty v-if="!progressLoading && progressList.length === 0" description="暂无处置进度" />
<div class="progress-timeline" v-else>
<div
class="progress-item"
v-for="(item, idx) in progressList"
:key="idx"
:class="{ first: idx === 0 }"
>
<div class="progress-item" v-for="(item, idx) in progressList" :key="idx"
:class="{ first: idx === 0 }">
<div class="dot-line">
<span class="dot" :class="{ active: idx === 0 }"></span>
<span class="line" v-if="idx !== progressList.length - 1"></span>
@ -118,6 +114,9 @@
import { showToast } from 'vant';
import 'vant/es/toast/style';
import { getComplaintDetail, getComplaintDisposalProgress } from '@/api/enterprise';
// 引入字典工具
import { loadDict } from '@/util/dictUtil';
import { reactive } from 'vue';
const router = useRouter();
const route = useRoute();
@ -125,6 +124,20 @@ const route = useRoute();
// 当前激活 tab
const activeTab = ref('detail');
// 投诉类型字典(与新增页面保持一致)
const complaintTypeDict = reactive({});
// 加载投诉类型字典
const loadComplaintTypeDict = () => {
loadDict('caseType', (columns) => {
columns.forEach(item => {
complaintTypeDict[item.value] = item.text;
});
}, () => {
// 加载失败不做处理,使用默认值
});
};
const detail = ref({
time: '',
bureauDept: '',
@ -167,7 +180,19 @@ const MOCK_PROGRESS_LIST = [
},
];
// 根据编码获取投诉类型显示文本
const getComplaintTypeText = (code) => {
console.log('投诉类型字典项111:', code);
if (complaintTypeDict[code] !== undefined) {
console.log('投诉类型字典项111:', code, complaintTypeDict[code]);
return complaintTypeDict[code];
}
// 默认值(兼容旧数据)
return code == 0 ? '默认' : code == 1 ? '联合检查' : (code || '');
};
onMounted(() => {
const id = route.query.id;
if (!id) {
showToast('缺少投诉ID');
@ -175,12 +200,49 @@ onMounted(() => {
}
fetchDetail(id);
fetchDisposalProgress(id);
// 加载投诉类型字典
loadComplaintTypeDict();
});
// 获取环境变量中的文件服务地址
const VITE_FILE_URL = import.meta.env.VITE_FILE_URL || '';
// 拼接完整的图片URL
const buildImageUrl = (path) => {
if (!path) return '';
// 如果已经是完整URL则直接返回
if (path.startsWith('http://') || path.startsWith('https://')) {
return path;
}
// 拼接后台地址
return VITE_FILE_URL + path;
};
const fetchDetail = (id) => {
getComplaintDetail({ id }, (res) => {
if (res && res.code === 200) {
detail.value = res.data || {};
const data = res.data || {};
// 处理附件图片,从fileList中提取uploadPath
const images = [];
if (data.fileList && Array.isArray(data.fileList)) {
data.fileList.forEach(file => {
if (file && file.uploadPath) {
images.push(buildImageUrl(file.uploadPath));
}
});
}
// 兼容旧的images字段
if (images.length === 0 && data.images && Array.isArray(data.images)) {
data.images.forEach(img => {
images.push(buildImageUrl(img));
});
}
detail.value = {
...data,
images: images
};
}
}, () => { });
};

177
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/complaintSuggestion.vue

@ -68,7 +68,7 @@
<van-radio :name="true">
<template #icon="{ checked }">
<div class="custom-radio-icon" :class="{ checked }">
<van-icon v-if="checked" name="success" size="16" color="#fff" />
<van-icon v-if="checked" name="success" size="14" color="#fff" />
</div>
</template>
<span class="radio-text">同意</span>
@ -76,7 +76,7 @@
<van-radio :name="false">
<template #icon="{ checked }">
<div class="custom-radio-icon" :class="{ checked }">
<van-icon v-if="checked" name="success" size="16" color="#fff" />
<van-icon v-if="checked" name="success" size="14" color="#fff" />
</div>
</template>
<span class="radio-text">不同意</span>
@ -94,7 +94,8 @@
<!-- 投诉事项选择弹窗 -->
<ComplaintItemPicker v-model:show="showComplaintItemPicker" :list="complaintItemList"
@select="onComplaintItemSelect" />
:loading="complaintLoading" :finished="complaintFinished"
@select="onComplaintItemSelect" @loadMore="loadComplaintItemList" @search="onComplaintItemSearch" />
<!-- 地址级联选择弹窗 -->
<van-popup v-model:show="showAddressPicker" position="bottom" :style="{ width: '100%', height: '60%' }">
@ -113,8 +114,9 @@
</template>
<script setup name="complaintSuggestion">
import { showToast } from 'vant';
import { showToast, showConfirmDialog } from 'vant';
import 'vant/es/toast/style';
import 'vant/es/dialog/style';
import { queryDict, getDeptList, getComplaintItemList, addComplaint } from '@/api/enterprise';
import { uploadFile } from '@/util/fileUpload';
import BureauPicker from '@/components/complaint/BureauPicker.vue';
@ -203,6 +205,15 @@ const onComplaintTypeConfirm = ({ text, value }) => {
// ========== 投诉事项弹窗数据 ==========
const showComplaintItemPicker = ref(false);
const complaintItemList = ref([]);
const complaintPageNum = ref(1);
const complaintPageSize = ref(10);
const complaintLoading = ref(false);
const complaintFinished = ref(false);
const complaintSearchParams = ref({
beginTime: '',
endTime: '',
searchValue: ''
});
// 将接口返回的一行数据适配为弹窗渲染结构
// 接口 /app-ent/complaint/listNotComplaint 返回字段:
@ -211,34 +222,77 @@ const complaintItemList = ref([]);
const mapComplaintItem = (item) => {
return {
id: item.id || item.relId || '',
relId: item.relId || '',
code: item.complaintItemCodes || item.complaintItemCode || item.code || '',
title: item.complaintItemNames || item.complaintItemName || item.title || '',
time: item.enforcementTime || item.enforceTime || item.createTime || '',
unit: item.complaintDepartments || item.bureauName || item.deptName || '',
unitId: item.complaintDepartmentIds || '',
subName: item.enterpriseName || item.subName || '',
userId: item.userId || '',
title: item.title || '',
enforcementTime: item.enforcementTime || '',
bureauDeptName: item.bureauDeptName || '',
lawEnforcer: item.lawEnforcer || '',
lawEnforcerId: item.lawEnforcerId || '',
lawEnforcerOther: item.lawEnforcerOther || '',
lawEnforcerOtherId: item.lawEnforcerOtherId || '',
lawEnforcementType: item.lawEnforcementType || '',
raw: item
};
};
// 加载投诉事项列表(不缓存,每次点击都重新拉取)
const loadComplaintItemList = () => {
getComplaintItemList({}, (res) => {
// 加载投诉事项列表(支持动态分页和搜索)
const loadComplaintItemList = (isRefresh = false, searchParams = null) => {
// 非刷新模式下,检查是否正在加载或已加载完成
if (!isRefresh && (complaintFinished.value || complaintLoading.value)) return;
if (isRefresh) {
complaintPageNum.value = 1;
complaintFinished.value = false;
}
// 合并搜索参数
const params = {
pageNum: complaintPageNum.value,
pageSize: complaintPageSize.value,
...complaintSearchParams.value,
...(searchParams || {})
};
complaintLoading.value = true;
getComplaintItemList(params, (res) => {
let rows = [];
if (Array.isArray(res)) rows = res;
else if (res && Array.isArray(res.rows)) rows = res.rows;
else if (res && Array.isArray(res.data)) rows = res.data;
else if (res && res.data && Array.isArray(res.data.rows)) rows = res.data.rows;
complaintItemList.value = rows.map(mapComplaintItem);
const total = res?.total ?? res?.data?.total ?? 0;
if (isRefresh) {
complaintItemList.value = rows.map(mapComplaintItem);
} else {
complaintItemList.value = [...complaintItemList.value, ...rows.map(mapComplaintItem)];
}
if (rows.length === 0 || complaintItemList.value.length >= total) {
complaintFinished.value = true;
} else {
complaintPageNum.value++;
}
complaintLoading.value = false;
}, () => {
showToast('投诉事项加载失败');
complaintLoading.value = false;
complaintFinished.value = true;
});
};
// 投诉事项弹窗搜索处理
const onComplaintItemSearch = (searchParams) => {
complaintSearchParams.value = { ...searchParams };
loadComplaintItemList(true);
};
const onComplaintItemSelect = (item) => {
form.value.complaintItem = item.title;
form.value.complaintItemCode = item.code || '';
form.value.complaintItemId = item.id || '';
showComplaintItemPicker.value = false;
};
// ========== 地址级联选择数据 ==========
@ -335,7 +389,7 @@ const showPicker = (field) => {
} else if (field === 'complaintItem') {
showComplaintItemPicker.value = true;
// 投诉事项不缓存,每次打开都刷新
loadComplaintItemList();
loadComplaintItemList(true);
} else if (field === 'address') {
showAddressPicker.value = true;
// 未加载时触发区级字典请求(已有缓存不重复调用)
@ -368,22 +422,27 @@ const onAfterReadImage = (file) => {
const files = Array.isArray(file) ? file : [file];
files.forEach(f => {
uploadFile(f, (res) => {
// 直接取返回的 data 字段(字符串路径)
const data = res && res.data ? res.data : res;
// 兼容后端返回结构
f.url = (data && (data.url || data.fileUrl || data.path)) || f.url;
f.fileName = (data && (data.fileName || data.name || data.originalFilename)) || (f.file && f.file.name) || '';
const filePath = typeof data === 'string' ? data : (data && (data.url || data.fileUrl || data.path)) || '';
if (filePath) {
// 设置文件对象的 url 属性,保持预览显示
f.url = filePath;
f.status = 'done';
}
});
});
};
// 将 form.images 转换为提交用的 fileList
// 将 form.images 转换为提交用的 fileList(纯字符串数组)
const buildFileList = () => {
return (form.value.images || [])
.filter(img => img && (img.url || img.content))
.map(img => ({
url: img.url || '',
fileName: img.fileName || (img.file && img.file.name) || ''
}));
.map(img => {
// 转换为纯字符串路径
return img.url || '';
})
.filter(Boolean);
};
// ========== 提交表单 ==========
@ -395,34 +454,44 @@ const onSubmit = () => {
showToast('附件上传中,请稍后');
return;
}
// const enterpriseAddress = ['深圳市', form.value.addressArea, form.value.addressDetail]
// .filter(Boolean)
// .join(' ');
const payload = {
enforceType: form.value.complaintTypeCode,
linkman: form.value.contactName,
linkmanTel: form.value.contactPhone,
problemDescription: form.value.content,
authorization: form.value.authorized ? 1 : 0,
addressArea: '深圳市' + form.value.addressArea,
addressDetail: form.value.addressDetail,
fileList: buildFileList(),
complaintItemCodes: form.value.complaintItemCode || '',
complaintItemNames: form.value.complaintItem || '',
complaintDepartments: form.value.bureauDept || '',
complaintDepartmentIds: form.value.bureauDeptId || ''
};
submitting.value = true;
addComplaint(payload, () => {
submitting.value = false;
showToast('提交成功,我们将尽快处理');
setTimeout(() => {
// 提交成功后直接回到我的页面,用 replace 清掉中间的投诉相关页面
router.replace({ name: 'myPage' });
}, 1200);
}, (err) => {
submitting.value = false;
showToast((err && err.msg) || '提交失败,请稍后重试');
// 弹出确认对话框
showConfirmDialog({
title: '确认提交',
message: '确认提交本次投诉建议吗?提交后将无法修改。',
}).then(() => {
// 确认提交
// const enterpriseAddress = ['深圳市', form.value.addressArea, form.value.addressDetail]
// .filter(Boolean)
// .join(' ');
const payload = {
enforceType: form.value.complaintTypeCode,
linkman: form.value.contactName,
linkmanTel: form.value.contactPhone,
problemDescription: form.value.content,
authorization: form.value.authorized ? 1 : 0,
enterpriseAddress: '深圳市' + form.value.addressArea,
detailedAddress: form.value.addressDetail,
fileList: buildFileList(),
complaintItemCodes: form.value.complaintItemCode || '',
complaintItemNames: form.value.complaintItem || '',
complaintDepartments: form.value.bureauDept || '',
complaintDepartmentIds: form.value.bureauDeptId || ''
};
submitting.value = true;
addComplaint(payload, () => {
submitting.value = false;
showToast('提交成功,我们将尽快处理');
setTimeout(() => {
// 提交成功后直接回到我的页面,用 replace 清掉中间的投诉相关页面
router.replace({ name: 'complaintList' });
}, 500);
}, (err) => {
submitting.value = false;
showToast((err && err.msg) || '提交失败,请稍后重试');
});
}).catch(() => {
// 取消提交
});
};
@ -605,13 +674,13 @@ const onFailed = (errorInfo) => {
.address-field {
padding: 0.15rem 0.3rem 0.3rem;
background: transparent;
margin-left: 70px;
margin-left: 86px;
box-sizing: border-box;
width: 80%;
:deep(.van-field__control) {
font-size: 0.32rem;
color: #999;
color: #333;
text-align: left;
}

18
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/settings.vue

@ -61,6 +61,7 @@ const router = useRouter();
const companyName = ref('');
const phone = ref('');
const avatar = ref('');
const userId = ref('');
const defaultAvatar = 'https://img.yzcdn.cn/vant/cat.jpeg';
// ========== 电话编辑弹窗 ==========
@ -69,12 +70,17 @@ const editPhone = ref('');
// ========== 获取企业信息 ==========
const fetchUserMine = () => {
getUserMine({}, (res) => {
// 从会话存储中获取 useCommon
const useCommonStr = sessionStorage.getItem('useCommon');
const useCommon = useCommonStr ? JSON.parse(useCommonStr) : {};
const sessionUserId = useCommon.userId || '';
getUserMine({ userId: sessionUserId }, (res) => {
if (res) {
companyName.value = res.deptName || '';
phone.value = res.phonenumber || '';
avatar.value = res.avatar || '';
userId.value = res.userId || '';
companyName.value = res.data.deptName || '';
phone.value = res.data.phonenumber || '';
avatar.value = res.data.avatar || '';
userId.value = res.data.userId || '';
} else {
showToast(res.msg || '企业信息加载失败');
}
@ -123,7 +129,7 @@ const onBeforeClose = (action) => {
return;
}
// 调用后端修改联系电话接口
updateContactPhone({ phone : editPhone.value, userId: userId.value }, (res) => {
updateContactPhone({ phoneNumber : editPhone.value, userId: userId.value }, (res) => {
if (res && (res.code === 200 || res.success === true)) {
phone.value = editPhone.value;
showToast('联系电话修改成功');

44
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/qr/qrCode.vue

@ -27,7 +27,8 @@
<span class="qr_code_text">生成时间:{{ data.generateTime }}</span>
</div>
<van-action-bar>
<van-action-bar-button color="#2b75fd" text="下载二维码[需要和深i企集成,todo]" @click="download(data.qrCodeUrl)" />
<!-- <van-action-bar-button color="#2b75fd" text="下载二维码[需要和深i企集成,todo]" @click="download(data.qrCodeUrl)" /> -->
<van-action-bar-button color="#2b75fd" text="下载二维码[需要和深i企集成,todo]" @click="downloadFile(data.qrCodeUrl)" />
<!-- <van-action-bar-button color="#2b75fd" text="二维码管理" @click="toHisrotyView()" />-->
</van-action-bar>
</div>
@ -37,7 +38,7 @@
<script setup name="register">
import {baseUrl} from "../../../config/env";
import {queryEnterpriseInformationQrCode} from '../../../api/enterprise'
import {queryEnterpriseInformationQrCode, forceGenerateQrCode} from '../../../api/enterprise'
import * as w6s from 'szient-js-sdk';
import sha1 from 'crypto-js/sha1';
import { reactive } from "vue";
@ -59,26 +60,37 @@ const goBack = () => {
onMounted(() => {
queryEnterpriseInformationQrCode(route?.query?.enterpriseNumber
,success =>{
if(success.success){
data.qrCodeUrl = baseUrl + success.data.qrCodeUrl;
data.enterpriseName = success.data.enterpriseName;
data.generateTime = success.data.generateTime;
queryEnterpriseInformationQrCode({}, success =>{
if(success.code === 200 && success.data){
data.qrCodeUrl = import.meta.env.VITE_FILE_URL + (success.data.qrCodeUrl || '');
console.log(data.qrCodeUrl);
data.enterpriseName = success.data.enterpriseName || '';
data.generateTime = success.data.generateTime || '';
}
},error =>{
console.log("查询失败")
})
});
const downloadFile = (url) => {
const a = document.createElement('a')
a.href = url
a.download = "123456" // 下载后文件名
a.style.display = 'none'
document.body.appendChild(a)
a.click() // 点击下载
document.body.removeChild(a) // 下载完成移除元素
const downloadFile = () => {
// 调用强制生成二维码接口
forceGenerateQrCode({}, (res) => {
console.log('强制生成二维码接口响应:', res);
if (res && res.data && res.data.qrCodeUrl) {
// 拼接文件服务器地址
const fullUrl = import.meta.env.VITE_FILE_URL + res.data.qrCodeUrl;
// 执行下载
const a = document.createElement('a')
a.href = fullUrl
a.download = "qrcode" // 下载后文件名
a.style.display = 'none'
document.body.appendChild(a)
a.click() // 点击下载
document.body.removeChild(a) // 下载完成移除元素
}
}, (err) => {
console.error('调用接口失败:', err);
});
}
const download = (url) =>{
console.log(url);

30
zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev.yml

@ -1,7 +1,7 @@
zdxt:
file:
# upload-path: /usr/local/uploadPath
upload-path: /Users/vincent/uploadPath
upload-path: /usr/local/uploadPath
# upload-path: /Users/vincent/uploadPath
url-prefix: /profile
qr_code_url: /usr/local/uploads/zfjd_logo.png
demo_enabled: false
@ -311,3 +311,29 @@ mssq:
hcpappid: zfjdm
hcpsign: ENC(SZL+KT860YpMBuK6GbNWTp0TYVeSu/DTYjKPRCm5xVJk9tI+O6/hqsE5zH9orApgjX6ggAS2hbGefmUsJwIkos0YtIgueK89ilDHtEy6/S0RWrnoi6F9aByxVG/mAwPxTPIXxwUECjvuET1rByTi7juNbufzWzJfYrH4dFXLmzbF5Cv5jJHM8R7Rq6DGL9X9UCqmROJygXv9KvrxN3OcnVoTHb0wQepEq6kplkd3SswLnPSDpb7q5vcs1XMxYcFRDLyqjmQYVRcx3HMsQZOGkTahOdzIfI/tL4D4upgYK1TFpaCiBL98vX/bh/s9RPmiHkyqMd8/R/NnoB8q5/5LldqxBhPCBi6RbPFGM/UfojdXeS5z2Uk/2w==)
hcptimestamp: 20240710172956
#深圳易平台对接密钥
szypt:
#测试
agentid: ENC(JHe/LoW7bh5Cxpn8BJ2Q6Q==)
url: ENC(pRnuGFcSRfkkLTp7NLU5EvD5QpSdkobiPlxjRhGE5l/Uvrur9isTzMkqYoYgMrHt)
corpid: ENC(jrCQGAujvdFRc5tCE8g8oM9F0Ln7shZoXB7WeM3Tzhs=)
corpsecret: ENC(Z8hjBADO1lZDAhOB7/ku9FpPIkYk4mGwyFH01vSwefMxweTeGaMuajSc9vD4bPL1wdgVhS/ZPeI=)
#市认证网关
srnwsrnwgg:
#正式
url: ENC(pHNm/o0+6S+HjrM5nuMiPRfkrHS1tXYD5i25OBtM4dWSi6MvH6iXfw==)
systemCode: ENC(cHDdxMKpJ/rbuj4PVCxylN+zPd9I2KT0)
integrationKey: ENC(txSndcPbZK5mYjW7Doa/n9Ips2PLa9NV)
paasId: szsfj_zhifajianduma_001
paasToken: ENC(VfUgR5OXHJcKvBBfq/2ysuNPH6I7tCCeWHYSzXKicGChlMiw9mVPGD51naX9w42E)
#市认证数据加密字符
secretKey: ENC(xWBA5VwT23j14A8+6I15HCerJvo3zaRxzVE2xc0i7wZ7wq/SCflOEkHCc8wwdi0KHkDGjKIoHhs=)
# #测试
# url: ENC(jFwf6bYIMn+FOtbCkyPr0r+TBOPrp84tNotl912ilUZy2e9Y8cbH3uDQ5jtr6SAa)
# systemCode: ENC(ECOnqNVVPmCmnqhde6tsS5JEQYPtlmCv)
# integrationKey: ENC(8RZtrfL4t5tsEk7lfrw00+4hSxbjxcVM)
# paasId: szsfj_zhifajianduma_001
# paasToken: ENC(0Cg8Vtpay+3hwRm+vJB0utikr4dXcEguwSaxlbTWkgQ4parB8pN2rL2xrhQ8eUd5)

1
zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml

@ -37,6 +37,7 @@ logging:
org.springframework: warn
org.mybatis.spring.mapper: debug
org.apache.fury: warn
com.zdxt.enforcementcode: debug
config: classpath:logback-plus.xml
# 用户配置

Loading…
Cancel
Save