Browse Source

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

dev-V1.10.2-temp
vincent 3 months ago
parent
commit
88d1e0956f
  1. 11
      doc/部署说明/部署过程描述.md
  2. 50
      ng/1/nginx.conf
  3. 3
      script/sql/zfjd-refactoring-v1/其他/njy/njy.sql
  4. 3
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java
  5. 6
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/NonEnforcementRegistration.java
  6. 1
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/NonEnforcementRegistrationVo.java
  7. 2
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpSettingService.java
  8. 15
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpNoticeServiceImpl.java
  9. 2
      zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml
  10. 11
      zdxt-web-client/zdxt-admin-plus-ui/src/store/modules/permission.ts
  11. 4
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/nos/EnforcementInfoSection.vue
  12. 9
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/nos/RegisterPopups.vue
  13. 45
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnforcementInfoSection.vue
  14. 5
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnterpriseInfoSection.vue
  15. 9
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnterpriseSelector.vue
  16. 9
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/NonEnforcementInfoSection.vue
  17. 15
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/RegisterPopups.vue
  18. 8
      zdxt-web-client/zdxt-efcode-enforcement-app/src/store/Common.js
  19. 29
      zdxt-web-client/zdxt-efcode-enforcement-app/src/util/util.js
  20. 15
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enforce/enforcementNoticeList.vue
  21. 82
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enforce/enforcementRegister.vue
  22. 26
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enterpriseScanPreview.vue
  23. 1
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/home/enforcementHome.vue
  24. 1
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/loginByPassword.vue
  25. 274
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_detail.vue
  26. 44
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_edit.vue
  27. 6
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_tab_content.vue
  28. 18
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_edit.vue
  29. 2
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue
  30. 15
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/nos/nosAdd.vue
  31. 2
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/nos/nosDetail.vue
  32. 2
      zdxt-web-client/zdxt-efcode-enterprise-app/src/api/enterprise/planNotice.js
  33. 8
      zdxt-web-client/zdxt-efcode-enterprise-app/src/router/enterprise-app/ent-main-router.js
  34. 60
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementEvaluateDetail.vue
  35. 24
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementRegistrationList.vue
  36. 6
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/message/messageCenter.vue
  37. 5
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/myPage.vue
  38. 216
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/plan/planNoticeDetail.vue
  39. 15
      zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/plan/planNoticeList.vue
  40. 5
      zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/enterprise_pub_qrcode.json

11
doc/部署说明/部署过程描述.md

@ -38,7 +38,7 @@ Nginx 是源码编译安装的,安装在 `/usr/local/nginx/`,可执行文件
* 备份数据库
* 备份1期库(排除市监表)
```bash
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events --ignore-table=zfjd.sszt_jbxx110497_new --ignore-table=zfjd.sszt_jbxx110497 zfjd > /efcode20/dbv1/zfjd_2026_07_21_ex_sszt_jbxx_utf8.sql
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events --ignore-table=zfjd.sszt_jbxx110497_new --ignore-table=zfjd.sszt_jbxx110497 zfjd > /efcode20/dbv1/zfjd_2026_08_05_ex_sszt_jbxx_utf8.sql
```
* 单独备份市监表
```bash
@ -85,18 +85,21 @@ Nginx 是源码编译安装的,安装在 `/usr/local/nginx/`,可执行文件
* 备份2期库
* 查询字符集
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 zfjd_ef20_prod -e "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='zfjd_ef20_1';"
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 zfjd_ef20_prod -e "SHOW CREATE TABLE zdxt_file\G"
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 zfjd_ef20_prod -e "select * from zdxt_file where org_code is not null;"
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' zfjd -e "ALTER TABLE zdxt_file MODIFY COLUMN org_code varchar(100) NULL COMMENT '机构编号';"
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' -e "select count(*) from zfjd.sszt_jbxx110497_new"
* 备份1期库(排除市监表)
* 备份2期库(排除市监表)
```bash
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events --ignore-table=zfjd_ef20_1.sszt_jbxx110497_new --ignore-table=zfjd_ef20_1.sszt_jbxx110497 zfjd_ef20_1 > /efcode20/dbv2/zfjd_ef20_1_2026_06_20_utf8.sql
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events zfjd_ef20_prod > /efcode20/dbv2/zfjd_ef20_prod_2026_07_30_utf8.sql
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events zfjd_ef20_prod > /efcode20/dbv2/zfjd_ef20_prod_2026_08_05_utf8.sql
```
* 单独备份市监表
```bash
mysqldump -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 --single-transaction --triggers --events zfjd_ef20_1 sszt_jbxx110497_new > /efcode20/dbv2/zfjd_ef20_1_2026_06_20_utf8_sszt_jbxx110497_new.sql
```
* 压缩备份文件
zip -e -P 'xj.sdeweqwew222qwe.12345' /efcode20/dbv2/zfjd_ef20_prod_2026_07_30.zip /efcode20/dbv2/zfjd_ef20_prod_2026_07_30_utf8.sql
zip -e -P 'xj.sdeweqwew222qwe.12345' /efcode20/dbv2/zfjd_ef20_prod_2026_08_05_utf8.zip /efcode20/dbv2/zfjd_ef20_prod_2026_08_05_utf8.sql
* 导入2期库
```
mysql -h 10.134.89.36 -P 15144 -u zfjd -p'szsf@zfjd' --default-character-set=utf8mb4 zfjd_ef20_prod < /efcode20/dbv2/zfjd_ef20_1_2026_07_21_utf8.sql

50
ng/1/nginx.conf

