Browse Source

代码重构

dev-V1.0.1
庄锐波 6 months ago
parent
commit
4a62a4a5ca
  1. 122
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfEnterpriseInformationController.java
  2. 11
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EnterpriseInformationVo.java
  3. 8
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java
  4. 17
      ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java
  5. 3
      zdxt-web-client/zdxt-enforcement-code-app/src/api/enforcement/index.js
  6. 9
      zdxt-web-client/zdxt-enforcement-code-app/src/router/enforcement-app/enf-main-router.js
  7. 229
      zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/enterpriseScanPreview.vue
  8. 38
      zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/scanEntQRCode.vue

122
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/controller/app/enforcement/AppEnfEnterpriseInformationController.java

@ -0,0 +1,122 @@
package com.zdxt.enforcementcode.controller.app.enforcement;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zdxt.enforcementcode.domain.vo.EnterpriseInformationVo;
import com.zdxt.enforcementcode.domain.vo.QrCodeGenerateHistoryVo;
import com.zdxt.enforcementcode.service.IEnterpriseInformationService;
import com.zdxt.enforcementcode.service.IQrCodeGenerateHistoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/app-enf/enterpriseInfo")
public class AppEnfEnterpriseInformationController {
private final IEnterpriseInformationService enterpriseInformationService;
private final IQrCodeGenerateHistoryService qrCodeGenerateHistoryService;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 扫描二维码后获取企业信息(多级降级查询)
* <p>
* 查询优先级:
* 1. 通过 salt 查找企业信息
* 2. 通过 codeId 查找二维码记录,再通过 enterpriseNumber 查找企业信息
* 3. 通过二维码中的 enterpriseNumber 直接查找企业信息
* </p>
*
* @param qrContent 前端解析二维码获取的原始文本内容
* @return 企业信息(含二维码状态)
*/
@SaIgnore
@GetMapping("/getEntInfoByQRCode")
public R<EnterpriseInformationVo> getEntInfoByQRCode(@RequestParam("qrContent") String qrContent) {
log.info("执法端扫码获取企业信息,二维码内容: {}", qrContent);
// 1. 判断 qrContent 是否为 JSON,是则转为 Map,否则打印日志
Map<String, String> qrMap = null;
try {
qrMap = OBJECT_MAPPER.readValue(qrContent, new TypeReference<Map<String, String>>() {});
log.info("二维码内容解析为JSON: {}", qrMap);
} catch (Exception e) {
log.warn("二维码内容不是JSON格式,原始内容: {}", qrContent);
}
EnterpriseInformationVo enterprise = null;
String salt = qrMap != null ? qrMap.get("salt") : null;
String codeId = qrMap != null ? qrMap.get("codeId") : null;
String enterpriseNumber = qrMap != null ? qrMap.get("enterpriseNumber") : null;
// 2. 优先通过 salt 查找企业信息
if (StrUtil.isNotBlank(salt)) {
enterprise = enterpriseInformationService.queryBySalt(salt);
if (enterprise != null) {
log.info("通过 salt 查询到企业信息: {}", enterprise.getEnterpriseName());
} else {
log.info("通过 salt[{}] 未查询到企业信息,进入降级处理", salt);
}
}
// 3. 降级:通过 codeId 查找二维码记录,再通过 enterpriseNumber 查找企业信息
if (enterprise == null && StrUtil.isNotBlank(codeId)) {
QrCodeGenerateHistoryVo qrHistory = qrCodeGenerateHistoryService.queryById(codeId);
if (qrHistory != null && StrUtil.isNotBlank(qrHistory.getEnterpriseNumber())) {
enterprise = enterpriseInformationService.queryByEnterpriseNumber(qrHistory.getEnterpriseNumber());
if (enterprise != null) {
log.info("通过 codeId[{}] -> enterpriseNumber[{}] 查询到企业信息: {}",
codeId, qrHistory.getEnterpriseNumber(), enterprise.getEnterpriseName());
} else {
log.info("通过 codeId[{}] -> enterpriseNumber[{}] 未查询到企业信息",
codeId, qrHistory.getEnterpriseNumber());
}
} else {
log.info("通过 codeId[{}] 未查询到二维码记录或记录中无 enterpriseNumber", codeId);
}
}
// 4. 最终降级:通过二维码中的 enterpriseNumber 直接查找企业信息
if (enterprise == null && StrUtil.isNotBlank(enterpriseNumber)) {
enterprise = enterpriseInformationService.queryByEnterpriseNumber(enterpriseNumber);
if (enterprise != null) {
log.info("通过二维码中的 enterpriseNumber[{}] 直接查询到企业信息: {}",
enterpriseNumber, enterprise.getEnterpriseName());
} else {
log.info("通过 enterpriseNumber[{}] 未查询到企业信息", enterpriseNumber);
}
}
if (enterprise == null) {
return R.fail("无法通过该二维码识别企业信息");
}
// 5. 校验二维码是否有效
boolean qrCodeValid = false;
String checkCodeId = codeId;
// 如果二维码中没有 codeId,尝试用企业上的 qrCodeId
if (StrUtil.isBlank(checkCodeId) && StrUtil.isNotBlank(enterprise.getQrCodeId())) {
checkCodeId = enterprise.getQrCodeId();
}
if (StrUtil.isNotBlank(checkCodeId)) {
QrCodeGenerateHistoryVo qrCode = qrCodeGenerateHistoryService.queryById(checkCodeId);
if (qrCode != null && qrCode.getStatus() != null && qrCode.getStatus() == 0L) {
qrCodeValid = true;
}
}
// 6. 设置二维码状态并返回
enterprise.setQrCodeValid(qrCodeValid);
enterprise.setQrCodeMessage(qrCodeValid ? "二维码正常" : "二维码已过期");
log.info("执法端扫码查询成功,企业: {},二维码状态: {}", enterprise.getEnterpriseName(), qrCodeValid ? "正常" : "过期");
return R.ok(enterprise);
}
}

