8 changed files with 422 additions and 17 deletions
@ -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); |
|||
} |
|||
} |
|||
@ -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> |
|||
Loading…
Reference in new issue