Browse Source

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

dev-V1.0.1
庄锐波 5 months ago
parent
commit
ce6da77619
  1. 3
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfAccordingController.java
  2. 52
      zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfEnterpriseLawEnforcementController.java
  3. 12
      zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js
  4. 226
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/common/DateFilterPicker.vue
  5. 142
      zdxt-web-client/zdxt-efcode-enforcement-app/src/components/enforcement/register/RegisterPopups.vue
  6. 9
      zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js
  7. 188
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/components/HistoryActivityDetail.vue
  8. 230
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/components/HistoryActivityList.vue
  9. 84
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enforce/enforcementRegister.vue
  10. 3
      zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/enterpriseScanPreview.vue

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

@ -41,7 +41,8 @@ public class AppEnfAccordingController extends BaseController {
/**
* 查询执依据告列表
*/
@SaCheckPermission("enforcementcode:zqyjjdm137344:list")
@SaIgnore
//@SaCheckPermission("enforcementcode:zqyjjdm137344:list")
@GetMapping("/list")
public TableDataInfo<Zqyjjdm137344Vo> list(Zqyjjdm137344Bo bo, PageQuery pageQuery) {
return zqyjjdm137344Service.queryPageList(bo, pageQuery);

52
zdxt-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfEnterpriseLawEnforcementController.java

@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.springframework.web.bind.annotation.*;
@ -37,29 +38,54 @@ public class AppEnfEnterpriseLawEnforcementController {
/**
* 执法端-执法预告列表
*/
@SaIgnore
@PostMapping("/queryList")
@ResponseBody
public TableDataInfo<EnterpriseLawEnforcementVo> queryList(@RequestBody EnterpriseLawEnforcementBo bo, PageQuery pageQuery) {
TableDataInfo<EnterpriseLawEnforcementVo> rspData = enterpriseLawEnforcementService.selectEnterpriseLawEnforcementVoPageByBo(bo, pageQuery);
public TableDataInfo<EnterpriseLawEnforcementVo> queryList(@RequestBody EnterpriseLawEnforcementBo bo, @RequestBody PageQuery pageQuery) {
// 使用 DataPermissionHelper.ignore() 跳过数据权限检查,避免未登录时获取 LoginUser 报错
TableDataInfo<EnterpriseLawEnforcementVo> rspData = DataPermissionHelper.ignore(() ->
enterpriseLawEnforcementService.selectEnterpriseLawEnforcementVoPageByBo(bo, pageQuery)
);
List<EnterpriseLawEnforcementVo> list = rspData.getRows();
if (list == null || list.isEmpty()) {
return rspData;
}
for (EnterpriseLawEnforcementVo vo : list) {
List<SysUserVo> userBeans = new ArrayList<>();
if (StringUtils.isNotEmpty(vo.getLawEnforcerTwoId())) {
Long[] userIds = Convert.toLongArray(vo.getLawEnforcerTwoId());
List<Long> userIdList = java.util.Arrays.asList(userIds);
userBeans = sysUserService.selectUserByIds(userIdList, null);
try {
String[] userIdStrs = Convert.toStrArray(vo.getLawEnforcerTwoId());
List<Long> userIdList = new ArrayList<>();
for (String id : userIdStrs) {
try {
userIdList.add(Long.parseLong(id.trim()));
} catch (NumberFormatException e) {
log.warn("无效的用户ID格式: {}", id);
}
}
if (!userIdList.isEmpty()) {
userBeans = sysUserService.selectUserByIds(userIdList, null);
}
} catch (Exception e) {
log.error("解析执法人员ID失败: {}", vo.getLawEnforcerTwoId(), e);
}
}
String tmpUserShow = "";
for (SysUserVo ub : userBeans) {
String temp = ub.getLawCertificateNum();
if(StringUtils.isEmpty(temp)) {
temp = CommonUtil.encryptPhone(ub.getPhonenumber());
if (userBeans != null && !userBeans.isEmpty()) {
for (SysUserVo ub : userBeans) {
if (ub != null) {
String temp = ub.getLawCertificateNum();
if(StringUtils.isEmpty(temp)) {
temp = CommonUtil.encryptPhone(ub.getPhonenumber());
}
tmpUserShow += ub.getUserName() +" "+ temp + ",";
}
}
if (tmpUserShow.length() > 0) {
tmpUserShow = tmpUserShow.substring(0, tmpUserShow.length()-1);
}
tmpUserShow += ub.getUserName() +" "+ temp + ",";
}
if (tmpUserShow.length() > 0) {
tmpUserShow = tmpUserShow.substring(0, tmpUserShow.length()-1);
}
vo.setLawEnforcer2Show(tmpUserShow);

12
zdxt-web-client/zdxt-efcode-enforcement-app/src/api/enforcement/index.js

@ -44,11 +44,23 @@ export const queryXzcfList = (enterpriseNumber, success, error) => _get(baseUrl
export const queryXzqzList = (enterpriseNumber, success, error) => _get(baseUrl + "/caseInfo/queryXzqzList", { c301010: enterpriseNumber }, success, error);
// 执法依据列表
export const queryAccordingList = (params, success, error) => _get(baseUrl + "/according//list", params, success, error);
export const queryEnfRegistrationList = (params, success, error) => _get(baseUrl + "/enfRegistration/queryList", params, success, error);
// 行政执法保存
export const saveEnfRegistration = (params, success, error) => _post(baseUrl + "/enfRegistration/add", params, success, error);
// 行政执法提交
export const submitEnfRegistration = (params, success, error) => _post(baseUrl + "/enfRegistration/edit", params, success, error);
// 历史活动列表
export const queryNonRegistrationList = (params, success, error) => _get(baseUrl + "/nonRegistration/queryList", params, success, error);
// 历史活动详情
export const queryNonRegistrationDetail = (params, success, error) => _get(baseUrl + "/nonRegistration/queryById", params, success, error);
export const queryEnforcementNoticeList = (params, success, error) => _post(baseUrl + "/enforcement/queryList", params, success, error);
export const queryUsersByPage = (params, success, error) => _post(baseUrl + "/system/queryUsersByPage", params, success, error);

226
zdxt-web-client/zdxt-efcode-enforcement-app/src/components/common/DateFilterPicker.vue

@ -0,0 +1,226 @@
<template>
<div class="date-filter-picker">
<!-- 日期快捷筛选按钮 -->
<div class="search-button-list">
<van-button
plain
hairline
:class="dateType === null ? 'search-btn active' : 'search-btn'"
@click="handleDateType(null)"
round
type="primary"
size="mini"
>
全部
</van-button>
<van-button
plain
hairline
:class="dateType === 1 ? 'search-btn active' : 'search-btn'"
@click="handleDateType(1)"
round
type="primary"
size="mini"
>
本月
</van-button>
<van-button
plain
hairline
:class="dateType === 2 ? 'search-btn active' : 'search-btn'"
@click="handleDateType(2)"
round
type="primary"
size="mini"
>
本季
</van-button>
<van-button
plain
hairline
:class="dateType === 3 ? 'search-btn active' : 'search-btn'"
@click="handleDateType(3)"
round
type="primary"
size="mini"
>
本年
</van-button>
<van-button
plain
hairline
:class="dateType === 9 ? 'search-btn active' : 'search-btn'"
@click="openDatePicker"
round
type="primary"
size="mini"
>
筛选
</van-button>
</div>
<!-- 指定月份显示 -->
<div class="search-date-display" v-show="dateShow">
<span class="date-label" @click="openDatePicker">{{ dateSearchDisplay }}</span>
</div>
<!-- 月份选择器弹出层 -->
<van-popup v-model:show="showDatePicker" position="bottom">
<van-date-picker
title="选择月度"
v-model="currentDate"
:min-date="minDate"
:max-date="maxDate"
:columns-type="['year', 'month']"
@confirm="onDateConfirm"
@cancel="showDatePicker = false"
/>
</van-popup>
</div>
</template>
<script setup name="DateFilterPicker">
import { ref, watch } from 'vue';
// Props
const props = defineProps({
// 日期类型:null=全部,1=本月,2=本季,3=本年,9=筛选
modelValue: {
type: Number,
default: null
},
dateSearch: {
type: String,
default: null
},
dateShow: {
type: Boolean,
default: false
}
});
// Emits
const emit = defineEmits(['update:modelValue', 'update:dateSearch', 'update:dateShow', 'change']);
// 当前选中的日期类型
const dateType = ref(props.modelValue);
// 日期显示文本
const dateSearchDisplay = ref('');
// 是否显示日期选择器
const showDatePicker = ref(false);
// 当前选中的日期
const currentDate = ref(['2026', '01']);
// 最小和最大日期
const minDate = new Date(2020, 0, 1);
const maxDate = new Date(2030, 11, 31);
// 监听外部值变化
watch(() => props.modelValue, (newVal) => {
dateType.value = newVal;
});
watch(() => props.dateSearch, (newVal) => {
if (newVal) {
const parts = newVal.split('-');
if (parts.length >= 2) {
currentDate.value = [parts[0], parts[1]];
dateSearchDisplay.value = `${parts[0]}/${parts[1]}`;
}
}
});
// ========== 方法 ==========
// 处理日期类型切换
const handleDateType = (val) => {
dateType.value = val;
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
let searchValue = null;
if (val === null) {
// 全部
searchValue = null;
} else if (val === 1) {
// 本月 - 传 month
searchValue = 'month';
} else if (val === 2) {
// 本季 - 传 quarter
searchValue = 'quarter';
} else if (val === 3) {
// 本年 - 传 year
searchValue = 'year';
}
emit('update:modelValue', val);
emit('update:dateSearch', searchValue);
emit('update:dateShow', false);
emit('change', { dateType: val, dateSearch: searchValue });
};
// 打开日期选择器
const openDatePicker = () => {
dateType.value = 9;
showDatePicker.value = true;
emit('update:modelValue', 9);
emit('update:dateShow', true);
};
// 日期选择确认
const onDateConfirm = (value) => {
const year = value.selectedValues[0];
const month = value.selectedValues[1];
dateSearchDisplay.value = `${year}/${month}`;
const searchValue = `${year}-${month}`; // 手动选择具体月份时传 yyyy-mm-dd 格式
emit('update:modelValue', 9);
emit('update:dateSearch', searchValue);
emit('update:dateShow', true);
emit('change', { dateType: 9, dateSearch: searchValue });
showDatePicker.value = false;
};
</script>
<style lang="less" scoped>
.date-filter-picker {
/* ===== 搜索按钮行 ===== */
.search-button-list {
display: flex;
flex-direction: row;
padding: 10px;
.search-btn {
width: 54px;
height: 24px;
background: #ebebeb;
border-color: #ebebeb;
color: #999;
font-size: 12px;
}
.search-btn.active {
background-color: #d9e6fd;
border-color: #75a5fb;
color: #1367fe;
}
}
/* ===== 日期显示 ===== */
.search-date-display {
padding: 10px;
.date-label {
color: #c1bfbf;
font-size: 0.4rem;
cursor: pointer;
}
}
}
</style>

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

@ -30,34 +30,29 @@
<span class="popup-title">预告查询</span>
<van-icon name="cross" class="close-icon" @click="localNoticePopup = false" />
</div>
<div class="popup-content" @scroll="onNoticeScroll">
<van-list v-model:loading="loading" :finished="finished" :immediate-check="false" finished-text="没有更多了" @load="loadNotices" class="popup-content">
<div v-for="(notice, index) in noticeList" :key="index" class="notice-item">
<div class="notice-info">
<div class="notice-matter">执法事项:{{ notice.matter }}</div>
<div class="notice-time">执法时间:{{ notice.time }}</div>
<div class="notice-matter">执法事项:{{ notice.checkItem }}</div>
<div class="notice-time">执法时间:{{ notice.checkTime }}</div>
</div>
<van-button class="link-btn" type="primary" @click="$emit('linkNotice', notice)">
一键关联
</van-button>
</div>
<div v-if="loading" class="loading-more">
<van-loading size="small" />
<span>加载中...</span>
</div>
<div v-else-if="finished" class="no-more">没有更多了</div>
</div>
</van-list>
</div>
</van-popup>
<!-- 类别选择弹窗 -->
<van-popup v-model:show="localCategoryPopup" round position="bottom">
<van-picker :columns="options.categories" @cancel="localCategoryPopup = false"
<van-picker :columns="categoryOptions" @cancel="localCategoryPopup = false"
@confirm="$emit('confirmCategory', $event)" />
</van-popup>
<!-- 任务来源弹窗 -->
<van-popup v-model:show="localTaskSourcePopup" round position="bottom">
<van-picker :columns="options.taskSources" @cancel="localTaskSourcePopup = false"
<van-picker :columns="taskSourceOptions" @cancel="localTaskSourcePopup = false"
@confirm="$emit('confirmTaskSource', $event)" />
</van-popup>
@ -96,13 +91,13 @@
@clear="clearBasisSearch" />
<van-button class="search-btn" type="primary" @click="handleBasisSearch">搜索</van-button>
</div>
<div class="enforcement-basis-list">
<van-list v-model:loading="basisLoading" :finished="basisFinished" :immediate-check="false" finished-text="没有更多了" @load="loadBasisList" class="enforcement-basis-list">
<div v-for="(item, index) in enforcementBasisList" :key="index" class="basis-list-item"
@click="$emit('selectBasis', item)">
<div class="basis-name">{{ item.name }}</div>
<div class="basis-name">{{ item.name || item.lawName }}</div>
</div>
<van-empty v-if="enforcementBasisList.length === 0" description="没有更多了" />
</div>
<van-empty v-if="enforcementBasisList.length === 0 && !basisLoading" description="暂无数据" />
</van-list>
</div>
</van-popup>
@ -131,21 +126,17 @@
</template>
<script setup name="RegisterPopups">
import { ref, reactive, watch, computed } from 'vue';
import { queryEnforcementNoticeList, queryUsersByPage } from '@/api/enforcement/index';
import { ref, reactive, watch, computed, onMounted } from 'vue';
import { showToast } from 'vant';
import { queryEnforcementNoticeList, queryUsersByPage, queryAccordingList } from '@/api/enforcement/index';
import { loadDict } from '@/util/dictUtil';
const props = defineProps({
visible: {
type: Object,
required: true
},
options: {
type: Object,
default: () => ({
categories: [],
taskSources: []
})
},
selectedPersons: {
type: Array,
default: () => []
@ -163,6 +154,32 @@ const emit = defineEmits([
'selectEntrustedAgency'
]);
// 类别选项(从字典获取)
const categoryOptions = ref([]);
// 任务来源选项(从字典获取)
const taskSourceOptions = ref([]);
// 加载执法类别字典
const loadCategoryDict = () => {
loadDict('law_enforce_category', (columns) => {
console.log(columns);
categoryOptions.value = columns;
});
};
// 加载检查类别字典
const loadTaskSourceDict = () => {
loadDict('check_category', (columns) => {
taskSourceOptions.value = columns;
});
};
onMounted(() => {
loadCategoryDict();
loadTaskSourceDict();
});
// 使用 computed 创建可写的计算属性(自动同步 props,保证响应式)
const localEnterprisePopup = computed({
get: () => props.visible.enterprise,
@ -325,26 +342,56 @@ watch(() => props.selectedPersons, () => {
// ========== 执法依据相关 ==========
const basisSearchKeyword = ref('');
const enforcementBasisList = ref([]);
const basisLoading = ref(false);
const basisFinished = ref(false);
const basisPageNum = ref(1);
const basisPageSize = ref(10);
const initBasisList = () => {
enforcementBasisList.value = [
{ id: 1, name: '《中华人民共和国行政处罚法》' },
{ id: 2, name: '《中华人民共和国行政许可法》' },
{ id: 3, name: '《中华人民共和国行政强制法》' },
{ id: 4, name: '《深圳市经济特区商事登记若干规定》' },
{ id: 5, name: '《深圳经济特区优化营商环境条例》' },
{ id: 6, name: '《中华人民共和国市场主体登记管理条例》' },
];
const loadBasisList = () => {
if (basisFinished.value) return;
const params = {
pageNum: basisPageNum.value,
pageSize: basisPageSize.value,
lawName: basisSearchKeyword.value || undefined
};
queryAccordingList(params, (res) => {
if (res.code === 200 || res.code === 0) {
const list = res.data || res.rows || [];
if (basisPageNum.value === 1) {
enforcementBasisList.value = list;
} else {
enforcementBasisList.value = [...enforcementBasisList.value, ...list];
}
basisFinished.value = list.length < basisPageSize.value;
if (!basisFinished.value) {
basisPageNum.value++;
}
} else {
console.error('获取执法依据失败:', res.msg);
showToast(res.msg || '获取执法依据失败');
basisFinished.value = true;
}
basisLoading.value = false;
}, (err) => {
basisLoading.value = false;
basisFinished.value = true;
console.error('获取执法依据接口失败', err);
showToast('获取执法依据失败');
});
};
const initBasisList = async () => {
basisLoading.value = false;
basisFinished.value = false;
basisPageNum.value = 1;
enforcementBasisList.value = [];
await nextTick();
loadBasisList();
};
const handleBasisSearch = () => {
initBasisList();
if (basisSearchKeyword.value.trim()) {
const keyword = basisSearchKeyword.value.toLowerCase();
enforcementBasisList.value = enforcementBasisList.value.filter(item =>
item.name.toLowerCase().includes(keyword)
);
}
};
const clearBasisSearch = () => {
@ -352,7 +399,7 @@ const clearBasisSearch = () => {
initBasisList();
};
watch(localBasisPopup, (val) => {
watch(() => props.visible.basis, (val) => {
if (val) {
basisSearchKeyword.value = '';
initBasisList();
@ -419,8 +466,7 @@ const loading = ref(false);
const finished = ref(false);
const loadNotices = () => {
if (loading.value || finished.value) return;
loading.value = true;
if (finished.value) return;
// 从缓存中获取企业统一信用代码
let enterpriseNumber = '';
@ -441,7 +487,6 @@ const loadNotices = () => {
};
queryEnforcementNoticeList(params, (res) => {
loading.value = false;
if (res.code === 200) {
const data = res.rows || [];
if (noticePage.value === 1) {
@ -449,6 +494,7 @@ const loadNotices = () => {
} else {
noticeList.value = [...noticeList.value, ...data];
}
console.log('获取预告列表成功:', data);
finished.value = data.length < noticePageSize.value;
if (!finished.value) {
noticePage.value++;
@ -464,19 +510,13 @@ const loadNotices = () => {
});
};
const onNoticeScroll = (e) => {
const target = e.target;
if (target.scrollTop + target.clientHeight >= target.scrollHeight - 10 && !loading.value && !finished.value) {
loadNotices();
}
};
watch(localNoticePopup, (newVal) => {
watch(localNoticePopup, async (newVal) => {
if (newVal) {
noticePage.value = 1;
noticeList.value = [];
loading.value = false;
finished.value = false;
await nextTick();
loadNotices();
}
});

9
zdxt-web-client/zdxt-efcode-enforcement-app/src/router/enforcement-app/enf-main-router.js

@ -44,6 +44,15 @@ const routes = [
isKeepAlive: false,
},
},
// 执法端-历史活动详情
{
path: "/enforcement/historyActivityDetail",
name: "historyActivityDetail",
component: () => import("@/views/enforcement/components/HistoryActivityDetail.vue"),
meta: {
isKeepAlive: false,
},
},
// 执法端-查询(tabbar)
{
path: "/enforcement/query",

188
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/components/HistoryActivityDetail.vue

@ -0,0 +1,188 @@
<template>
<div class="history-activity-detail">
<!-- 头部导航 -->
<!-- <van-nav-bar title="活动详情" left-arrow @click-left="goBack" /> -->
<div class="detail-content">
<!-- 企业信息 -->
<div class="custom-cell-group">
<div class="activity-title">企业信息</div>
<div class="custom-cell">
<span class="custom-cell-label">企业名称</span>
<span class="custom-cell-value">{{ activityDetail.enterpriseName || '-' }}</span>
</div>
<div class="custom-cell">
<span class="custom-cell-label">统一社会信用代码</span>
<span class="custom-cell-value">{{ activityDetail.enterpriseNumber || '-' }}</span>
</div>
</div>
</div>
<div class="detail-content">
<!-- 入企信息 -->
<div class="custom-cell-group">
<div class="activity-title">入企信息</div>
<div class="custom-cell">
<span class="custom-cell-label">入企单位</span>
<span class="custom-cell-value">{{ activityDetail.bureauDeptName || '-' }}</span>
</div>
<div class="custom-cell">
<div class="custom-cell-label">
<span>入企人员</span>
</div>
<div>
<div class="custom-cell-address">{{ activityDetail.lawEnforcer }}{{ activityDetail.lawEnforcerId
}}</div>
<div class="custom-cell-address">{{ activityDetail.lawEnforcerOther }}{{
activityDetail.lawEnforcerIdOther }}</div>
</div>
</div>
<div class="custom-cell">
<span class="custom-cell-label">入企事由</span>
<span class="custom-cell-value">{{ activityDetail.lawEnforcementTypeText }}</span>
</div>
<div class="custom-cell">
<span class="custom-cell-label">入企事项</span>
<span class="custom-cell-value">{{ activityDetail.LawEnforcementItemText }}</span>
</div>
<div class="custom-cell">
<span class="custom-cell-label">入企时间</span>
<span class="custom-cell-value">{{ formattedDate(activityDetail.enforcementTime) }}</span>
</div>
<div class="custom-cell">
<span class="custom-cell-label">原因</span>
<span class="custom-cell-value">{{ activityDetail.reason }}</span>
</div>
</div>
</div><!-- 附件 -->
<div class="detail-content">
<div class="custom-cell-group"
v-if="activityDetail.params && activityDetail.params.fileList && activityDetail.params.fileList.length > 0">
<div class="activity-title">附件</div>
<div class="attachments-list">
<div v-for="(file, index) in activityDetail.params.fileList" :key="index" class="attachment-item">
<img v-if="file.uploadPath" :src="baseUrl + file.uploadPath" class="attachment-image" />
<van-icon v-else name="paper" />
</div>
</div>
</div>
</div>
<!-- 备注 -->
</div>
</template>
<script setup name="HistoryActivityDetail">
import { ref, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { formattedDate } from '@/util/util.js';
import { queryNonRegistrationDetail } from '@/api/enforcement/index';
import { baseUrl } from '@/config/env';
const router = useRouter();
const route = useRoute();
// 活动详情数据
const activityDetail = ref({});
// 返回上一页
const goBack = () => {
router.back();
};
// 获取详情数据
const fetchDetail = (id) => {
queryNonRegistrationDetail({ id }, (res) => {
if (res.code === 200) {
activityDetail.value = res.data || {};
} else {
console.error('获取活动详情失败:', res.msg);
}
}, (err) => {
console.error('获取活动详情接口失败', err);
});
};
onMounted(() => {
const id = route.query.id;
if (id) {
fetchDetail(id);
}
});
</script>
<style lang="less" scoped>
.history-activity-detail {
min-height: 100vh;
background-color: #ebf3fb;
box-sizing: border-box;
padding-top: 12px;
.detail-content {
margin: 0px 15px 15px 15px;
.activity-title {
font-size: 16px;
font-weight: bold;
color: #000;
padding: 16px;
box-sizing: border-box;
}
.custom-cell-group {
background: #fff;
border-radius: 8px;
overflow: hidden;
}
.custom-cell {
display: flex;
padding: 16px;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
}
.custom-cell-label {
width: 68px;
flex-shrink: 0;
color: #666;
font-size: 14px;
margin-right: 26px;
}
.custom-cell-value {
flex: 1;
color: #333;
font-size: 14px;
word-break: break-all;
}
.custom-cell-address {
color: #333;
font-size: 14px;
padding-bottom: 10px;
}
:deep(.van-cell-group--inset) {
margin: 0;
}
}
.attachments-list {
display: flex;
align-items: center;
.attachment-item {
padding: 10px;
.attachment-image {
width: 40px;
height: 40px;
border-radius: 4px;
object-fit: cover;
}
}
}
}
</style>

230
zdxt-web-client/zdxt-efcode-enforcement-app/src/views/enforcement/components/HistoryActivityList.vue

@ -1,66 +1,46 @@
<template>
<div class="history-activity-list">
<!-- 搜索栏 -->
<van-search v-model="searchText" show-action placeholder="入企事项/入企部门/入企人员" clearable clear-trigger="always"
@clear="onClear" @search="onSearch">
<template #action>
<div @click="onSearch">搜索</div>
</template>
</van-search>
<!-- 日期快捷筛选按钮 -->
<div class="search-button-list">
<van-button plain hairline :class="dateType === null ? 'search-btn active' : 'search-btn'"
@click="searchDateType(null)" round type="primary" size="mini">全部</van-button>
<van-button plain hairline :class="dateType === 1 ? 'search-btn active' : 'search-btn'"
@click="searchDateType(1)" round type="primary" size="mini">本月</van-button>
<van-button plain hairline :class="dateType === 2 ? 'search-btn active' : 'search-btn'"
@click="searchDateType(2)" round type="primary" size="mini">本季</van-button>
<van-button plain hairline :class="dateType === 3 ? 'search-btn active' : 'search-btn'"
@click="searchDateType(3)" round type="primary" size="mini">本年</van-button>
<van-button plain hairline :class="dateType === 9 ? 'search-btn active' : 'search-btn'"
@click="openDatePicker" round type="primary" size="mini">筛选</van-button>
</div>
<!-- 指定月份显示 -->
<div class="search-date-display" v-show="dateShow">
<span class="date-label" @click="openDatePicker">{{ dateSearchDisplay }}</span>
<div class="search-header">
<van-search v-model="searchText" show-action placeholder="入企事项/入企部门/入企人员" clearable clear-trigger="always"
@clear="onClear" @search="onSearch">
<template #action>
<div @click="onSearch">搜索</div>
</template>
</van-search>
<!-- 日期筛选组件 -->
<DateFilterPicker v-model="dateType" v-model:date-search="dateSearch" v-model:date-show="dateShow"
@change="onDateFilterChange" />
</div>
<!-- 月份选择器弹出层 -->
<van-popup v-model:show="showDatePicker" position="bottom">
<van-date-picker title="选择月度" v-model="currentDate" :min-date="minDate" :max-date="maxDate"
:columns-type="['year', 'month']" @confirm="onDateConfirm" @cancel="showDatePicker = false" />
</van-popup>
<!-- 搜索栏 -->
<!-- 活动列表 -->
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="已加载全部数据"
@load="onLoad"
class="activity-list"
>
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" immediate-check
class="activity-list">
<van-empty v-if="finished && activityList.length === 0" description="暂无数据" />
<div v-for="(item, index) in activityList" :key="index" class="activity-card-item">
<div v-for="(item, index) in activityList" :key="index" class="activity-card-item"
@click="goToDetail(item)">
<div class="activity-header">
<span class="activity-time">{{ formatDate(item.createTime) }}</span>
<span class="activity-status" v-if="item.isRealUnion === 1">联</span>
<span class="activity-time">入企时间:{{ formattedDate(item.enforcementTime) }}</span>
<span class="activity-status" v-if="item.hasUnion === 1">联</span>
</div>
<div class="activity-divider"></div>
<div class="activity-body">
<div class="activity-title">{{ item.lawEnforcementItemText || '-' }}</div>
<div class="activity-row">
<span class="activity-label">入企部门:</span>
<span>{{ item.lawEnforcement || '-' }}</span>
<span class="activity-label">入企单位:</span>
<span>{{ item.bureauDeptName || '-' }}</span>
</div>
<div class="activity-row">
<span class="activity-label">入企人员:</span>
<span>{{ getEnforcerDisplay(item) }}</span>
<div class="activity-label">入企人员:</div>
<div>
<div>{{ item.lawEnforcer }} {{ item.lawEnforcerId }} </div>
<div>{{ item.lawEnforcerOther }} {{ item.lawEnforcerIdOther }}</div>
</div>
</div>
<div class="activity-row">
<span class="activity-label">企业名称:</span>
<span>{{ enterpriseName || '-' }}</span>
<span>{{ item.enterpriseName || enterpriseName || '-' }}</span>
</div>
</div>
</div>
@ -70,7 +50,12 @@
<script setup name="HistoryActivityList">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { queryNonRegistrationList } from '@/api/enforcement/index';
import DateFilterPicker from '@/components/common/DateFilterPicker.vue';
import { formattedDate } from '@/util/util.js';
const router = useRouter();
const props = defineProps({
enterpriseName: {
@ -79,6 +64,14 @@ const props = defineProps({
}
});
// ========== 点击跳转详情 ==========
const goToDetail = (item) => {
router.push({
path: '/enforcement/historyActivityDetail',
query: { id: item.id }
});
};
// ========== 数据 ==========
// 活动列表数据
const activityList = ref([]);
@ -96,41 +89,16 @@ const searchText = ref('');
// 日期筛选
const dateType = ref(null);
const dateSearch = ref(null);
const dateSearchDisplay = ref('');
const dateShow = ref(false);
const showDatePicker = ref(false);
const currentDate = ref(['2026', '01']);
const minDate = new Date(2020, 0, 1);
const maxDate = new Date(2030, 11, 31);
// ========== 格式化日期 ==========
const formatDate = (dateStr) => {
if (!dateStr) return '-';
const d = new Date(dateStr.replace ? dateStr.replace(/-/g, '/') : dateStr);
if (isNaN(d.getTime())) return dateStr;
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
};
// ========== 执法人员展示 ==========
const getEnforcerDisplay = (item) => {
if (item.lawEnforcerDisplay) return item.lawEnforcerDisplay;
const names = [];
if (item.lawEnforcer) names.push(item.lawEnforcer);
if (item.lawEnforcerTwo) names.push(item.lawEnforcerTwo);
if (Array.isArray(item.lawEnforcer2List)) names.push(...item.lawEnforcer2List);
return names.length ? names.join('、') : '-';
};
// ========== 获取活动数据 ==========
const fetchActivityList = (isLoadMore = false) => {
loading.value = true;
const params = {
pageSize: pageSize.value,
pageNum: isLoadMore ? pageNum.value : 1
};
// 关键字搜索
if (searchText.value) {
params.searchValue = searchText.value;
@ -139,24 +107,39 @@ const fetchActivityList = (isLoadMore = false) => {
if (dateSearch.value) {
params.dateSearch = dateSearch.value;
}
queryNonRegistrationList(params, (res) => {
loading.value = false;
if (res.code === 200) {
const data = res.data.list || [];
// 兼容不同的响应码格式
if (res.code === 200 || res.code === 0) {
const data = res.rows || [];
const total = res.total || 0;
if (isLoadMore) {
activityList.value = [...activityList.value, ...data];
} else {
activityList.value = data;
pageNum.value = 1;
}
// 判断是否还有更多数据
hasMore.value = data.length >= pageSize.value;
// 判断是否还有更多数据:根据 total 判断,当前已加载数量 < 总数量则还有更多
const currentCount = activityList.value.length;
hasMore.value = currentCount < total;
finished.value = !hasMore.value;
// 如果还有更多数据,更新页码(初始加载后设置为2,后续每次加载后递增)
if (hasMore.value) {
pageNum.value++;
if (!isLoadMore) {
pageNum.value = 2;
} else {
pageNum.value++;
}
}
// 如果还有更多数据但列表没有自动触发加载,强制触发一次
if (hasMore.value && !loading.value) {
// 延迟执行,确保 van-list 状态已更新
setTimeout(() => {
onLoad();
}, 100);
}
console.log('历史活动数据加载成功:', activityList.value);
} else {
console.error('获取历史活动失败:', res.msg);
finished.value = true;
@ -170,7 +153,9 @@ const fetchActivityList = (isLoadMore = false) => {
// ========== 列表加载处理 ==========
const onLoad = () => {
if (loading.value || !hasMore.value) return;
if (loading.value || !hasMore.value) {
return;
}
fetchActivityList(true);
};
@ -196,48 +181,8 @@ const onClear = () => {
onSearch();
};
// ========== 日期类型切换 ==========
const searchDateType = (val) => {
dateType.value = val;
dateShow.value = false;
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
if (val === null) {
// 全部
dateSearch.value = null;
} else if (val === 1) {
// 本月 - 传 yyyy-mm-dd 格式(当月第一天)
dateSearch.value = `${year}-${month}-01`;
} else if (val === 2) {
// 本季 - 传季度格式 yyyy-Qq
const quarter = Math.ceil((now.getMonth() + 1) / 3);
dateSearch.value = `${year}-Q${quarter}`;
} else if (val === 3) {
// 本年 - 传年份格式 yyyy
dateSearch.value = `${year}`;
}
onSearch();
};
// ========== 打开月份选择器 ==========
const openDatePicker = () => {
dateType.value = 9;
showDatePicker.value = true;
};
// ========== 月份选择确认 ==========
const onDateConfirm = (value) => {
const year = value.selectedValues[0];
const month = value.selectedValues[1];
dateSearchDisplay.value = year + '/' + month;
dateSearch.value = `${year}-${month}-01`; // 传 yyyy-mm-dd 格式
dateType.value = 9;
dateShow.value = true;
showDatePicker.value = false;
// ========== 日期筛选变化处理 ==========
const onDateFilterChange = () => {
onSearch();
};
@ -249,38 +194,7 @@ fetchActivityList();
.history-activity-list {
// padding: 0 0.27rem;
background-color: #fff;
min-height: calc(100vh - 150px);
/* ===== 搜索按钮行 ===== */
.search-button-list {
display: flex;
flex-direction: row;
padding: 10px;
gap: 0.15rem;
.search-btn {
flex: 1;
height: 0.7rem;
background: #ebebeb;
border-color: #ebebeb;
color: #999;
font-size: 0.3rem;
}
.search-btn.active {
background-color: #d9e6fd;
border-color: #75a5fb;
color: #1367fe;
}
}
/* ===== 日期显示 ===== */
.search-date-display {
padding: 10px;
.date-label {
color: #c1bfbf;
font-size: 0.4rem;
}
}
min-height: calc(100vh - 160px);
/* ===== 卡片样式 ===== */
.activity-card-item {
@ -289,6 +203,7 @@ fetchActivityList();
margin-bottom: 0.27rem;
padding: 0.2rem 0.3rem;
position: relative;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.activity-header {
@ -344,7 +259,8 @@ fetchActivityList();
}
.activity-list {
height: calc(100vh - 200px);
height: calc(100vh - 240px);
padding: 10px;
}
}

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

@ -59,7 +59,6 @@
<!-- 弹窗组件 -->
<RegisterPopups
:visible="showPopups"
:options="{ categories: categoryOptions, taskSources: taskSourceOptions }"
:selected-persons="selectedPersonsList"
@close-popup="handleClosePopup"
@select-enterprise="handleSelectEnterprise"
@ -78,6 +77,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 { saveEnfRegistration, submitEnfRegistration } from '@/api/enforcement/index';
import EnterpriseInfoSection from '@/components/enforcement/register/EnterpriseInfoSection.vue';
import EnforcementInfoSection from '@/components/enforcement/register/EnforcementInfoSection.vue';
import NonEnforcementInfoSection from '@/components/enforcement/register/NonEnforcementInfoSection.vue';
@ -104,6 +104,7 @@ const enterpriseData = ref({
const formData = reactive({
relatedNotice: '',
enforcementUnit: '',
checkCss: '',
category: '',
taskSource: '',
enforcementMatter: '',
@ -256,9 +257,10 @@ const handleSelectEnterprise = (enterprise) => {
// 关联预告
const handleLinkNotice = (notice) => {
formData.relatedNotice = `预告-${notice.id}`;
formData.relatedNotice = `${notice.checkItem}`;
formData.checkCss = notice.id;
showPopups.notice = false;
showSuccessToast('关联成功');
// showSuccessToast('关联成功');
};
// 类别选择确认
@ -289,15 +291,69 @@ const goBack = () => {
router.back();
};
// 构建提交数据
const buildSubmitPayload = () => {
const useCommonStr = sessionStorage.getItem('useCommon');
const useCommon = JSON.parse(useCommonStr) || {};
const mainPerson = enforcementPersons.value[0] || {};
const lawCertificateNumText = mainPerson.name && mainPerson.phonenumber
? `${mainPerson.name} ${mainPerson.phonenumber}`
: '';
const lawEnforcerTwo = additionalPersons.value
.filter(p => p.name)
.map(p => p.name)
.join(',');
const lawEnforcerIdTwo = additionalPersons.value
.filter(p => p.id)
.map(p => p.id)
.join(',');
return {
enterpriseName: enterpriseData.value.enterpriseName || '',
enterpriseNumber: enterpriseData.value.enterpriseNumber || '',
oureauDeptName: formData.enforcementUnit || '',
checkCss: formData.checkCss || '',
lawCertificateNumText: lawCertificateNumText,
lawEnforcerTwo: lawEnforcerTwo,
lawEnforcerIdTwo: lawEnforcerIdTwo,
lawEnforceCategory: formData.category || '',
hasUnion: formData.jointEnforcement || 0,
hasAuto: formData.entrustedEnforcement || 0,
lawEnforcement: useCommon.deptName || '',
lawEnforcementId: useCommon.deptId || '',
oureauDeptId: useCommon.bureauUnitId || '',
isRealUnion: formData.jointEnforcement === 1 ? 1 : 0,
lawEnforcementBasisText: formData.enforcementBases ? formData.enforcementBases.join(',') : '',
fileList: buildFileList(),
enforcementTime: formData.enforcementTime || '',
enforcementMatter: formData.enforcementMatter || '',
reason: formData.reason || '',
result: formData.result || '',
remark: formData.remark || ''
};
};
// 保存
const handleSave = () => {
showConfirmDialog({
title: '确认保存',
message: '确认保存吗?',
width: '80%',
}).then(() => {
showSuccessToast('保存成功');
const payload = buildSubmitPayload();
saveEnfRegistration(payload, (res) => {
if (res.code === 200 || res.code === 0) {
showSuccessToast('保存成功');
} else {
showToast(res.msg || '保存失败');
}
}, (err) => {
console.error('保存接口失败', err);
showToast('保存失败');
});
}).catch(() => {
// 用户取消
});
@ -327,13 +383,19 @@ const onSubmit = () => {
message: '确认提交吗?提交后将无法修改。',
width: '80%',
}).then(() => {
// 构建提交数据,包含文件列表
const payload = {
...formData,
fileList: buildFileList()
};
const payload = buildSubmitPayload();
console.log('提交数据:', payload);
showSuccessToast('提交成功');
submitEnfRegistration(payload, (res) => {
if (res.code === 200 || res.code === 0) {
showSuccessToast('提交成功');
router.back();
} else {
showToast(res.msg || '提交失败');
}
}, (err) => {
console.error('提交接口失败', err);
showToast('提交失败');
});
}).catch(() => {
// 用户取消
});

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

@ -251,7 +251,7 @@ const fetchEnterpriseInformation = (enterpriseNumber) => {
// 检测文本是否超过2行
checkTextOverflow();
// 第一次进入时获取历史案件数据(只请求一次)
if (!hasFetchedCaseData.value) {
if (!hasFetchedCaseData.value && !isNonEnforcement.value) {
hasFetchedCaseData.value = true;
fetchZfList(enterpriseNumber);
fetchCfList(enterpriseNumber);
@ -449,6 +449,7 @@ const toSign = () => {
height: calc(100vh - 70px);
background: #fff;
box-sizing: border-box;
overflow-y: auto;
}
.addinfo {

Loading…
Cancel
Save