11
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/domain/vo/EnterpriseInformationVo.java

@ -153,5 +153,16 @@ public class EnterpriseInformationVo implements Serializable {
@ExcelProperty(value = "")
private String operatingTermEnd;
// ========== 非持久化字段,用于扫码接口返回 ==========
/**
* 二维码是否有效(非数据库字段,扫码接口动态赋值)
*/
private transient Boolean qrCodeValid;
/**
* 二维码状态描述(非数据库字段,扫码接口动态赋值)
*/
private transient String qrCodeMessage;
}

8
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/IEnterpriseInformationService.java

@ -76,6 +76,14 @@ public interface IEnterpriseInformationService {
*/
EnterpriseInformationVo queryByEnterpriseNumber(String enterpriseNumber);
/**
* 根据盐加密字符串查询唯一企业信息
*
* @param salt 盐加密字符串
* @return 企业信息,不存在返回 null
*/
EnterpriseInformationVo queryBySalt(String salt);
/**
* 为企业生成蓝色二维码(含 LOGO)
* <p>如果企业已存在有效二维码,则直接返回已有记录,不重复生成</p>

17
ruoyi-modules/zdxt-enforcement-code/src/main/java/com/zdxt/enforcementcode/service/impl/EnterpriseInformationServiceImpl.java

@ -177,6 +177,23 @@ public class EnterpriseInformationServiceImpl implements IEnterpriseInformationS
return list.get(0);
}
/**
* 根据盐加密字符串查询唯一企业信息
*/
@Override
public EnterpriseInformationVo queryBySalt(String salt) {
if (StringUtils.isBlank(salt)) {
return null;
}
LambdaQueryWrapper<EnterpriseInformation> lqw = Wrappers.lambdaQuery();
lqw.eq(EnterpriseInformation::getSalt, salt);
List<EnterpriseInformationVo> list = baseMapper.selectVoList(lqw);
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
/**
* 为企业生成蓝色二维码(含 LOGO)
* <p>如果企业已存在有效二维码,则直接返回已有记录,不重复生成</p>

3
zdxt-web-client/zdxt-enforcement-code-app/src/api/enforcement/index.js

@ -7,4 +7,7 @@ let enforcementAppBaseUrl = "/app-enf";
// 执法端用户登录
export const enforcementLogin = (params, success, error) => _post(enforcementAppBaseUrl + "/login/do", params, success, error);
// 扫描二维码后获取企业信息(qrContent 为前端解析二维码获取的原始文本)
export const getEntInfoByQRCode = (qrContent, success, error) => _get(enforcementAppBaseUrl + "/enterpriseInfo/getEntInfoByQRCode", { qrContent }, success, error);
// endregion

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

@ -27,6 +27,15 @@ const routes = [
isKeepAlive: false,
},
},
// 执法端扫码-企业详情预览
{
path: "/enforcement/enterpriseScanPreview",
name: "enfEnterpriseScanPreview",
component: () => import("@/views/enforcement/enterpriseScanPreview.vue"),
meta: {
isKeepAlive: false,
},
},
];
export {routes};

229
zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/enterpriseScanPreview.vue

@ -0,0 +1,229 @@
<template>
<div class="home app_content">
<!-- 返回首页 -->
<span class="tohome" @click="toEnforcementHome">
<i class="van-badge__wrapper van-icon van-icon-wap-home-o"></i>
</span>
<!-- 中间 -->
<div class="warp_body">
<div class="white-body">
<!-- Tab 切换 -->
<div class="tabs">
<ul>
<li v-for="(item, index) in tabList" :key="index"
@click="currentTab = index"
:class="{ active: index === currentTab }">
<span>{{ item.title }}</span>
</li>
</ul>
</div>
<!-- 企业画像 Tab -->
<div v-if="currentTab === 0" class="tab-content">
<div v-if="enterpriseData" class="enterprise-info">
<van-cell-group inset>
<van-cell title="企业名称" :value="enterpriseData.enterpriseName" />
<van-cell title="纳税识别号" :value="enterpriseData.enterpriseNumber" />
<van-cell title="企业类型" :value="enterpriseData.enterpriseType" />
<van-cell title="法定代表人" :value="enterpriseData.legalPerson" />
<van-cell title="注册资本" :value="enterpriseData.registeredCapital" />
<van-cell title="成立日期" :value="formatDate(enterpriseData.establishmentTime)" />
<van-cell title="营业期限" :value="enterpriseData.operatingTerm" />
<van-cell title="企业地址" :value="enterpriseData.enterpriseAddress" :label="enterpriseData.enterpriseAddress" />
<van-cell title="经营范围" :label="enterpriseData.businessScope" />
<van-cell title="联系电话" :value="enterpriseData.enterpriseTel" />
<van-cell title="所属行业" :value="enterpriseData.industry" />
</van-cell-group>
</div>
<van-empty v-else description="暂无企业信息" />
</div>
<!-- 执法记录 Tab -->
<div v-if="currentTab === 1" class="tab-content">
<van-empty description="执法记录功能待对接" />
</div>
</div>
</div>
<!-- 登记按钮 -->
<div class="addinfo" @click="toSign">登记</div>
</div>
</template>
<script setup name="EnterpriseScanPreview">
import { ref, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { showFailToast } from 'vant';
const router = useRouter();
const route = useRoute();
// ========== 数据 ==========
const currentTab = ref(0);
const tabList = [
{ title: '企业画像', value: '0' },
{ title: '执法记录', value: '1' },
];
const enterpriseData = ref(null);
const enterpriseNumber = ref('');
const qrCodeValid = ref(false);
// ========== 初始化加载 ==========
onMounted(() => {
// 从 sessionStorage 读取扫码页传递的企业信息
const cached = sessionStorage.getItem('enterpriseScanData');
if (cached) {
try {
const data = JSON.parse(cached);
enterpriseData.value = data;
enterpriseNumber.value = data.enterpriseNumber || '';
qrCodeValid.value = !!data.qrCodeValid;
console.log('企业详情加载成功(来自缓存):', data.enterpriseName);
} catch (e) {
console.error('解析企业缓存数据失败', e);
showFailToast('企业信息解析失败');
}
} else {
showFailToast('缺少企业信息,请重新扫码');
}
});
// ========== 工具方法 ==========
const formatDate = (dateStr) => {
if (!dateStr) return '';
const d = new Date(dateStr);
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
};
// ========== 页面跳转 ==========
const toEnforcementHome = () => {
router.push({ path: '/enforcement/enforcementHome' });
};
const toSign = () => {
router.push({
path: '/sign',
query: {
enterpriseNumber: enterpriseNumber.value,
reason: route?.query?.reason || '',
checkCss: route?.query?.checkCss || '',
isNoScan: route?.query?.isNoScan || 'false',
},
});
};
</script>
<style lang="less" scoped>
.home {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
background-color: #ebf3fb;
.warp_body {
position: relative;
flex: 1;
overflow-y: auto;
background-image: linear-gradient(to bottom, #ebf3fb, transparent);
}
.white-body {
margin: 0 3%;
width: 94%;
min-height: 100vh;
background-color: #fff;
border-radius: 0.27rem;
}
}
.tohome {
position: absolute;
top: 1.25%;
right: 5%;
font-size: 0.5rem;
z-index: 10;
}
.tabs {
padding: 3% 3% 0;
width: 94%;
height: 1.25rem;
box-sizing: content-box;
}
.tabs ul {
display: flex;
width: 100%;
height: 100%;
font-size: 0.4rem;
line-height: 1.25rem;
text-align: center;
align-content: center;
justify-items: center;
}
.tabs ul li {
float: left;
width: 50%;
height: 100%;
cursor: pointer;
}
.tabs ul li span {
display: block;
width: 100%;
height: 100%;
color: #4aa1f9;
background: #e6f0fd;
border-radius: 0.15rem;
}
.tabs ul li.active span {
background: linear-gradient(135deg, #3b82f6, #2563eb);
color: #fff;
}
.tab-content {
padding: 0.3rem;
}
.enterprise-info {
:deep(.van-cell) {
padding: 0.25rem 0.35rem;
font-size: 0.35rem;
}
:deep(.van-cell__title) {
color: #999;
flex: none;
width: 2.5rem;
}
:deep(.van-cell__value) {
color: #333;
}
:deep(.van-cell__label) {
color: #666;
font-size: 0.32rem;
line-height: 1.5;
}
}
.addinfo {
position: absolute;
bottom: 3%;
right: 2%;
z-index: 99999;
width: 1.5rem;
height: 1.5rem;
background-color: #1367fe;
border-radius: 50%;
box-shadow: 0 0 0.27rem #1367fe;
color: #fff;
font-size: 0.4rem;
text-align: center;
vertical-align: middle;
padding-top: 0.45rem;
box-sizing: border-box;
}
</style>

38
zdxt-web-client/zdxt-enforcement-code-app/src/views/enforcement/scanEntQRCode.vue

@ -51,6 +51,7 @@ import { ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue';
import { useRouter } from 'vue-router';
import { showFailToast, showSuccessToast, showToast, showConfirmDialog } from 'vant';
import { baseUrl, appEnv } from '@/config/env.js';
import { getEntInfoByQRCode } from '@/api/enforcement/index';
import wx from 'weixin-js-sdk';
const router = useRouter();
@ -92,6 +93,7 @@ const openHtml5QrcodeScanner = async () => {
);
} catch (err) {
console.error('摄像头启动失败', err);
html5QrCode = null; // 启动失败,清除实例,避免销毁时调 stop 报错
showScanner.value = false;
// 摄像头不可用时,提供上传二维码图片的后备方案
showConfirmDialog({
@ -219,24 +221,28 @@ const handleScanResult = (resultStr) => {
console.log('========== 扫码结果处理 ==========');
console.log('原始内容:', resultStr);
if (isHttpLink(resultStr)) {
// HTTP 链接类型(市监二维码)
// TODO: 对接服务端 getEnterpriseInfoBySj 接口
console.log('识别到 HTTP 链接,待对接服务端接口:', resultStr);
showToast('识别到企业链接,服务端接口待对接');
} else {
// JSON 类型(执法码二维码)
try {
const scanObj = JSON.parse(resultStr);
console.log('解析到 JSON 二维码:', scanObj);
// TODO: 对接服务端 checkIsState 接口
// checkIsState(scanObj.salt, scanObj.codeId, (res) => { ... });
showToast('识别到执法码二维码,服务端接口待对接');
} catch (e) {
console.warn('非 JSON 格式,原始内容:', resultStr);
showFailToast('无法识别该二维码');
// 不管解码结果是 HTTP 链接还是纯文本,统一交给后端解析
showToast({ message: '正在查询企业信息...', duration: 0 });
getEntInfoByQRCode(resultStr, (res) => {
showToast({ message: '', duration: 1 }); // 关闭 loading
if (res.code === 200) {
const data = res.data;
console.log('企业信息查询成功:', data);
if (!data.qrCodeValid) {
showFailToast(data.qrCodeMessage || '二维码已过期');
}
// 将企业信息存入 sessionStorage,预览页直接使用,无需再调接口
sessionStorage.setItem('enterpriseScanData', JSON.stringify(data));
// 跳转企业详情预览页
router.push({ path: '/enforcement/enterpriseScanPreview' });
} else {
showFailToast(res.msg || '查询企业信息失败');
}
}, (err) => {
showToast({ message: '', duration: 1 });
console.error('getEntInfoByQRCode 调用失败', err);
showFailToast('查询企业信息失败,请重试');
});
};
const isHttpLink = (url) => {

Loading…
Cancel
Save