feat(sip): 添加代理商查询和二维码生成功能

- 新增代理商查询页面和相关接口
- 添加生成代理商二维码的功能
- 优化服务页面布局,增加响应式设计
- 引入 Hutool 和 Google ZXing 依赖
master
chenhao 2025-07-10 17:53:44 +08:00
parent 3e3fe5be8d
commit 903bdd41d9
7 changed files with 367 additions and 175 deletions

View File

@ -90,6 +90,49 @@
width: 80px; width: 80px;
text-align: center; text-align: center;
} }
@media (max-width: 768px) {
.tableBOx {
width: 100%;
}
.container,.topBox{
display: none;
}
.table-striped thead {
display: none; /* 隐藏表头 */
}
.table-striped tbody tr {
display: flex;
flex-direction: column;
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
}
.table-striped tbody td {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
border-bottom: 1px solid #eee;
}
/*.table-striped tbody tr td:first-child {*/
/* font-weight: bold;*/
/* min-width: 100px;*/
/* max-width: 120px;*/
/*}*/
/* 新增样式:为每个 td 添加伪元素来显示表头 */
.table-striped tbody tr td::before {
content: attr(data-th); /* 使用 data-th 属性来显示表头 */
font-weight: bold;
display: inline-block;
min-width: 100px;
max-width: 100px;
margin-right: 10px;
}
}
</style> </style>
</head> </head>
<body class="gray-bg"> <body class="gray-bg">
@ -101,7 +144,7 @@
<div class="container"> <div class="container">
<div class="form-group"> <div class="form-group">
<label for="serialNumber">序列号</label> <label for="serialNumber">序列号</label>
<input type="text" id="serialNumber" placeholder="请输入产品序列号"> <input type="text" th:value="${code}" id="serialNumber" placeholder="请输入产品序列号">
</div> </div>
<button type="button" onclick="getData()">查询</button> <button type="button" onclick="getData()">查询</button>
@ -163,6 +206,7 @@
<script> <script>
$(function() { $(function() {
getData()
}); });
function getData() { function getData() {
@ -173,11 +217,11 @@
str=`` str=``
res.data.forEach((ele)=>{ res.data.forEach((ele)=>{
str+=`<tr> str+=`<tr>
<td>${ele.serialNumber}</td> <td data-th="序列号">${ele.serialNumber}</td>
<td>${ele.productCode}</td> <td data-th="产品编码">${ele.productCode}</td>
<td>${ele.description}</td> <td data-th="产品描述">${ele.description}</td>
<td>${ele.productName}</td> <td data-th="产品名称">${ele.productName}</td>
<td>CN</td> <td data-th="区域">CN</td>
</tr>` </tr>`
}) })
} }
@ -189,15 +233,15 @@
str=`` str=``
res.data.forEach((ele)=>{ res.data.forEach((ele)=>{
str+=`<tr> str+=`<tr>
<td>${ele.orderCode}</td> <td data-th="合同识别号">${ele.orderCode}</td>
<td>${ele.versionCode}</td> <td data-th="版本号">${ele.versionCode}</td>
<td>${ele.orderName}</td> <td data-th="合同名称">${ele.orderName}</td>
<td>${ele.saleName}</td> <td data-th="销售人员姓名">${ele.saleName || ''}</td>
<td>${ele.saleEmail}</td> <td data-th="销售人员邮箱">${ele.saleEmail || ''}</td>
<td>${ele.customerName}</td> <td data-th="最终客户名称">${ele.customerName || ''}</td>
<td>${ele.contactPerson}</td> <td data-th="联系人">${ele.contactPerson || ''}</td>
<td>${ele.contactPhone}</td> <td data-th="电话">${ele.contactPhone || ''}</td>
<td>${ele.contactEmail}</td> <td data-th="客户邮箱">${ele.contactEmail || ''}</td>
</tr>` </tr>`
}) })
} }
@ -209,11 +253,11 @@
str=`` str=``
res.data.forEach((ele)=>{ res.data.forEach((ele)=>{
str+=`<tr> str+=`<tr>
<td>${ele.serviceLevel}</td> <td data-th="服务项">${ele.serviceLevel}</td>
<td>${ele.serviceDescribe}</td> <td data-th="服务项描述">${ele.serviceDescribe}</td>
<td>${ele.serviceStartTime}</td> <td data-th="开始时间">${ele.serviceStartTime}</td>
<td>${ele.serviceEndTime}</td> <td data-th="结束时间">${ele.serviceEndTime}</td>
<td>有效</td> <td data-th="状态">有效</td>
</tr>` </tr>`
}) })
} }