@ -24,6 +24,9 @@ http {
include mime.types;
default_type application/octet-stream;
# 允许带下划线_的header
underscores_in_headers on;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
@ -39,13 +42,52 @@ http {
#gzip on;
server {
listen 12004;
location / {
proxy_pass http://10.76.108.1:85;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /efcode20-sup-web/ {
proxy_pass http://10.76.108.15:12004/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 民生述求跳转
location /mssq_proxy/ {
proxy_pass http://10.224.158.101:8182/proxy/;
# 保留原始请求头
proxy_pass_request_headers on;
proxy_pass_request_body on;
# 关键:不要伪造 Host
proxy_set_header Host $proxy_host;
# 保留客户端信息
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# token / session 常用
proxy_set_header Authorization $http_authorization;
proxy_set_header Cookie $http_cookie;
# 保持长连接行为
proxy_http_version 1.1;
# 如果接口有响应跳转地址,自动改回来
proxy_redirect off;
}
# 政务微信跳转
location /zwwx_proxy/ {
proxy_pass https://zwwx-hlht.sz.gov.cn:30443/;
# 保持长连接行为
proxy_http_version 1.1;
}
}
server {
listen 80;
@ -58,8 +100,14 @@ http {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
location /efcode20-sup-web/ {
proxy_pass http://10.76.108.15:12004/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html

3
script/sql/zfjd-refactoring-v1/其他/njy/njy.sql

@ -13,3 +13,6 @@ ALTER TABLE siq_msg_info ADD error_msg varchar(500) NULL COMMENT '错误信息';
ALTER TABLE efcode_cp_task ADD is_read INT DEFAULT 0 NULL COMMENT '是否已读 0:未读 1:已读';
ALTER TABLE efcode_cp_reserve ADD is_read INT DEFAULT 0 NULL COMMENT '预约是否已读 0:未读 1:已读';
ALTER TABLE efcode_cp_notice ADD is_read INT DEFAULT 0 NULL COMMENT '预告是否已读 0:未读 1:已读';
ALTER TABLE enterprise_information MODIFY COLUMN enterprise_tel varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '企业联系电话';

3
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfCpPlanController.java

@ -80,7 +80,8 @@ public class AppEnfCpPlanController extends EfcodeCpPlanController {
*/
@GetMapping("/reserve/check/{targetPlanId}")
public R<Void> checkCanReserve(@PathVariable String targetPlanId) {
return cpReserveService.checkCanReserve(targetPlanId);
cpReserveService.checkCanReserve(targetPlanId);
return R.ok();
}
/**

6
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/NonEnforcementRegistration.java

@ -16,9 +16,9 @@ import java.io.Serial;
* @date 2026-05-19
*/
@Data
@EqualsAndHashCode(callSuper = true)
@EqualsAndHashCode(callSuper = false)
@TableName("non_enforcement_registration")
public class NonEnforcementRegistration extends BaseEntity {
public class NonEnforcementRegistration {
@Serial
private static final long serialVersionUID = 1L;
@ -184,5 +184,7 @@ public class NonEnforcementRegistration extends BaseEntity {
*/
private String reason;
private String createBy;
}

1
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/NonEnforcementRegistrationVo.java

@ -233,4 +233,5 @@ public class NonEnforcementRegistrationVo implements Serializable {
*/
private String area;
private String createBy;
}

2
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEfcodeCpSettingService.java

@ -59,7 +59,7 @@ public interface IEfcodeCpSettingService {
/**
* 默认值:下阶段计划提交最晚时间
*/
int DEFAULT_SUBMIT_DEADLINE = 26;
int DEFAULT_SUBMIT_DEADLINE = 25;
/**
* 默认值:系统自动推荐匹配开始时间(号)

15
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EfcodeCpNoticeServiceImpl.java

@ -2,9 +2,12 @@ package com.zdxt.enforcementcode.service.impl;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.zdxt.enforcementcode.common.commonenum.MsgSourceTypeEnum;
import com.zdxt.enforcementcode.domain.EnterpriseInformation;
import com.zdxt.enforcementcode.domain.bean.EnforcementEducationServices;
import com.zdxt.enforcementcode.domain.bo.thirdparty.YuGaoMsgParamBo;
import com.zdxt.enforcementcode.mapper.EnterpriseInformationMapper;
import com.zdxt.enforcementcode.service.ISysMessageViewLogService;
import com.zdxt.enforcementcode.service.thirdparty.ISIQService;
import org.dromara.common.core.utils.MapstructUtils;
@ -47,6 +50,7 @@ public class EfcodeCpNoticeServiceImpl implements IEfcodeCpNoticeService {
private final EfcodeCpNoticeMessageMapper noticeMessageMapper;
private final ISysMessageViewLogService sysMessageViewLogService;
private final ISIQService siqService;
private final EnterpriseInformationMapper enterpriseInformationMapper;
/**
* 查询行政执法检查计划-预告
*/
@ -143,6 +147,11 @@ public class EfcodeCpNoticeServiceImpl implements IEfcodeCpNoticeService {
getSendYuGaoMsg(entity);
}
//同步更新企业电话
UpdateWrapper<EnterpriseInformation> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("enterprise_number",entity.getEnterpriseNumber());
updateWrapper.set("enterprise_tel",entity.getContactPhone());
enterpriseInformationMapper.update(updateWrapper);
return "操作成功";
}
@ -186,6 +195,12 @@ public class EfcodeCpNoticeServiceImpl implements IEfcodeCpNoticeService {
if (update.getStatus() != null && update.getStatus() == 1L) {
generateSystemMessage(update);
}
//同步更新企业电话
UpdateWrapper<EnterpriseInformation> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("enterprise_number",bo.getEnterpriseNumber());
updateWrapper.set("enterprise_tel",bo.getContactPhone());
enterpriseInformationMapper.update(updateWrapper);
return "操作成功";
}

2
zdxt-modules/zdxt-enforcement-code/src/main/resources/mapper/enforcementcode/EfcodeVirtualUnitMapper.xml

@ -26,7 +26,7 @@
</choose>
FROM sys_user u
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE u.del_flag = '0' and d.dept_id != 405
WHERE u.del_flag = '0' and d.dept_id != 405 and u.user_name != 'admin'
<if test="!globalSearch and sysDeptId != null and sysDeptId != ''">
AND (u.dept_id = #{sysDeptId} OR u.dept_id IN (
SELECT t.dept_id FROM sys_dept t WHERE t.del_flag = '0' AND FIND_IN_SET(#{sysDeptId}, t.ancestors)

11
zdxt-web-client/zdxt-admin-plus-ui/src/store/modules/permission.ts

@ -28,7 +28,7 @@ export interface SystemCodeOption {
export const CATCH_ALL_ROUTE_NAME = 'CatchAll404';
//http://10.132.108.3:85/loginByUserId
export const systemCodeOptions: SystemCodeOption[] = [
{ label: '首页', value: 'planindex', icon: 'HomeFilled', iframeUrl: 'http://10.132.108.3:85/loginByUserId' },
{ label: '首页', value: 'planindex', icon: 'HomeFilled', iframeUrl: 'Same-origin/loginByUserId' },
{ label: '执法监督码', value: 'supervisionCode', icon: 'Document' },
{ label: '后台管理', value: 'authService', icon: 'Setting' }
];
@ -39,13 +39,18 @@ export const usePermissionStore = defineStore('permission', () => {
*/
const buildIframeUrl = (baseUrl: string): string => {
if (!baseUrl) return '';
// 当配置了 Same-origin 占位符时,替换为浏览器当前的 origin(协议+主机+端口)
let resolvedUrl = baseUrl;
if (baseUrl.includes('Same-origin')) {
resolvedUrl = baseUrl.replace('Same-origin', window.location.origin);
}
const userStore = useUserStore();
const params = new URLSearchParams();
if (userStore.v1SystemCredential) {
params.set('v1_system_credential', userStore.v1SystemCredential);
}
const separator = baseUrl.includes('?') ? '&' : '?';
return baseUrl + separator + params.toString();
const separator = resolvedUrl.includes('?') ? '&' : '?';
return resolvedUrl + separator + params.toString();
};
const routes = ref<RouteRecordRaw[]>([]);

4
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/nos/EnforcementInfoSection.vue

@ -17,11 +17,11 @@
<div class="form-label"><span class="required-mark" :class="{ 'required-mark--placeholder': formData.taskTypeId == 5 }">*</span>{{ formData.taskTypeId == 1 ? '执法人员' : '参与人员' }}</div>
<div class="form-value person-select">
<div class="person-item default-person">
<span>{{ defaultPerson?.lawEnforcerName }} {{ defaultPerson?.lawEnforcerIdCard ?? defaultPerson?.lawEnforcerPhone }}</span>
<span>{{ defaultPerson?.lawEnforcerName }} {{ defaultPerson?.lawEnforcerIdCard || defaultPerson?.lawEnforcerPhone }}</span>
</div>
<div v-for="(person, index) in additionalPersons" :key="index" class="person-item-add">
<span @click="$emit('openPersonPicker', index)" :class="{ placeholder: !person.lawEnforcerName }">
{{ person.lawEnforcerName || "请选择" }} {{ person.lawEnforcerIdCard ?? person.lawEnforcerPhone }}
{{ person.lawEnforcerName || "请选择" }} {{ person.lawEnforcerIdCard || person.lawEnforcerPhone }}
</span>
<van-icon name="close" class="remove-icon" @click="$emit('removePerson', index)" />
</div>

9
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/nos/RegisterPopups.vue

@ -49,7 +49,7 @@
<div v-for="(person, index) in personList" :key="index" class="person-list-item"
@click="handleSelectPerson(person)">
<div class="person-name">{{ person.userName }}</div>
<div class="person-id">执法证件号:{{ person.lawEnforcerIdCard ?? person.lawEnforcerPhone }}</div>
<div class="person-id">执法证件号:{{ person.lawCertificateNum || person.phonenumber || person.mobileNumber }}</div>
</div>
<van-empty v-if="personList.length === 0 && !personLoading" description="暂无数据" />
</van-list>
@ -298,11 +298,14 @@ const loadPersonList = () => {
userId: item.userId,
userName: item.userName,
phonenumber: item.phonenumber,
lawEnforcerIdCard: item.mobileNumber,
lawEnforcerIdCard: item.lawCertificateNum,
lawEnforcerId: item.userId,
lawEnforcerName: item.userName,
lawEnforcerPhone: item.phonenumber,
lawEnforcerPhone: item.mobileNumber,
lawCertificateNum: item.lawCertificateNum,
mobileNumber: item.mobileNumber,
}))
console.log(data)
const total = res.total || res.count || 0
if (personPageNum.value === 1) {

45
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnforcementInfoSection.vue

@ -15,7 +15,7 @@
<div class="form-label"><span class="required-mark">*</span>执法人员</div>
<div class="form-value person-select">
<div class="person-item default-person">
<span>{{ defaultPerson?.name }} {{ defaultPerson?.phonenumber }}</span>
<span>{{ defaultPerson?.name }} {{ defaultPerson?.lawCertificateNum || defaultPerson?.phonenumber }} </span>
</div>
<div v-for="(person, index) in additionalPersons" :key="index" class="person-item-add">
<span @click="$emit('openPersonPicker', index)" :class="{ placeholder: !person.name }">
@ -64,9 +64,11 @@
</div>
<!-- 原因 -->
<template v-if="showReason">
<van-field v-model="formData.reason" name="reason" label="原因" :placeholder="formData.reason || '请选择'" readonly
:clickable="canSelectReason" :is-link="canSelectReason"
:rules="[{ required: true, message: '请选择原因' }]" required
:rules="canSelectReason ? [{ required: true, message: '请选择原因' }] : []"
:required="canSelectReason"
@click="canSelectReason && (showReasonPicker = true)" />
<!-- 原因选择弹窗 -->
@ -79,6 +81,7 @@
<van-field v-if="formData.reason === '其他'" v-model="formData.otherReasons" name="otherReasons" label="其他原因"
placeholder="请输入其他原因" type="textarea" rows="3" maxlength="500" show-word-limit
:rules="[{ required: true, message: '请填写其他原因' }]" required />
</template>
<!-- 执法时间(可选,近10天内) -->
<van-field v-model="formData.enforcementTime" name="enforcementTime" label="执法时间" placeholder="请选择执法时间" readonly
@ -189,6 +192,10 @@ const props = defineProps({
type: Boolean,
default: false
},
showReason: {
type: Boolean,
default: true
},
canEditTime: {
type: Boolean,
default: true
@ -396,14 +403,16 @@ const onAfterReadImage = (file) => {
.required-mark {
color: #ee0a24;
font-size: 0.32rem;
margin-right: 0.08rem;
font-size: 15px;
font-weight: bold;
position: absolute;
left: -4px;
top: 2px;
}
.form-label {
font-size: 14px;
color: #333;
color: #000;
flex: none;
width: 2.4rem;
font-weight: 500;
@ -467,12 +476,10 @@ const onAfterReadImage = (file) => {
}
.basis-container {
margin-bottom: 0.12rem;
margin-left: 6px;
}
.basis-row {
padding: 0.24rem 0.32rem;
padding: 0.26rem 0.42667rem;
}
.basis-wrapper {
@ -554,7 +561,10 @@ const onAfterReadImage = (file) => {
justify-content: flex-end;
color: #000;
}
:deep(.van-field__label) {
font-size: 14px;
color: #000;
}
:deep(.van-checkbox__label) {
font-size: 14px;
color: #333;
@ -575,7 +585,7 @@ const onAfterReadImage = (file) => {
:deep(.van-field__label) {
font-size: 14px;
color: #333;
color: #000;
}
}
@ -624,11 +634,11 @@ const onAfterReadImage = (file) => {
}
.file-upload-row {
padding: 0px 20px 20px 20px;
padding: 0px 20px 20px 16px;
.file-upload-label {
font-size: 14px;
color: #333;
color: #000;
margin-bottom: 0.16rem;
}
}
@ -639,4 +649,15 @@ const onAfterReadImage = (file) => {
border-radius: 0.1rem;
}
}
.entrusted-options{
:deep(.van-field__label){
width:100px;
color: #000;
}
}
:deep(.van-field__label--required:before){
position: absolute;
left: 8px;
top: 10px;
}
</style>

5
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnterpriseInfoSection.vue

@ -87,4 +87,9 @@ const handleClick = () => {
color: #000;
}
:deep(.van-field__label--required:before){
position: absolute;
left: 8px;
top: 10px;
}
</style>

9
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/EnterpriseSelector.vue

@ -17,7 +17,8 @@
<div v-for="(item, index) in enterpriseList" :key="index" class="enterprise-list-item"
@click="handleSelectEnterprise(item)">
<div class="enterprise-qr">
<van-icon name="qr" />
<img v-if="item.qrCodeUrl" :src="item.qrCodeUrl" class="qr-image" />
<van-icon v-else name="qr" />
</div>
<div class="enterprise-info">
<div class="enterprise-name">{{ item.enterpriseName }}</div>
@ -248,7 +249,11 @@ const handleClose = () => {
flex-direction: column;
}
}
.enterprise-qr .qr-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.enterprise-name {
font-size: 16px;
color: #333;

9
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/NonEnforcementInfoSection.vue

@ -59,9 +59,11 @@
</div>
<!-- 原因 -->
<template v-if="showReason">
<van-field v-model="formData.reason" name="reason" label="原因" :placeholder="formData.reason || '请选择'" readonly
:clickable="canSelectReason" :is-link="canSelectReason"
:rules="[{ required: true, message: '请选择原因' }]" required
:rules="canSelectReason ? [{ required: true, message: '请选择原因' }] : []"
:required="canSelectReason"
@click="canSelectReason && (showReasonPicker = true)" />
<!-- 原因选择弹窗 -->
@ -74,6 +76,7 @@
<van-field v-if="formData.reason === '其他'" v-model="formData.otherReasons" name="otherReasons" label="其他原因"
placeholder="请输入其他原因" type="textarea" rows="3" maxlength="500" show-word-limit
:rules="[{ required: true, message: '请填写其他原因' }]" required />
</template>
<!-- 入企时间(可选,近10天内;仅补录模式可编辑) -->
<van-field v-model="formData.enforcementTime" name="enforcementTime" label="入企时间" placeholder="请选择入企时间"
@ -181,6 +184,10 @@ const props = defineProps({
type: Boolean,
default: false
},
showReason: {
type: Boolean,
default: true
},
canEditTime: {
type: Boolean,
default: false

15
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/RegisterPopups.vue

@ -58,7 +58,7 @@
<div v-for="(person, index) in personList" :key="index" class="person-list-item"
@click="handleSelectPerson(person)">
<div class="person-name">{{ person.userName }}</div>
<div class="person-id">执法证件号:{{ person.mobileNumber }}</div>
<div class="person-id">执法证件号:{{ person.lawCertificateNum || person.phonenumber || person.mobileNumber }}</div>
</div>
<van-empty v-if="personList.length === 0 && !personLoading" description="暂无数据" />
</van-list>
@ -242,7 +242,15 @@ const loadPersonList = () => {
console.log(params);
getBureauUnitUsers(params, (res) => {
if (res.code === 200 || res.code === 0) {
const data = res.data || res.rows || [];
let data = res.data || res.rows || [];
// 前端过滤:移除已选择的人员
const selectedIds = props.selectedPersons.map(p => p.lawCertificateNum || p.userId || p.id).filter(Boolean);
if (selectedIds.length > 0) {
data = data.filter(item => {
const id = item.lawCertificateNum || item.mobileNumber || item.userId || item.id || '';
return !selectedIds.includes(id);
});
}
const total = res.total || res.count || 0;
if (personPageNum.value === 1) {
personList.value = data;
@ -283,7 +291,8 @@ const handleSelectPerson = (person) => {
// 转换字段名称,将接口返回的 userName 转换为 name,phonenumber 转换为 id
emit('selectPerson', {
name: person.userName || person.name || '',
id: person.mobileNumber || person.id || ''
id: person.lawCertificateNum || person.mobileNumber || '',
userId: person.userId || '',
});
localPersonPopup.value = false;
};

8
zdxt-web-client/zdxt-efcode-enforcement-app/src/store/Common.js

@ -36,6 +36,8 @@ export default defineStore('useCommon', {
firstLoad: true,
// 是否执法人员
hasLaw: false,
// 执法证件号
lawCertificateNum: "",
}),
getters: {},
actions: {
@ -115,6 +117,10 @@ export default defineStore('useCommon', {
SET_HAS_LAW(data){
this.hasLaw = data;
},
//设置执法证件号
SET_LAW_CERTIFICATE_NUM(data){
this.lawCertificateNum = data;
},
// 获取多语言数据
/*async getLang(params) {
let url = $globalRequestUrl({
@ -157,6 +163,6 @@ export default defineStore('useCommon', {
},
persist: {
storage: sessionStorage,
pick: ['token', 'userId', 'userName', 'nickName', 'enterpriseNumber', 'enterpriseName', 'enterpriseId', 'phonenumber', 'deptId', 'deptName', 'organId', 'organName', 'bureauUnitId', 'bureauUnitName', 'hasLaw'],
pick: ['token', 'userId', 'userName', 'nickName', 'enterpriseNumber', 'enterpriseName', 'enterpriseId', 'phonenumber', 'deptId', 'deptName', 'organId', 'organName', 'bureauUnitId', 'bureauUnitName', 'hasLaw', 'lawCertificateNum'],
},
});

29
zdxt-web-client/zdxt-efcode-enforcement-app/src/util/util.js

@ -122,9 +122,17 @@ const formatTime = (dateStr) => {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
const h = String(d.getHours()).padStart(2, '0');
const min = String(d.getMinutes()).padStart(2, '0');
return `${y}-${m}-${day} ${h}:${min}:00`;
const h = d.getHours();
const min = d.getMinutes();
const sec = d.getSeconds();
// 时分秒全为0时只展示日期
if (h === 0 && min === 0 && sec === 0) {
return `${y}-${m}-${day}`;
}
const hh = String(h).padStart(2, '0');
const mm = String(min).padStart(2, '0');
const ss = String(sec).padStart(2, '0');
return `${y}-${m}-${day} ${hh}:${mm}:${ss}`;
};
/**
@ -182,4 +190,17 @@ const formatEnforcer = (item) => {
return enforcers;
};
export { setGoodsNum, isObject, comparisonObject, isElementHidden, formattedTimeYYYYmmdd, formattedTime, getDeviceType, formattedDate, formatEnforcer, formatTime };
/**
* 电话号码脱敏处理
* 保留前3位和后4位,中间用 4 个 * 替换
* @param {string|number} phone 原始电话号码
* @returns {string} 脱敏后的电话号码,如 138****5678
*/
const maskPhone = (phone) => {
if (!phone) return '';
const str = String(phone);
if (str.length < 7) return str;
return str.substring(0, 3) + '****' + str.substring(str.length - 4);
};
export { setGoodsNum, isObject, comparisonObject, isElementHidden, formattedTimeYYYYmmdd, formattedTime, getDeviceType, formattedDate, formatEnforcer, formatTime, maskPhone };

15
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enforce/enforcementNoticeList.vue

@ -22,7 +22,7 @@
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="onLoad" :offset="50">
<van-empty v-if="finished && list.length === 0" description="暂无数据" />
<div class="notice-card" v-for="item in list" :key="item.id">
<div class="notice-card" v-for="item in list" :key="item.id" @click="onViewDetail(item)">
<div class="card-row time-row">
<span class="label">执法时间:</span>
<span class="value">{{ item.enforceDate }}</span>
@ -34,7 +34,7 @@
</div>
<div class="card-action">
<span class="feedback-btn" :class="{ 'has-dot': item.hasFeedback }"
@click="onFeedback(item)">
@click.stop="onFeedback(item)">
<van-icon name="chat-o" size="14" />
反馈
</span>
@ -164,6 +164,16 @@ const onFeedback = (item) => {
});
};
// ========== 查看预告详情 ==========
const onViewDetail = (item) => {
router.push({
path: '/enforcement/notice/detail',
query: {
id: item.id,
}
});
};
// ========== 页面挂载加载数据 ==========
onMounted(() => {
fetchList();
@ -211,6 +221,7 @@ onMounted(() => {
padding: 0.3rem 0.35rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
cursor: pointer;
}
.card-row {

82
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enforce/enforcementRegister.vue

@ -7,7 +7,7 @@
</div> -->
<!-- 表单主体 -->
<van-form @submit="onSubmit" scroll-to-error class="page-content">
<van-form ref="formRef" @submit="onSubmit" scroll-to-error class="page-content">
<!-- 企业信息组件 -->
<EnterpriseInfoSection :enterprise-data="enterpriseData" :is-sign-mode="isSignMode"
@open-picker="showPopups.enterprise = true" />
@ -16,6 +16,7 @@
<EnforcementInfoSection v-if="!isNonEnforcement" :form-data="formData"
:default-person="enforcementPersons[0]" :additional-persons="additionalPersons"
:enterprise-number="enterpriseData.enterpriseNumber" :can-select-reason="canSelectReason"
:show-reason="showReason"
:can-edit-time="isSignMode"
@show-notice-picker="showPopups.notice = true" @open-person-picker="handleOpenPersonPicker"
@remove-person="handleRemovePerson" @show-category-picker="showPopups.category = true"
@ -26,6 +27,7 @@
<!-- 活动信息组件(非行政执法模式) -->
<NonEnforcementInfoSection v-else :form-data="formData" :default-person="enforcementPersons[0]"
:additional-persons="additionalPersons" :can-select-reason="canSelectReason"
:show-reason="showReason"
:can-edit-time="isSignMode"
@open-person-picker="handleOpenPersonPicker"
@remove-person="handleRemovePerson" @open-basis-picker="handleOpenBasisPicker"
@ -54,6 +56,7 @@ import { ref, reactive, computed, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { showConfirmDialog, showSuccessToast, showToast } from 'vant';
import { loadDict } from '@/util/dictUtil';
import { maskPhone } from '@/util/util';
import { saveEnfRegistration, submitEnfRegistration, addNonRegistration, getEnforcementRegistrationDetailById, getSystemConfig } from '@/api/enforcement/index';
import EnterpriseInfoSection from '@/components/enforcement/register/EnterpriseInfoSection.vue';
import EnforcementInfoSection from '@/components/enforcement/register/EnforcementInfoSection.vue';
@ -71,7 +74,12 @@ const isSignMode = ref(false);
// 扫码登记模式
const isScanMode = ref(false);
// 是否可以选择原因(补录和扫码登记模式不可选择,手动搜索企业可选择)
// 原因字段是否显示(仅扫码登记模式不显示)
const showReason = computed(() => {
return !isScanMode.value;
});
// 是否可以选择原因(仅手动搜索企业可选择,补录模式显示但不可选择)
const canSelectReason = computed(() => {
return !isSignMode.value && !isScanMode.value;
});
@ -156,13 +164,20 @@ const selectedPersonsList = computed(() => {
const list = [];
// 添加默认执法人员
if (enforcementPersons.value[0]) {
list.push({ id: enforcementPersons.value[0].id, name: enforcementPersons.value[0].name, userId: enforcementPersons.value[0].userId });
list.push(
{
id: enforcementPersons.value[0].id,
name: enforcementPersons.value[0].name,
userId: enforcementPersons.value[0].userId || '',
phone: maskPhone(enforcementPersons.value[0].phonenumber || ''),
lawCertificateNum: enforcementPersons.value[0].lawCertificateNum || ''
});
}
// 添加额外执法人员
additionalPersons.value.forEach(p => {
if (p.id || p.name) {
list.push({ id: p.id, name: p.name, userId: p.userId });
}
list.push({ id: p.id, name: p.name, userId: p.userId || '', lawCertificateNum: p.lawCertificateNum || '' });
}
});
return list;
});
@ -441,29 +456,41 @@ const getCurrentDateTime = () => {
};
// 保存
const formRef = ref();
const handleSave = () => {
showConfirmDialog({
title: '确认保存',
message: '确认保存吗?',
width: '80%',
}).then(() => {
const payload = buildSubmitPayload();
saveEnfRegistration(payload, (res) => {
if (res.code === 200 || res.code === 0) {
showSuccessToast('保存成功');
sessionStorage.removeItem('enterpriseScanData');
sessionStorage.removeItem('outOfCityEnterprise');
sessionStorage.removeItem('scanReason');
router.replace('/enforcement/enforcementList');
} else {
showToast(res.msg || '保存失败');
}
}, (err) => {
console.error('保存接口失败', err);
showToast('保存失败');
// 验证执法人员数量
const totalPersons = enforcementPersons.value.length + additionalPersons.value.length;
if (totalPersons < 2) {
showToast('人员至少需要2人');
return;
}
// 验证表单必填项
formRef.value?.validate().then(() => {
showConfirmDialog({
title: '确认保存',
message: '确认保存吗?',
width: '80%',
}).then(() => {
const payload = buildSubmitPayload();
saveEnfRegistration(payload, (res) => {
if (res.code === 200 || res.code === 0) {
showSuccessToast('保存成功');
sessionStorage.removeItem('enterpriseScanData');
sessionStorage.removeItem('outOfCityEnterprise');
sessionStorage.removeItem('scanReason');
router.replace('/enforcement/enforcementList');
} else {
showToast(res.msg || '保存失败');
}
}, (err) => {
console.error('保存接口失败', err);
showToast('保存失败');
});
}).catch(() => {
// 用户取消
});
}).catch(() => {
// 用户取消
showToast('请完善必填信息');
});
};
@ -710,8 +737,11 @@ onMounted(() => {
let useCommon = JSON.parse(useCommonStr);;
const name = useCommon.userName || '';
const phonenumber = useCommon.phonenumber || '';
const lawCertificateNum = useCommon.lawCertificateNum || '';
if (name || phonenumber) {
enforcementPersons.value = [{ name, phonenumber, userId: useCommon.userId || '' }];
enforcementPersons.value = [
{ name, phonenumber: maskPhone(phonenumber || ''), userId:useCommon.userId || '',lawCertificateNum }
];
}
formData.enforcementUnit = useCommon.bureauUnitName || '';

26
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enterpriseScanPreview.vue

@ -23,9 +23,9 @@
<div class="info-value">{{ enterpriseData.enterpriseName }}</div>
</div>
<template v-if="!isCollapsed">
<div class="info-item">
<div class="info-label">统一社会信用代码</div>
<div class="info-value">{{ enterpriseData.enterpriseNumber }}</div>
<div class="info-item enterpriseData-number">
<div class="info-label">统一社会<br>信用代码</div>
<div class="info-value ">{{ enterpriseData.enterpriseNumber }}</div>
</div>
<div class="info-item">
<div class="info-label">法定代表人</div>
@ -33,11 +33,11 @@
</div>
<div class="info-item">
<div class="info-label">企业类型</div>
<div class="info-value">{{ enterpriseData.enterpriseType }}</div>
<div class="info-value">{{ enterpriseData.companyOrgType }}</div>
</div>
<div class="info-item">
<div class="info-label">注册资本</div>
<div class="info-value">{{ enterpriseData.registeredCapital }}</div>
<div class="info-value">{{ formatCapital(enterpriseData.registeredCapital) }}(万元人民币)</div>
</div>
<div class="info-item">
<div class="info-label">成立日期</div>
@ -45,7 +45,7 @@
</div>
<div class="info-item">
<div class="info-label">经营期限</div>
<div class="info-value">{{ enterpriseData.operatingTerm }}</div>
<div class="info-value">{{ enterpriseData.operatingTerm }} 至 {{ formatDate(enterpriseData.operatingTermEnd) }}</div>
</div>
<div class="info-item">
<div class="info-label">注册地址</div>
@ -153,6 +153,14 @@ const hasFetchedCaseData = ref(false);
// ========== 方法 ==========
// 注册资本保留两位小数
const formatCapital = (val) => {
if (val === null || val === undefined || val === '') return '';
const num = Number(val);
if (isNaN(num)) return val;
return num.toFixed(2);
};
const toggleCollapse = () => {
isCollapsed.value = !isCollapsed.value;
};
@ -414,6 +422,12 @@ const toSign = () => {
word-break: break-all;
}
.enterpriseData-number {
display: flex;
align-items: center;
justify-content: flex-start;
}
.address-value,
.scope-value {
display: flex;

1
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/home/enforcementHome.vue

@ -233,6 +233,7 @@ onMounted(() => {
useCommon.SET_BUREAU_UNIT_ID(success.data.bureauUnitId);
useCommon.SET_BUREAU_UNIT_NAME(success.data.bureauUnitName || "");
useCommon.SET_HAS_LAW(success.data.lawOfficer || "");
useCommon.SET_LAW_CERTIFICATE_NUM(success.data.lawCertificateNum || "");
isLoading.value = false;
fetchNoticeList();
fetchBannerList();

1
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/loginByPassword.vue

@ -135,6 +135,7 @@ const doLogin = (secretName, secretKey) => {
useCommon.SET_BUREAU_UNIT_ID(response.data.bureauUnitId);
useCommon.SET_BUREAU_UNIT_NAME(response.data.bureauUnitName || "");
useCommon.SET_HAS_LAW(response.data.lawOfficer || "");
useCommon.SET_LAW_CERTIFICATE_NUM(response.data.lawCertificateNum || "");
useCommon.SET_IS_FIRST_LOAD(false);
console.log("bureauUnitName", response.data.bureauUnitName);
console.log("enforcement login success", useCommon.userId);

274
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_detail.vue

@ -1,76 +1,60 @@
<template>
<div class="notice-detail-page app_content">
<!-- 顶部导航 -->
<!-- <van-nav-bar
title="预告详情"
left-arrow
@click-left="onBack"
/> -->
<div class="content">
<div class="notice-detail-page">
<!-- 内容区域 -->
<div class="content-area">
<div v-if="loading" class="loading-wrap">
<van-loading size="20" />&nbsp;加载中...
</div>
<template v-else-if="detail">
<!-- 基本信息 -->
<div class="form-card">
<div class="card-header">
<div class="status-tag" :class="'status-' + detail.status">
{{ getStatusText(detail.status) }}
</div>
<div class="card-date">{{ formatDate(detail.createTime) }}</div>
</div>
<div class="notice-title">{{ detail.enforceContent || '暂无执法事项' }}</div>
<!-- 基本信息卡片 -->
<div class="info-card">
<div class="info-row">
<div class="label">执法日期</div>
<div class="value">{{ detail.enforceDate || '-' }} {{ getTimeText(detail.enforceTime) }}</div>
<span class="info-label">企业名称</span>
<span class="info-value">{{ detail.enterpriseName || '-' }}</span>
</div>
<div class="info-row">
<div class="label">执法单位</div>
<div class="value">{{ detail.bureauDeptName || '-' }}</div>
<span class="info-label">企业联系人</span>
<span class="info-value">{{ detail.contactPerson || '-' }}</span>
</div>
<div class="info-row">
<div class="label">企业名称</div>
<div class="value">{{ detail.enterpriseName || '-' }}</div>
<span class="info-label">联系电话</span>
<span class="info-value">{{ detail.contactPhone || '-' }}</span>
</div>
<div class="info-row">
<div class="label">企业联系人</div>
<div class="value">{{ detail.contactPerson || '-' }}</div>
<div class="info-row">
<span class="info-label">执法日期</span>
<span class="info-value">{{ formatDate(detail.enforceDate) || '-' }} {{ getTimeText(detail.enforceTime) }}</span>
</div>
<div class="info-row">
<div class="label">联系电话</div>
<div class="value">{{ detail.contactPhone || '-' }}</div>
<div class="info-row">
<span class="info-label">执法事项</span>
<span class="info-value detail_content">{{ detail.enforceContent || '-' }}</span>
</div>
</div>
<!-- 执法人员 -->
<div class="form-card">
<div class="section-title">执法人员</div>
<div v-if="personList.length" class="person-list">
<div v-for="(person, index) in personList" :key="index" class="person-line">
<span class="person-name">{{ person.name }}</span>
<span class="person-phone">{{ person.phone }}</span>
<div class="info-row">
<span class="info-label">执法要求</span>
<span class="info-value detail_content">{{ detail.enforceRequirement || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">执法人员</span>
<div v-if="personList.length" class="enforcer-list">
<div v-for="(person, index) in personList" :key="index" class="enforcer-item">
<span class="enforcer-name">{{ person.name }}</span>
<span class="enforcer-phone">{{ person.phone }}</span>
</div>
</div>
<div v-else class="empty-text">暂无执法人员</div>
</div>
<!-- 执法事项 -->
<div class="form-card">
<div class="section-title">执法事项</div>
<div class="content-text">{{ detail.enforceContent || '-' }}</div>
</div>
<!-- 执法要求 -->
<div class="form-card">
<div class="section-title">执法要求</div>
<div class="content-text">{{ detail.enforceRequirement || '-' }}</div>
</div>
<!-- <div class="info-row">
<span class="info-label">登记</span>
<span class="info-value">{{ detail.enforceRegister || '-' }}</span>
</div> -->
</div>
</template>
<van-empty v-else description="未查询到预告信息" />
</div>
<!-- 底部反馈按钮 -->
<div class="footer-bar" v-if="detail">
<van-button class="feedback-btn" type="primary" block @click="goFeedback">反馈</van-button>
</div>
</div>
</template>
@ -97,11 +81,22 @@ const getTimeText = (time) => {
const formatDate = (dateStr) => {
if (!dateStr) return '';
return String(dateStr).substring(0, 16).replace('T', ' ');
return String(dateStr).substring(0, 10).replace('T', ' ');
};
const onBack = () => { router.back(); };
const goFeedback = () => {
const id = route.query.id;
router.push({
path: '/enforcement/notice/message',
query: {
id: id,
readonly: 0
}
});
};
onMounted(() => {
const id = route.query.id;
if (!id) {
@ -134,28 +129,13 @@ onMounted(() => {
flex-direction: column;
height: 100%;
background: #fbfdff;
overflow: hidden;
}
:deep(.van-nav-bar) {
background: #347bc3;
flex-shrink: 0;
.van-nav-bar__title {
color: #fff;
font-size: 18px;
font-weight: 600;
}
.van-icon {
color: #fff;
}
}
.content {
.content-area {
flex: 1;
overflow-y: auto;
padding: 12px;
padding: 0.27rem;
padding-bottom: 1.8rem;
}
.loading-wrap {
@ -167,127 +147,101 @@ onMounted(() => {
font-size: 14px;
}
.form-card {
/* ===== 信息卡片 ===== */
.info-card {
background: #fff;
border-radius: 14px;
padding: 16px;
margin-bottom: 12px;
box-shadow: 0 4px 14px rgba(44, 116, 190, 0.08);
border-radius: 4px;
padding: 0.3rem 0.35rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.card-header {
.card-title {
font-size: 0.4rem;
font-weight: bold;
color: #333;
margin-bottom: 0.25rem;
padding-bottom: 0.15rem;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.status-tag {
font-size: 12px;
font-weight: 500;
padding: 3px 10px;
border-radius: 10px;
}
.status-0 {
background: #f0f0f0;
color: #666;
}
.status-1 {
background: #e6f7ff;
color: #1890ff;
}
.status-2 {
background: #fff2e8;
color: #fa8c16;
}
.status-3 {
background: #f6ffed;
color: #52c41a;
}
.card-date {
font-size: 12px;
color: #999;
}
.notice-title {
font-size: 16px;
font-weight: 700;
color: #111;
line-height: 1.5;
margin-bottom: 14px;
align-items: baseline;
}
.info-row {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
font-size: 14px;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
font-size: 0.32rem;
line-height: 1.8;
padding: 6px 0px;
.info-label {
color: #333;
margin-right: 18px;
font-size: 14px;
width: 70px;
flex-shrink: 0;
}
.info-value {
color: #999;
flex: 1;
word-break: break-all;
font-size: 14px;
}
}
.label {
width: 80px;
flex-shrink: 0;
color: #333;
font-weight: 500;
}
.value {
flex: 1;
color: #8a8a8a;
.content-text {
color: #555;
line-height: 1.6;
word-break: break-all;
white-space: pre-wrap;
}
.section-title {
font-size: 15px;
font-weight: 600;
color: #333;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #f0f0f0;
}
.person-list {
/* ===== 执法人员 ===== */
.enforcer-list {
display: flex;
flex-direction: column;
gap: 8px;
padding: 6px 0px;
}
.person-line {
.enforcer-item {
display: flex;
align-items: center;
font-size: 14px;
color: #666;
gap: 12px;
.person-name {
.enforcer-name {
font-weight: 500;
color: #999;
}
.person-phone {
.enforcer-phone {
color: #999;
}
}
.detail_content{
height: 100px;
}
.empty-text {
font-size: 14px;
color: #ccc;
/* ===== 底部反馈按钮 ===== */
.footer-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 0.2rem 0.4rem;
padding-bottom: calc(0.2rem + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
z-index: 10;
}
.content-text {
font-size: 14px;
color: #555;
line-height: 1.6;
word-break: break-all;
white-space: pre-wrap;
.feedback-btn {
background: #2b7de9;
border: none;
border-radius: 0.3rem;
font-size: 0.34rem;
height: 0.88rem;
}
</style>

44
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_edit.vue

@ -59,10 +59,10 @@
:key="index"
class="person-line"
>
<span class="person-name">{{ person.name }}</span>
<span class="person-name">{{ person.name }} </span>
<span class="person-phone">{{ person.phone }}</span>
<van-icon
v-if="personList.length > 1"
v-if="personList.length > 1 && person.id !== useCommon.userId"
name="close"
class="person-remove"
@click="removePerson(index)"
@ -92,6 +92,7 @@
v-model="form.contactPerson"
label="企业联系人"
placeholder="请输入联系人"
readonly
/>
<!-- 企业联系电话 -->
@ -99,6 +100,9 @@
v-model="form.contactPhone"
label="企业联系电话"
placeholder="请输入联系电话"
type="tel"
maxlength="11"
:rules="[{ pattern: /^\d{11}$/, message: '请输入11位手机号码' }]"
/>
<!-- 执法事项 -->
@ -232,7 +236,7 @@
>
<div class="person-item-name">{{ user.fullname || user.userName }}</div>
<div class="person-item-meta">
<span v-if="user.mobileNumber">{{ user.mobileNumber }}</span>
<span>{{ user.lawCertificateNum || user.phonenumber || user.mobileNumber }}</span>
<span v-if="user.loginName" class="person-item-login">@{{ user.loginName }}</span>
</div>
</div>
@ -287,7 +291,7 @@ import { useRouter, useRoute } from 'vue-router';
import { showToast, showSuccessToast, showConfirmDialog } from 'vant';
import { addNotice, editNotice, getNoticeDetail } from '@/api/enforcement/notice';
import { getPlanList, searchUnionByEnterpriseName, searchBureauUnitUsers, getEnterpriseContactInfo } from '@/api/enforcement/plan';
import { maskPhone } from '@/util/util';
const router = useRouter();
const route = useRoute();
const { useCommon } = $globalStore;
@ -345,14 +349,14 @@ const datePickerValue = ref([
]);
const timeColumns = [
{ text: '上午', value: 1 },
{ text: '下午', value: 2 },
{ text: '其他', value: 3 },
{ text: '上午(9:00-12:00)', value: 1 },
{ text: '下午(14:00-18:00)', value: 2 },
{ text: '其他(18:00-21:00)', value: 3 },
];
// 日期+时段展示
const enforceTimeDisplay = computed(() => {
const timeText = { 1: '上午', 2: '下午', 3: '其他' };
const timeText = { 1: '上午(9:00-12:00)', 2: '下午(14:00-18:00)', 3: '其他(18:00-21:00)' };
return timeText[form.value.enforceTime] || '';
});
@ -402,7 +406,7 @@ onMounted(() => {
const bindCurrentUserAsDefaultPerson = () => {
const name = useCommon.nickName || useCommon.userName || '';
const phone = useCommon.phonenumber || '';
const phone = useCommon.lawCertificateNum || maskPhone(useCommon.phonenumber) || '';
const id = useCommon.userId || '';
if (!name && !id) return;
personList.value = [{ id, name, phone, code: '' }];
@ -534,7 +538,13 @@ const triggerPersonSearch = (keyword) => {
if (seq !== personSearchSeq) return;
personSearching.value = false;
if (res && res.code === 200 && Array.isArray(res.rows)) {
personSearchResult.value = res.rows;
let rows = res.rows;
// 过滤掉已选择的执法人员
if (personList.value.length > 0) {
const selectedIds = personList.value.map(p => String(p.id || '')).filter(Boolean);
rows = rows.filter(item => !selectedIds.includes(String(item.userId || '')));
}
personSearchResult.value = rows;
} else {
personSearchResult.value = [];
}
@ -552,17 +562,23 @@ const onSelectPerson = (user) => {
const exists = personList.value.some(p => String(p.id || '') === uid);
if (exists) { showToast('该人员已添加'); return; }
if (personList.value.length >= maxPersonNum) { showToast(`最多只能添加 ${maxPersonNum} 名执法人员`); return; }
personList.value.push({ id: uid, name: user.fullname || user.userName || '', phone: user.mobileNumber || '', code: '' });
personList.value.push({ id: uid, name: user.fullname || user.userName || '', phone: user.lawCertificateNum || maskPhone(user.mobileNumber) || '', code: '' });
syncPersonData();
showPersonPicker.value = false;
};
const removePerson = (index) => {
const person = personList.value[index];
if (person && person.id === useCommon.userId) {
showToast('本人不可移除');
return;
}
personList.value.splice(index, 1);
syncPersonData();
};
const syncPersonData = () => {
console.log(personList.value);
form.value.enforceUserNames = personList.value.map(p => p.name).join(',');
form.value.enforceUserIds = personList.value.map(p => p.id || '').join(',');
form.value.enforceUserTels = personList.value.map(p => p.phone || '').join(',');
@ -624,6 +640,12 @@ const validate = (isDraft) => {
if (!form.value.enterpriseName) { showToast('请输入企业名称'); return false; }
if (personList.value.length === 0) { showToast('请添加执法人员'); return false; }
if (personList.value.length < 2) { showToast('执法人员不得少于2人'); return false; }
// 校验企业联系电话
const phone = form.value.contactPhone;
if (phone && !/^\d{11}$/.test(phone)) {
showToast('请输入11位手机号码');
return false;
}
return true;
};

6
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/notice/cp_notice_tab_content.vue

@ -14,12 +14,12 @@
class="notice-card"
@click="$emit('detail', item)"
>
<div class="card-header">
<!-- <div class="card-header">
<div class="status-tag" :class="'status-' + item.status">
{{ getStatusText(item.status) }}
</div>
<div class="card-date">{{ formatTime(item.createTime) }}</div>
</div>
</div> -->
<div class="notice-title">{{ item.enforceContent || '暂无执法事项' }}</div>
@ -116,7 +116,7 @@ const getStatusText = (status) => {
};
const getTimeText = (time) => {
const map = { 1: '上午', 2: '下午', 3: '其他' };
const map = { 1: '上午(9:00-12:00)', 2: '下午(14:00-18:00)', 3: '其他(18:00-21:00)' };
return map[time] || '';
};

18
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_edit.vue

@ -49,9 +49,9 @@
<van-field name="planTime" label="执行时段" required :disabled="isPrefillMode">
<template #input>
<van-radio-group v-model="form.planTime" direction="horizontal" :disabled="isPrefillMode">
<van-radio :name="1">上午</van-radio>
<van-radio :name="2">下午</van-radio>
<van-radio :name="3">其他</van-radio>
<van-radio :name="1">上午(9:00-12:00)</van-radio>
<van-radio :name="2">下午(14:00-18:00)</van-radio>
<van-radio :name="3">其他(18:00-21:00)</van-radio>
</van-radio-group>
</template>
</van-field>
@ -101,7 +101,7 @@
<span class="person-name">{{ person.name }}</span>
<span class="person-phone">{{ person.phone }}</span>
<van-icon
v-if="personList.length > 1 && person.id !== useCommon.userId"
v-if="personList.length > 1 && person.phone !== useCommon.phonenumber"
name="close"
class="person-remove"
@click="removePerson(index)"
@ -194,7 +194,7 @@
>
<div class="person-item-name">{{ user.fullname || user.userName }}</div>
<div class="person-item-meta">
<span v-if="user.mobileNumber">{{ user.mobileNumber }}</span>
<span>{{ user.lawCertificateNum || user.phonenumber || user.mobileNumber }}</span>
<span v-if="user.loginName" class="person-item-login">@{{ user.loginName }}</span>
</div>
</div>
@ -252,7 +252,7 @@
import { useRouter, useRoute } from 'vue-router';
import { showToast, showSuccessToast, showConfirmDialog } from 'vant';
import { addPlan, editPlan, getPlanDetail, getSubmitDeadline, getManualMatchDays, getMaxInnerUnitAcPersonNum, searchUnionByEnterpriseName, searchBureauUnitUsers } from '@/api/enforcement/plan';
import { maskPhone } from '@/util/util';
const router = useRouter();
const route = useRoute();
const {useCommon} = $globalStore;
@ -265,7 +265,7 @@ const submitting = ref(false);
const showDatePicker = ref(false);
// 下阶段计划提交最晚时间(每月几号前需提交下阶段计划)
const submitDeadline = ref(26);
const submitDeadline = ref(25);
// 手工匹配距计划开始天数
const manualMatchDays = ref(3);
@ -395,7 +395,7 @@ onMounted(() => {
// 默认绑定当前登录用户为执法人员
const bindCurrentUserAsDefaultPerson = () => {
const name = useCommon.nickName || useCommon.userName || '';
const phone = useCommon.phonenumber || '';
const phone = useCommon.lawCertificateNum || maskPhone(useCommon.phonenumber) || '';
const id = useCommon.userId || '';
if (!name && !id) return;
personList.value = [{ id, name, phone, code: '' }];
@ -642,7 +642,7 @@ const onSelectPerson = (user) => {
personList.value.push({
id: uid,
name: user.fullname || user.userName || '',
phone: user.mobileNumber || '',
phone: user.lawCertificateNum || maskPhone(user.mobileNumber) || '',
code: '',
});
syncPersonData();

2
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/my/plan/cp_plan_mine.vue

@ -214,7 +214,7 @@ const getStatusText = (status) => {
// 时段文本
const getPlanTimeText = (time) => {
const map = { 1: '上午', 2: '下午', 3: '其他' };
const map = { 1: '上午(9:00-12:00)', 2: '下午(14:00-18:00)', 3: '其他(18:00-21:00)' };
return map[time] || '';
};

15
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/nos/nosAdd.vue

@ -75,7 +75,7 @@ import RegisterPopups from '@/components/enforcement/nos/RegisterPopups.vue';
import AttachmentTaskSource from '@/components/enforcement/nos/AttachmentTaskSource.vue';
import { nosAddApi, nosTaskSourceListApi } from '@/api/nos/index';
import { toFullFileUrl, toRelativeFilePath } from '@/util/fileUrl';
import { maskPhone } from '@/util/util';
const router = useRouter();
const route = useRoute();
@ -110,9 +110,9 @@ const formData = reactive({
const lawEnforcer = ref([
{
lawEnforcerName: $globalStore.useCommon.userName,
lawEnforcerPhone: $globalStore.useCommon.phonenumber,
lawEnforcerPhone: maskPhone($globalStore.useCommon.phonenumber),
lawEnforcerId: $globalStore.useCommon.userId,
lawEnforcerIdCard: null
lawEnforcerIdCard: $globalStore.useCommon.lawCertificateNum,
}
]);
@ -390,14 +390,16 @@ const handleSelectPerson = (person) => {
lawEnforcerName: person.lawEnforcerName,
lawEnforcerId: person.lawEnforcerId,
lawEnforcerPhone: person.lawEnforcerPhone,
lawEnforcerIdCard: person.lawEnforcerIdCard
lawEnforcerIdCard: person.lawEnforcerIdCard,
lawCertificateNum: person.lawCertificateNum || ''
});
} else {
additionalLawEnforcers.value[currentEditIndex.value] = {
lawEnforcerName: person.lawEnforcerName,
lawEnforcerId: person.lawEnforcerId,
lawEnforcerPhone: person.lawEnforcerPhone,
lawEnforcerIdCard: person.lawEnforcerIdCard
lawEnforcerIdCard: person.lawEnforcerIdCard,
lawCertificateNum: person.lawCertificateNum || ''
};
}
showPopups.person = false;
@ -497,7 +499,8 @@ const buildLawEnforcerList = () => {
lawEnforcerId: item.lawEnforcerId,
lawEnforcerName: item.lawEnforcerName,
lawEnforcerPhone: item.lawEnforcerPhone,
lawEnforcerIdCard: item.lawEnforcerIdCard
lawEnforcerIdCard: item.lawEnforcerIdCard,
lawCertificateNum: item.lawCertificateNum || ''
}));
return list;
};

2
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/nos/nosDetail.vue

@ -90,7 +90,7 @@ const applyDetailData = (data) => {
})),
taskSource: data.taskSourceName || '',
enforcementUnit: data.lawEnforcementAgency || '',
enforcementPerson: (data.lawEnforcer || []).map((e) => `${e.lawEnforcerName || ''} ${e.lawEnforcerPhone || ''}`.trim()).filter(Boolean),
enforcementPerson: (data.lawEnforcer || []).map((e) => `${e.lawEnforcerName || ''} ${e.lawEnforcerIdCard || e.lawEnforcerPhone || ''}`.trim()).filter(Boolean),
enforcementPersonNames: (data.lawEnforcer || []).map((e) => e.lawEnforcerName || '').filter(Boolean),
enterpriseName: data.enterpriseName || '',
enterpriseNumber: data.usciCode || '',

2
zdxt-web-client/zdxt-efcode-enterprise-app/src/api/enterprise/planNotice.js

@ -6,7 +6,7 @@ let enterpriseAppBaseUrl = "/app-ent";
export const getPlanNoticeList = (params, success, error) => _get(enterpriseAppBaseUrl +"/enterprise/lawNotice/myList",params,success,error);
//执法预告详情
export const getPlanNoticeDetail = (params, success, error) => _get(enterpriseAppBaseUrl +"/planNotice/" + params.id,{},success,error);
export const getPlanNoticeDetail = (params, success, error) => _get(enterpriseAppBaseUrl +"/enterprise/lawNotice/noticeDetails",params,success,error);
//执法预告留言列表
export const getPlanNoticeMessageList = (params, success, error) => _get(enterpriseAppBaseUrl +"/planNotice/message/list",params,success,error);

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

@ -123,6 +123,14 @@ const routes = [
component: () =>
import("@/views/enterprise/plan/planNoticeList.vue"),
},
// 执法预告详情
{
path: "/enterprise/planNoticeDetail",
name: "planNoticeDetail",
meta: { title: "预告详情" },
component: () =>
import("@/views/enterprise/plan/planNoticeDetail.vue"),
},
// 执法预告留言
{
path: "/enterprise/planNoticeMessage",

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

@ -28,11 +28,9 @@
<div class="info-row">
<span class="info-label">执法人员</span>
<div class="info-value enforcer-value">
<div>
{{ detail.lawEnforcerDisplay }}
</div>
<div v-for="(item, index) in detail.lawEnforcer2List" :key="index">
{{ item }}
<div v-for="(person, index) in getEnforcers(detail)" :key="index" class="enforcer-item">
<span class="enforcer-name">{{ person.name }}</span>
<span class="enforcer-phone">{{ person.phone }}</span>
</div>
</div>
</div>
@ -282,19 +280,33 @@ const pickFirst = (obj, keys, fallback = '') => {
return fallback;
};
// 解析执法人员
const parseEnforcers = (data) => {
// 解析执法人员(支持逗号分隔的多人)
const getEnforcers = (data) => {
const list = [];
if (data.lawEnforcer) list.push({ name: data.lawEnforcer, phone: data.lawEnforcerId || '' });
if (data.lawEnforcerTwo) list.push({ name: data.lawEnforcerTwo, phone: data.lawEnforcerIdTwo || '' });
const raw = data.enforcers || data.enforcerList || [];
// 第一名执法人员
if (data.lawEnforcer) {
list.push({ name: data.lawEnforcer, phone: data.lawEnforcerId || '' });
}
// 第二名及之后:lawEnforcerTwo 和 lawEnforcerIdTwo 均为逗号分隔字符串
if (data.lawEnforcerTwo) {
const names = String(data.lawEnforcerTwo).split(',');
const phones = data.lawEnforcerIdTwo ? String(data.lawEnforcerIdTwo).split(',') : [];
names.forEach((name, i) => {
const trimmed = name.trim();
if (trimmed) list.push({ name: trimmed, phone: phones[i] ? phones[i].trim() : '' });
});
}
// 数组形式(兼容其他字段名)
const raw = data.enforcers || data.enforcerList || data.lawEnforcer2List || [];
if (Array.isArray(raw) && raw.length) {
raw.forEach(p => {
if (typeof p === 'string') list.push({ name: p, phone: '' });
else list.push({
name: p.name || p.userName || p.realName || '',
phone: p.phone || p.mobile || p.tel || ''
});
if (typeof p === 'string') {
list.push({ name: p, phone: '' });
} else {
const name = p.name || p.userName || p.realName || '';
const phone = p.phone || p.mobile || p.tel || '';
if (name) list.push({ name, phone });
}
});
}
return list.filter(p => p.name);
@ -526,6 +538,24 @@ const onSubmit = () => {
.enforcer-value {
display: flex;
flex-direction: column;
gap: 4px;
}
.enforcer-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
line-height: 1.6;
.enforcer-name {
color: #666;
font-weight: 500;
}
.enforcer-phone {
color: #999;
}
}
.result-row {

24
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/enforcement/enforcementRegistrationList.vue

@ -26,9 +26,7 @@
<div class="card-row">
<span class="card-label">执法人员:</span>
<span class="enforcer-block">
<!-- <div v-for="(enforcer, idx) in getEnforcers(item)" :key="idx">{{ enforcer }}</div> -->
<div>{{ item.lawEnforcerDisplay || '-' }}</div>
<div v-for="value in item.lawEnforcer2List" :key="value">{{ value || '-' }}</div>
<div v-for="(enforcer, idx) in getEnforcers(item)" :key="idx">{{ enforcer }}</div>
</span>
</div>
<div class="card-row">
@ -85,6 +83,26 @@ const formatDate = (dateStr) => {
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
};
// ========== 执法人员展示(姓名 + 空格 + 手机号,支持逗号分隔的多人)==========
const getEnforcers = (item) => {
const list = [];
// 第一名执法人员:lawEnforcer + lawEnforcerId
if (item.lawEnforcer) {
list.push(`${item.lawEnforcer} ${item.lawEnforcerId || ''}`);
}
// 第二名及之后:lawEnforcerTwo 和 lawEnforcerIdTwo 均为逗号分隔字符串
if (item.lawEnforcerTwo) {
const names = String(item.lawEnforcerTwo).split(',');
const phones = item.lawEnforcerIdTwo ? String(item.lawEnforcerIdTwo).split(',') : [];
names.forEach((name, i) => {
const trimmed = name.trim();
if (trimmed) list.push(`${trimmed} ${phones[i] ? phones[i].trim() : ''}`);
});
}
return list.length ? list : ['-'];
};
// ========== 加载数据 ==========
const fetchList = () => {
const params = {

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

@ -330,9 +330,9 @@ const onClickLeft = () => {
onMounted(() => {
// 设置深i企标题
w6s.ready(() => {
w6s.header.setTitle('消息中心');
});
// w6s.ready(() => {
// w6s.header.setTitle('消息中心');
// });
// 优先从sessionStorage获取返回时要显示的tab页(用于页面返回时定位)
const returnTab = sessionStorage.getItem('messageReturnTab');
if (returnTab === '1') {

5
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/my/myPage.vue

@ -5,7 +5,7 @@
<div class="user-info">
<div class="avatar-wrapper">
<!-- <img class="avatar" src="https://picsum.photos/120/120?random=avatar" alt="avatar" /> -->
<div>企</div>
<div class="avatar">企</div>
</div>
<div class="user-name">{{ useCommon.enterpriseName}}</div>
<div class="user-phone">电话:{{ phoneNumber }}</div>
@ -98,6 +98,9 @@ const toSettings = () => {
line-height: 80px;
color: #fff;
background: #1989fa;
.avatar{
font-size:38px;
}
}
.user-name {

216
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/plan/planNoticeDetail.vue

@ -0,0 +1,216 @@
<template>
<div class="notice-detail-page">
<!-- 内容区域 -->
<div class="content-area">
<div v-if="loading" class="loading-wrap">
<van-loading size="20" />&nbsp;加载中...
</div>
<template v-else-if="detail">
<!-- 基本信息卡片 -->
<div class="info-card">
<div class="info-row">
<span class="info-label">企业名称</span>
<span class="info-value">{{ detail.enterpriseName || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">企业联系人</span>
<span class="info-value">{{ detail.contactPerson || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">联系电话</span>
<span class="info-value">{{ detail.contactPhone || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">执法日期</span>
<span class="info-value">{{ formatDate(detail.enforceDate) || '-' }} {{ getTimeText(detail.enforceTime) }}</span>
</div>
<div class="info-row">
<span class="info-label">执法事项</span>
<span class="info-value detail_content">{{ detail.enforceContent || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">执法要求</span>
<span class="info-value detail_content">{{ detail.enforceRequirement || '-' }}</span>
</div>
<div class="info-row">
<span class="info-label">执法人员</span>
<div v-if="personList.length" class="enforcer-list">
<div v-for="(person, index) in personList" :key="index" class="enforcer-item">
<span class="enforcer-name">{{ person.name }}</span>
<span class="enforcer-phone">{{ person.phone }}</span>
</div>
</div>
<span v-else class="info-value">-</span>
</div>
</div>
</template>
<van-empty v-else description="未查询到预告信息" />
</div>
<!-- 底部反馈按钮 -->
<div class="footer-bar" v-if="detail">
<van-button class="feedback-btn" type="primary" block @click="goFeedback">反馈</van-button>
</div>
</div>
</template>
<script setup name="planNoticeDetail">
import { useRouter, useRoute } from 'vue-router';
import { getPlanNoticeDetail } from '@/api/enterprise/planNotice';
const router = useRouter();
const route = useRoute();
const loading = ref(true);
const detail = ref(null);
const personList = ref([]);
const getTimeText = (time) => {
const map = { 1: '上午', 2: '下午', 3: '其他' };
return map[time] || '';
};
const formatDate = (dateStr) => {
if (!dateStr) return '';
return String(dateStr).substring(0, 10).replace('T', ' ');
};
const goFeedback = () => {
const id = route.query.id;
router.push({
path: '/enterprise/enforcementChat',
query: { id }
});
};
onMounted(() => {
const id = route.query.id;
if (!id) {
loading.value = false;
return;
}
getPlanNoticeDetail({ id }, (res) => {
loading.value = false;
if (res.code === 200 && res.data) {
detail.value = res.data;
// 解析执法人员
if (res.data.enforceUserNames) {
const names = res.data.enforceUserNames.split(',');
const tels = res.data.enforceUserTels ? res.data.enforceUserTels.split(',') : [];
personList.value = names.map((name, i) => ({
name,
phone: i < tels.length ? tels[i] : '',
}));
}
}
}, () => {
loading.value = false;
});
});
</script>
<style lang="less" scoped>
.notice-detail-page {
display: flex;
flex-direction: column;
height: 100%;
background: #fbfdff;
}
.content-area {
flex: 1;
overflow-y: auto;
padding: 0.27rem;
padding-bottom: 1.8rem;
}
.loading-wrap {
display: flex;
align-items: center;
justify-content: center;
padding: 40px 0;
color: #999;
font-size: 14px;
}
/* ===== 信息卡片 ===== */
.info-card {
background: #fff;
border-radius: 4px;
padding: 0.3rem 0.35rem;
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
.info-row {
display: flex;
align-items: flex-start;
font-size: 0.32rem;
line-height: 1.8;
padding: 6px 0px;
.info-label {
color: #333;
margin-right: 18px;
font-size: 14px;
width: 70px;
flex-shrink: 0;
}
.info-value {
color: #999;
flex: 1;
word-break: break-all;
font-size: 14px;
}
}
/* ===== 执法人员 ===== */
.enforcer-list {
display: flex;
flex-direction: column;
gap: 8px;
padding: 6px 0px;
}
.enforcer-item {
display: flex;
align-items: center;
font-size: 14px;
color: #666;
gap: 12px;
.enforcer-name {
font-weight: 500;
color: #999;
}
.enforcer-phone {
color: #999;
}
}
.detail_content {
min-height: 100px;
}
/* ===== 底部反馈按钮 ===== */
.footer-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 0.2rem 0.4rem;
padding-bottom: calc(0.2rem + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
z-index: 10;
}
.feedback-btn {
background: #2b7de9;
border: none;
border-radius: 0.3rem;
font-size: 0.34rem;
height: 0.88rem;
}
</style>

15
zdxt-web-client/zdxt-efcode-enterprise-app/src/views/enterprise/plan/planNoticeList.vue

@ -32,18 +32,18 @@
class="notice-card"
v-for="item in list"
:key="item.id"
@click="toDetail(item)"
>
<div class="card-row time-row">
<span class="label">执法时间:</span>
<span class="value">{{ item.enforceDate }}</span>
</div>
<!-- <div class="card-title">{{ item.checkItemText }}</div> -->
<div class="card-row">
<span class="label">执法单位:</span>
<span class="value">{{ item.bureauDeptName }}</span>
</div>
<div class="card-action">
<span class="feedback-btn" :class="{ 'has-dot': item.hasFeedback }" @click="onFeedback(item)">
<span class="feedback-btn" :class="{ 'has-dot': item.hasFeedback }" @click.stop="onFeedback(item)">
<van-icon name="chat-o" size="14" />
反馈
</span>
@ -166,6 +166,16 @@ const onFeedback = (item) => {
}
});
};
// ========== 跳转详情 ==========
const toDetail = (item) => {
router.push({
path: '/enterprise/planNoticeDetail',
query: {
id: item.id
}
});
};
</script>
<style lang="less" scoped>
@ -210,6 +220,7 @@ const onFeedback = (item) => {
margin-bottom: 0.27rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
position: relative;
cursor: pointer;
}
.card-row {

5
zdxt-web-server/zdxt-admin-web-server/src/main/resources/businessdatasyn/enterprise_pub_qrcode.json

@ -13,7 +13,7 @@
"area_name", "area_id", "street_name", "street_id",
"matching_status", "matching_message", "download_status",
"dept_name", "dept_id", "user_name", "user_id",
"create_time", "create_by", "qr_code_path", "last_qr_code_time",
"create_time", "qr_code_path", "last_qr_code_time",
"import_row_num", "import_file_name", "import_file_id", "remark",
"matching_to_type", "matching_to_id",
"zone_dept_id", "zone_dept_name", "update_time"
@ -30,7 +30,7 @@
"area_name", "area_id", "street_name", "street_id",
"matching_status", "matching_message", "download_status",
"dept_name", "dept_id", "user_name", "user_id",
"create_time", "create_by", "qr_code_path", "last_qr_code_time",
"create_time", "qr_code_path", "last_qr_code_time",
"import_row_num", "import_file_name", "import_file_id", "remark",
"matching_to_type", "matching_to_id",
"zone_dept_id", "zone_dept_name", "update_time",
@ -55,7 +55,6 @@
"user_name": "user_name",
"user_id": "user_id",
"create_time": "create_time",
"create_by": "create_by",
"qr_code_path": "qr_code_path",
"last_qr_code_time": "last_qr_code_time",
"import_row_num": "import_row_num",

Loading…
Cancel
Save