View File

@ -84,9 +84,12 @@
<script th:inline="javascript"> <script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('system:partner:edit')}]]; var editFlag = [[${@permission.hasPermi('system:partner:edit')}]];
var removeFlag = [[${@permission.hasPermi('system:partner:remove')}]]; var removeFlag = [[${@permission.hasPermi('system:partner:remove')}]];
var qrCodeFlag = [[${@permission.hasPermi('system:partner:qrCode')}]];
var levelDatas = [[${@dict.getType('identify_level')}]]; var levelDatas = [[${@dict.getType('identify_level')}]];
var prefix = ctx + "system/partner"; var prefix = ctx + "system/partner";
function generatedQrCode(id){
window.location.href = prefix + `/qr/code?id=` +id;
}
$(function() { $(function() {
var options = { var options = {
url: prefix + "/list", url: prefix + "/list",
@ -154,13 +157,14 @@
title: '创建时间' title: '创建时间'
}, },
{ {
width:150, width:170,
title: '操作', title: '操作',
align: 'center', align: 'center',
formatter: function(value, row, index) { formatter: function(value, row, index) {
var actions = []; var actions = [];
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> '); actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a>'); actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.id + '\')"><i class="fa fa-remove"></i>删除</a>');
actions.push('<a style="margin-left: 5px" class="btn btn-info btn-xs '+qrCodeFlag+' " href="javascript:void(0)" onclick="generatedQrCode(\'' + row.id + '\')"><i class="fa fa-remove"></i>生成二维码</a>');
return actions.join(''); return actions.join('');
} }
}] }]

View File

@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header('代理商查询')" />
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f9f9f9;
}
.container {
/*width: 100%;*/
margin: 0;
padding: 10px 0;
background-color: white;
border-radius: 8px;
display: flex;
flex-direction: row;
gap: 30px;
justify-content: center;
}
h1 {
text-align: center;
color: #e74c3c;
}
.form-group {
margin-bottom: 15px;
display: flex;
flex-direction: row;
align-items: center;
}
.tableBOx{
width:70vw;
}
label {
margin-bottom: 0;
width: 80px;
font-weight: 600;
}
input[type="text"] {
width: 100%;
padding:5px 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
width:100px;
padding:0;
height: 30px;
background-color: #1c84c6;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
border-color: #1a7bb9;
}
.topBox{
display: flex;
flex-direction: row;
gap: 20px;
margin: 30px 0 10px;
align-items: center;
}
.topBox .title{
font-size: 24px;
font-weight: 600;
}
.table-striped {
display: flex;justify-content: flex-start;flex-direction: column;align-items: center
}
.table-striped thead{
background: #f5f5f5 !important;
}
.table-striped thead th{
padding: 10px;
}
.table-striped tbody td{
padding: 10px;
}
.tabBtn{
display: inline-block;
padding:8px 10px;
cursor: pointer;
width: 80px;
text-align: center;
}
.form-group label{
width: 100px;
}
@media (max-width: 768px) {
.tableBOx {
width: 100%;
}
.container,.topBox{
display: none;
}
.table-striped thead {
display: none; /* 隐藏表头 */
}
.table-striped tbody tr {
display: flex;
flex-direction: column;
border-bottom: 1px solid #ddd;
margin-bottom: 10px;
}
.table-striped tbody td {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
border-bottom: 1px solid #eee;
}
/*.table-striped tbody tr td:first-child {*/
/* font-weight: bold;*/
/* min-width: 100px;*/
/* max-width: 120px;*/
/*}*/
/* 新增样式:为每个 td 添加伪元素来显示表头 */
.table-striped tbody tr td::before {
content: attr(data-th); /* 使用 data-th 属性来显示表头 */
font-weight: bold;
display: inline-block;
min-width: 100px;
max-width: 100px;
margin-right: 10px;
}
}
</style>
</head>
<body class="gray-bg">
<div class="col-sm-12 select-table table-striped" >
<div class="topBox">
<div class="title">代理商查询 </div>
<!-- <div style="color: #dd242a">H3C产品保修条款</div>-->
</div>
<div class="container">
<div class="form-group">
<label for="partnerCode">代理商代码</label>
<input type="text" th:value="${code}" id="partnerCode" placeholder="请输入代理商代码">
</div>
<button type="button" onclick="getData()">查询</button>
</div>
<div style="font-size: 20px;text-align: left;width: 70vw;margin: 10px 0">查询结果</div>
<div style="font-size: 16px;text-align: left;width: 70vw;font-weight: 600;"><blockquote style="border-left-color: #1c84c6">代理商信息</blockquote> </div>
<div style="width: 70svw;overflow-x: auto">
<table class="tableBOx" id="tableBOx">
<thead>
<tr>
<th style="min-width: 100px">代理商编码</th>
<th style="min-width: 100px">代理商名称</th>
<th style="min-width: 100px"></th>
<th style="min-width: 100px"></th>
<th style="min-width: 100px">详细地址</th>
<th style="min-width: 100px">联系人</th>
<th style="min-width: 100px">联系电话</th>
<th style="min-width: 100px">认证级别</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javaScript">
var prefix = ctx + "system/partner";
$(function() {
getData()
});
function getData() {
let partnerCode = $('#partnerCode').val()
$.operate.get(`/system/partner/list/query?partnerCode=${partnerCode}`, function (res) {
let str = `<tr><td colspan="8" style="text-align: center">暂无数据</td></tr>`
if (res.data.length) {
str = ``
res.data.forEach((ele) => {
str += `<tr>
<td data-th="代理商编码">${ele.partnerCode}</td>
<td data-th="代理商名称">${ele.partnerName}</td>
<td data-th="省">${ele.province}</td>
<td data-th="市">${ele.city}</td>
<td data-th="地址">${ele.address}</td>
<td data-th="联系人">${ele.contactPerson}</td>
<td data-th="联系电话">${ele.contactPhone}</td>
<td data-th="认证级别">${ele.levelName}</td>
</tr>`
})
}
$('#tableBOx tbody').html(str)
})
}
</script>
</body>
</html>

View File

@ -35,5 +35,14 @@
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId> <artifactId>hutool-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -13,8 +13,10 @@ import com.ruoyi.sip.service.IProductInfoService;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
/** /**
@ -45,8 +47,9 @@ public class MaintenanceController {
@Anonymous @Anonymous
@GetMapping() @GetMapping()
public String service() public String service(@RequestParam(value = "code",required = false)String code, ModelMap modelMap)
{ {
modelMap.put("code",code);
return prefix + "/service"; return prefix + "/service";
} }

View File

@ -1,15 +1,25 @@
package com.ruoyi.sip.controller; package com.ruoyi.sip.controller;
import java.io.File;
import java.util.Collections;
import java.util.List; import java.util.List;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.google.zxing.qrcode.encoder.QRCode;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.sip.domain.PartnerInfo; import com.ruoyi.sip.domain.PartnerInfo;
@ -19,6 +29,9 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** /**
* Controller * Controller
* *
@ -27,6 +40,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
*/ */
@Controller @Controller
@RequestMapping("/system/partner") @RequestMapping("/system/partner")
@Slf4j
public class PartnerInfoController extends BaseController public class PartnerInfoController extends BaseController
{ {
private String prefix = "system/partner"; private String prefix = "system/partner";
@ -125,4 +139,48 @@ public class PartnerInfoController extends BaseController
{ {
return toAjax(partnerInfoService.deletePartnerInfoByIds(ids)); return toAjax(partnerInfoService.deletePartnerInfoByIds(ids));
} }
@GetMapping("/query")
@Anonymous
public String partnerQuery(@RequestParam(value = "code",required = false)String code,ModelMap modelMap)
{
modelMap.put("code",code);
return prefix + "/partnerQuery";
}
@GetMapping("/list/query")
@ResponseBody
@Anonymous
public AjaxResult listQuery(PartnerInfo partnerInfo)
{
if (StringUtils.isEmpty(partnerInfo.getPartnerCode())){
return AjaxResult.success(Collections.emptyList());
}
List<PartnerInfo> list = partnerInfoService.selectPartnerInfoList(partnerInfo);
for (PartnerInfo info : list) {
info.setLevelName(DictUtils.getDictLabel("identify_level",info.getLevel()));
}
return AjaxResult.success(list);
}
@GetMapping("/qr/code")
public void download(@RequestParam("id") Long id, HttpServletRequest request, HttpServletResponse response) {
try {
PartnerInfo partnerInfo = partnerInfoService.selectPartnerInfoById(id);
String localPath = RuoYiConfig.getProfile();
String filePath = localPath + File.separator +"partner"+ File.separator +partnerInfo.getPartnerCode()+".jpg";
if (!FileUtil.exist(filePath)){
new File(filePath).createNewFile();
}
StringBuilder url=new StringBuilder();
url.append("http://oms.unissense.top")
.append("/system/partner/query?code=")
.append(partnerInfo.getPartnerCode());
QrCodeUtil.generate(url.toString(), 300, 300, FileUtil.file(filePath));
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, partnerInfo.getPartnerCode()+".jpg");
FileUtils.writeBytes(filePath, response.getOutputStream());
} catch (Exception e) {
log.error("下载文件失败", e);
}
}
} }

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.domain;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel;
@ -13,6 +14,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
* @author mula * @author mula
* @date 2025-04-30 * @date 2025-04-30
*/ */
@Data
public class PartnerInfo extends BaseEntity public class PartnerInfo extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -51,6 +53,7 @@ public class PartnerInfo extends BaseEntity
/** 认证级别 */ /** 认证级别 */
@Excel(name = "认证级别") @Excel(name = "认证级别")
private String level; private String level;
private String levelName;
/** */ /** */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@ -66,152 +69,5 @@ public class PartnerInfo extends BaseEntity
/** */ /** */
private Integer status; private Integer status;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setPartnerCode(String partnerCode)
{
this.partnerCode = partnerCode;
}
public String getPartnerCode()
{
return partnerCode;
}
public void setPartnerName(String partnerName)
{
this.partnerName = partnerName;
}
public String getPartnerName()
{
return partnerName;
}
public void setProvince(String province)
{
this.province = province;
}
public String getProvince()
{
return province;
}
public void setCity(String city)
{
this.city = city;
}
public String getCity()
{
return city;
}
public void setAddress(String address)
{
this.address = address;
}
public String getAddress()
{
return address;
}
public void setContactPerson(String contactPerson)
{
this.contactPerson = contactPerson;
}
public String getContactPerson()
{
return contactPerson;
}
public void setContactPhone(String contactPhone)
{
this.contactPhone = contactPhone;
}
public String getContactPhone()
{
return contactPhone;
}
public void setLevel(String level)
{
this.level = level;
}
public String getLevel()
{
return level;
}
public void setCreateAt(Date createAt)
{
this.createAt = createAt;
}
public Date getCreateAt()
{
return createAt;
}
public void setUpdateAt(Date updateAt)
{
this.updateAt = updateAt;
}
public Date getUpdateAt()
{
return updateAt;
}
public void setDeleteAt(Date deleteAt)
{
this.deleteAt = deleteAt;
}
public Date getDeleteAt()
{
return deleteAt;
}
public void setStatus(Integer status)
{
this.status = status;
}
public Integer getStatus()
{
return status;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("partnerCode", getPartnerCode())
.append("partnerName", getPartnerName())
.append("province", getProvince())
.append("city", getCity())
.append("address", getAddress())
.append("contactPerson", getContactPerson())
.append("contactPhone", getContactPhone())
.append("level", getLevel())
.append("createAt", getCreateAt())
.append("updateAt", getUpdateAt())
.append("deleteAt", getDeleteAt())
.append("status", getStatus())
.toString();
}
} }