Merge remote-tracking branch 'origin/master'
# Conflicts: # dl_admin/ruoyi-common/src/main/java/com/ruoyi/common/utils/GoogleRankUtil.java
This commit is contained in:
commit
17c620d530
@ -115,6 +115,9 @@ public class BaseSiteController extends BaseController {
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids) {
|
||||
List<String> list = new ArrayList<>(Arrays.asList(ids));
|
||||
if (list.contains("main")){
|
||||
return error("请勿删除主站点");
|
||||
}
|
||||
return toAjax(baseSiteService.removeByIds(list));
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,10 +21,12 @@ import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysDictDataService;
|
||||
import com.ruoyi.utils.OssUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
@ -64,6 +66,8 @@ public class WebController extends BaseController {
|
||||
@Autowired
|
||||
private IBusiChatMainService busiChatMainService;
|
||||
@Autowired
|
||||
private IBusiThirdItemService busiThirdItemService;
|
||||
@Autowired
|
||||
private IBusiPageService pageService;
|
||||
@Autowired
|
||||
private CommonUtils commonUtils;
|
||||
@ -73,6 +77,8 @@ public class WebController extends BaseController {
|
||||
private IBaseAppService appService;
|
||||
@Autowired
|
||||
private GoogleConfig googleConfig;
|
||||
@Autowired
|
||||
private OssUtil ossUtil;
|
||||
|
||||
/**
|
||||
* 导航栏接口--所有分类
|
||||
@ -170,10 +176,13 @@ public class WebController extends BaseController {
|
||||
* @date 10:04 2025/7/8
|
||||
**/
|
||||
@ApiOperation("热门产品-前10")
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParams(value = {
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/hotProduct")
|
||||
public R<List<BusiProdNew>> hotProduct(@RequestParam(required = true) String tenantId) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_PRODUCT, true));
|
||||
public R<List<BusiProdNew>> hotProduct(@RequestParam(required = true) String tenantId,@RequestParam(required = true) String showPlat) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_PRODUCT, true,showPlat));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,10 +193,13 @@ public class WebController extends BaseController {
|
||||
* @date 10:04 2025/7/8
|
||||
**/
|
||||
@ApiOperation("普通产品-前10")
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParams(value = {
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/product")
|
||||
public R<List<BusiProdNew>> product(@RequestParam(required = true) String tenantId) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_PRODUCT, false));
|
||||
public R<List<BusiProdNew>> product(@RequestParam(required = true) String tenantId,@RequestParam(required = true) String showPlat) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_PRODUCT, false,showPlat));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,10 +210,13 @@ public class WebController extends BaseController {
|
||||
* @date 10:04 2025/7/8
|
||||
**/
|
||||
@ApiOperation("热门新闻-前10")
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParams(value = {
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/hotNews")
|
||||
public R<List<BusiProdNew>> hotNews(@RequestParam(required = true) String tenantId) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_NEWS, true));
|
||||
public R<List<BusiProdNew>> hotNews(@RequestParam(required = true) String tenantId,@RequestParam(required = true) String showPlat) {
|
||||
return R.ok(prodNewService.hotProdOrNews(tenantId, DATA_TYPE_NEWS, true,showPlat));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,16 +250,18 @@ public class WebController extends BaseController {
|
||||
@ApiImplicitParam(name = "pageNum", value = "页码(1开始)", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示数量", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "catgId", value = "分类id", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/prodPageList")
|
||||
public R<IPage<BusiProdNew>> prodPageList(String tenantId, String catgId, String text,
|
||||
public R<IPage<BusiProdNew>> prodPageList(String tenantId, @RequestParam(required = false) String catgId, @RequestParam(required = false) String text,String showPlat,
|
||||
@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||
Page<BusiProdNew> page = new Page<>(pageNum, pageSize);
|
||||
LambdaQueryWrapper<BusiProdNew> queryWrapper = new LambdaQueryWrapper<BusiProdNew>()
|
||||
.eq(BusiProdNew::getDataType, DATA_TYPE_PRODUCT)
|
||||
.eq(BusiProdNew::getIfPublic, true)
|
||||
.like(BusiProdNew::getShowPlat,showPlat)
|
||||
.eq(BusiProdNew::getTenantId, tenantId);
|
||||
if (StringUtils.isNotEmpty(text)) {
|
||||
queryWrapper.and(wq -> wq
|
||||
@ -289,16 +306,18 @@ public class WebController extends BaseController {
|
||||
@ApiImplicitParam(name = "pageNum", value = "页码(1开始)", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示数量", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "catgId", value = "分类id", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = false, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/newsPageList")
|
||||
public R<IPage<BusiProdNew>> newsPageList(String tenantId, String catgId, String text,
|
||||
public R<IPage<BusiProdNew>> newsPageList(String tenantId, @RequestParam(required = false) String catgId, @RequestParam(required = false) String text,String showPlat,
|
||||
@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||
Page<BusiProdNew> page = new Page<>(pageNum, pageSize);
|
||||
LambdaQueryWrapper<BusiProdNew> queryWrapper = new LambdaQueryWrapper<BusiProdNew>()
|
||||
.eq(BusiProdNew::getDataType, DATA_TYPE_NEWS)
|
||||
.eq(BusiProdNew::getIfPublic, true)
|
||||
.like(BusiProdNew::getShowPlat,showPlat)
|
||||
.eq(BusiProdNew::getTenantId, tenantId);
|
||||
if (StringUtils.isNotEmpty(text)) {
|
||||
queryWrapper.and(wq -> wq
|
||||
@ -352,14 +371,15 @@ public class WebController extends BaseController {
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "pageNum", value = "页码(1开始)", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示数量", required = true, dataType = "int", paramType = "query", dataTypeClass = Integer.class),
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@ApiImplicitParam(name = "text", value = "搜索内容", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class),
|
||||
@ApiImplicitParam(name = "showPlat", value = "平台标识(网站|App)", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
})
|
||||
@GetMapping("/searchText")
|
||||
public R<IPage<BusiProdNew>> searchText(String tenantId, String text,
|
||||
public R<IPage<BusiProdNew>> searchText(String tenantId, String text,String showPlat,
|
||||
@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||
Page<BusiProdNew> page = new Page<>(pageNum, pageSize);
|
||||
return R.ok(prodNewService.searchTextAll(tenantId, text, page));
|
||||
return R.ok(prodNewService.searchTextAll(tenantId, text, page,showPlat));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,7 +393,6 @@ public class WebController extends BaseController {
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点唯一码", required = true, dataType = "string", paramType = "query", dataTypeClass = String.class)
|
||||
@GetMapping("/inquirySet")
|
||||
public R<BaseInquiry> inquirySet(@RequestParam(required = true) String tenantId, HttpServletRequest request) {
|
||||
String ip = CommonUtils.getIpAddr(request);
|
||||
return R.ok(baseInquiryService.getInquiry(tenantId));
|
||||
}
|
||||
|
||||
@ -459,46 +478,17 @@ public class WebController extends BaseController {
|
||||
return R.ok(appService.selectNewApp());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@ApiOperation("下载APK文件")
|
||||
@GetMapping("/downloadApk")
|
||||
public void downloadApk(HttpServletResponse response) {
|
||||
try {
|
||||
// APK文件路径
|
||||
File file = new File(googleConfig.getAppDownload());
|
||||
|
||||
// 检查文件是否存在
|
||||
if (!file.exists()) {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
response.getWriter().write("文件不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.android.package-archive");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=truck.apk");
|
||||
response.setHeader("Content-Length", String.valueOf(file.length()));
|
||||
|
||||
// 写入响应流
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
OutputStream os = response.getOutputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
fis.close();
|
||||
os.flush();
|
||||
os.close();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
response.getWriter().write("文件下载失败: " + e.getMessage());
|
||||
} catch (Exception ex) {
|
||||
logger.error("下载APK文件时发生错误", ex);
|
||||
}
|
||||
public void downloadApk(HttpServletResponse response,@RequestParam(required = false) String id) {
|
||||
BaseApp appVersion;
|
||||
if(StringUtils.isNotEmpty(id)){
|
||||
appVersion = appService.getById(id);
|
||||
}else{
|
||||
appVersion = appService.selectNewApp();
|
||||
}
|
||||
ossUtil.downloadFile(response, appVersion.getApkUrl(), appVersion.getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,4 +516,27 @@ public class WebController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 三方询盘点击记录次数
|
||||
*
|
||||
* @return com.ruoyi.common.core.domain.AjaxResult
|
||||
* @author vinjor-M
|
||||
* @date 10:04 2025/7/8
|
||||
**/
|
||||
@ApiOperation("三方询盘点击记录次数")
|
||||
@ApiImplicitParams(value = {
|
||||
@ApiImplicitParam(name = "thirdSoft", value = "三方程序类型(Email|WhatsApp|Tel)", required = true, paramType = "body"),
|
||||
@ApiImplicitParam(name = "tenantId", value = "站点编码", required = true, paramType = "body"),
|
||||
@ApiImplicitParam(name = "equipment", value = "设备类型(移动端|电脑端)", required = true, paramType = "body")
|
||||
})
|
||||
@PostMapping("/thirdItemSave")
|
||||
public R<String> thirdItemSave(@ApiIgnore @RequestBody BusiThirdItem thirdItem, HttpServletRequest request) {
|
||||
thirdItem.setViewType("漂浮询盘");
|
||||
Map<String, String> ipMap = commonUtils.getIPAndCountry(request);
|
||||
thirdItem.setIp(ipMap.get("ip"));
|
||||
thirdItem.setNational(ipMap.get("national"));
|
||||
thirdItem.setOceania(ipMap.get("oceania"));
|
||||
busiThirdItemService.save(thirdItem);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,10 @@ public class BaseApp extends DlBaseEntity
|
||||
@Excel(name = "版本")
|
||||
private String version;
|
||||
|
||||
/** app包下载地址 */
|
||||
@Excel(name = "app包下载地址")
|
||||
private String apkUrl;
|
||||
|
||||
/** 本次升级描述 */
|
||||
@Excel(name = "本次升级描述")
|
||||
private String content;
|
||||
|
||||
@ -3,10 +3,12 @@ package com.ruoyi.base.service.impl;
|
||||
import java.util.List;
|
||||
|
||||
import com.ruoyi.base.vo.SiteVO;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@ -25,6 +27,8 @@ public class BaseSiteServiceImpl extends ServiceImpl<BaseSiteMapper,BaseSite> i
|
||||
{
|
||||
@Autowired
|
||||
private BaseSiteMapper baseSiteMapper;
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
@Override
|
||||
public IPage<SiteVO> queryListPage(BaseSite pageReqVO, Page<BaseSite> page) {
|
||||
@ -45,6 +49,13 @@ public class BaseSiteServiceImpl extends ServiceImpl<BaseSiteMapper,BaseSite> i
|
||||
//超级管理员,查所有站点
|
||||
return this.list();
|
||||
}
|
||||
return baseSiteMapper.selectByUserId(userId);
|
||||
List<BaseSite> managerList = baseSiteMapper.selectByUserId(userId);
|
||||
if(managerList.isEmpty()){
|
||||
//没有管理权限的站点,查当前用户所属的站点
|
||||
SysUser user = sysUserService.selectUserById(userId);
|
||||
BaseSite site = this.getById(user.getTenantId());
|
||||
managerList.add(site);
|
||||
}
|
||||
return managerList;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.busi.domain.BusiChatItem;
|
||||
import com.ruoyi.busi.service.IBusiChatItemService;
|
||||
import com.ruoyi.busi.vo.ChatExcelMainVO;
|
||||
import com.ruoyi.busi.vo.ChatMainVO;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
@ -66,10 +67,12 @@ public class BusiChatMainController extends BaseController
|
||||
@PreAuthorize("@ss.hasPermi('busi:chatMain:export')")
|
||||
@Log(title = "在线聊天", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, BusiChatMain busiChatMain)
|
||||
public void export(HttpServletResponse response, ChatMainVO busiChatMain)
|
||||
{
|
||||
List<BusiChatMain> list = busiChatMainService.list();
|
||||
ExcelUtil<BusiChatMain> util = new ExcelUtil<BusiChatMain>(BusiChatMain.class);
|
||||
// List<BusiChatMain> list = busiChatMainService.list();
|
||||
// ExcelUtil<BusiChatMain> util = new ExcelUtil<BusiChatMain>(BusiChatMain.class);
|
||||
List<ChatExcelMainVO> list = busiChatMainService.listChatMain(busiChatMain);
|
||||
ExcelUtil<ChatExcelMainVO> util = new ExcelUtil<ChatExcelMainVO>(ChatExcelMainVO.class);
|
||||
util.exportExcel(response, list, "在线聊天数据");
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.base.service.IBasePicsService;
|
||||
import com.ruoyi.busi.domain.BusiProdNew;
|
||||
import com.ruoyi.busi.domain.BusiProdRandom;
|
||||
import com.ruoyi.busi.domain.BusiRelation;
|
||||
import com.ruoyi.busi.service.IBusiProdNewService;
|
||||
import com.ruoyi.busi.service.IBusiProdRandomService;
|
||||
import com.ruoyi.busi.service.IBusiRelationService;
|
||||
import com.ruoyi.busi.utils.SimHash;
|
||||
import com.ruoyi.busi.utils.TextPreprocessor;
|
||||
import com.ruoyi.busi.vo.ProdNewVO;
|
||||
@ -15,6 +17,7 @@ import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@ -43,6 +46,8 @@ public class BusiNewController extends BaseController
|
||||
private IBasePicsService basePicsService;
|
||||
@Autowired
|
||||
private IBusiProdRandomService prodRandomService;
|
||||
@Autowired
|
||||
private IBusiRelationService relationService;
|
||||
|
||||
/**
|
||||
* 查询新闻列表
|
||||
@ -121,6 +126,13 @@ public class BusiNewController extends BaseController
|
||||
});
|
||||
basePicsService.saveBatch(prodNewVO.getFileList());
|
||||
}
|
||||
//默认负责人就是当前用户
|
||||
BusiRelation relation = new BusiRelation();
|
||||
relation.setUserId(SecurityUtils.getUserId());
|
||||
relation.setProdId(prodNewVO.getId());
|
||||
relation.setTenantId(prodNewVO.getTenantId());
|
||||
relationService.save(relation);
|
||||
|
||||
busiProdNewService.setAmount(prodNewVO.getTenantId());
|
||||
return success();
|
||||
}
|
||||
|
||||
@ -10,11 +10,14 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.base.service.IBasePicsService;
|
||||
import com.ruoyi.busi.domain.BusiProdRandom;
|
||||
import com.ruoyi.busi.domain.BusiRelation;
|
||||
import com.ruoyi.busi.service.IBusiProdRandomService;
|
||||
import com.ruoyi.busi.service.IBusiRelationService;
|
||||
import com.ruoyi.busi.utils.SimHash;
|
||||
import com.ruoyi.busi.utils.TextPreprocessor;
|
||||
import com.ruoyi.busi.vo.ProdNewVO;
|
||||
import com.ruoyi.busi.vo.ProdRandomVO;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -54,6 +57,8 @@ public class BusiProdController extends BaseController
|
||||
private IBasePicsService basePicsService;
|
||||
@Autowired
|
||||
private IBusiProdRandomService prodRandomService;
|
||||
@Autowired
|
||||
private IBusiRelationService relationService;
|
||||
|
||||
/**
|
||||
* 查询产品列表
|
||||
@ -132,6 +137,13 @@ public class BusiProdController extends BaseController
|
||||
});
|
||||
basePicsService.saveBatch(prodNewVO.getFileList());
|
||||
}
|
||||
//默认负责人就是当前用户
|
||||
BusiRelation relation = new BusiRelation();
|
||||
relation.setUserId(SecurityUtils.getUserId());
|
||||
relation.setProdId(prodNewVO.getId());
|
||||
relation.setTenantId(prodNewVO.getTenantId());
|
||||
relationService.save(relation);
|
||||
|
||||
busiProdNewService.setAmount(prodNewVO.getTenantId());
|
||||
return success();
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ public class BusiRelationController extends BaseController
|
||||
List<BusiRelation> busiRelationList = new ArrayList<>();
|
||||
userIdList.forEach(item->{
|
||||
BusiRelation relation = new BusiRelation();
|
||||
relation.setUserId(item);
|
||||
relation.setUserId(Long.valueOf(item));
|
||||
relation.setProdId(busiRelation.getProdId());
|
||||
relation.setTenantId(busiRelation.getTenantId());
|
||||
busiRelationList.add(relation);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.ruoyi.busi.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
@ -70,9 +71,15 @@ public class BusiProdNew extends DlBaseEntity
|
||||
@ApiModelProperty("文章来源")
|
||||
private String newsFrom;
|
||||
|
||||
/** 展示平台(PC、APP) */
|
||||
@Excel(name = "展示平台(PC、APP)")
|
||||
@ApiModelProperty("展示平台(PC、APP)")
|
||||
private String showPlat;
|
||||
|
||||
/** 文章发布日期 */
|
||||
@Excel(name = "文章发布日期")
|
||||
@ApiModelProperty("文章发布日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date publicDate;
|
||||
|
||||
/** 产品主图或文章图片 */
|
||||
|
||||
@ -30,7 +30,7 @@ public class BusiRelation extends DlBaseEntity
|
||||
|
||||
/** 用户id */
|
||||
@Excel(name = "用户id")
|
||||
private String userId;
|
||||
private Long userId;
|
||||
|
||||
/** 产品、新闻id */
|
||||
@Excel(name = "产品、新闻id")
|
||||
|
||||
@ -39,6 +39,9 @@ public class BusiThirdItem extends DlBaseEntity
|
||||
/** 来源国家 */
|
||||
@Excel(name = "来源国家")
|
||||
private String national;
|
||||
/** 来源洲 */
|
||||
@Excel(name = "来源洲")
|
||||
private String oceania;
|
||||
|
||||
/** 所属email/电话/teams账户 */
|
||||
@Excel(name = "所属email/电话/teams账户")
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.busi.domain.BusiChatMain;
|
||||
import com.ruoyi.busi.vo.ChartDataVO;
|
||||
import com.ruoyi.busi.vo.ChatExcelMainVO;
|
||||
import com.ruoyi.busi.vo.ChatMainVO;
|
||||
import com.ruoyi.busi.vo.ThirdSoftVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
@ -22,6 +23,8 @@ public interface BusiChatMainMapper extends BaseMapper<BusiChatMain>
|
||||
{
|
||||
IPage<ChatMainVO> queryListPage(@Param("entity") ChatMainVO entity, Page<BusiChatMain> page);
|
||||
|
||||
List<ChatExcelMainVO> selectChatList(@Param("entity") BusiChatMain entity);
|
||||
|
||||
/**
|
||||
* 查询IP数量
|
||||
* @author vinjor-M
|
||||
|
||||
@ -24,7 +24,7 @@ public interface BusiKeywordItemMapper extends BaseMapper<BusiKeywordItem>
|
||||
{
|
||||
IPage<BusiKeywordItem> queryListPage(@Param("entity") BusiKeywordItem entity, Page<BusiKeywordItem> page);
|
||||
|
||||
int deleteBySelectDateInt(@Param("date") String date);
|
||||
int deleteBySelectDateInt(@Param("date") String date,@Param("title") String title);
|
||||
|
||||
/**
|
||||
* 分页查询关键词基础信息
|
||||
|
||||
@ -26,4 +26,5 @@ public interface BusiKeywordMapper extends BaseMapper<BusiKeyword>
|
||||
**/
|
||||
Date selectNewDate();
|
||||
|
||||
void deleteByIdAndTenantId(@Param("id") String item, @Param("tenantId") String tenantId);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.ruoyi.busi.domain.BusiChatMain;
|
||||
import com.ruoyi.busi.vo.ChatExcelMainVO;
|
||||
import com.ruoyi.busi.vo.ChatMainVO;
|
||||
|
||||
/**
|
||||
@ -17,6 +18,15 @@ import com.ruoyi.busi.vo.ChatMainVO;
|
||||
public interface IBusiChatMainService extends IService<BusiChatMain> {
|
||||
IPage<ChatMainVO> queryListPage(ChatMainVO pageReqVO, Page<BusiChatMain> page);
|
||||
|
||||
/**
|
||||
* 不分页查询聊天记录适配导出
|
||||
* @author PQZ
|
||||
* @date 14:03 2025/10/21
|
||||
* @param chatMainVO {@link ChatMainVO}
|
||||
* @return java.util.List<com.ruoyi.busi.vo.ChatMainVO>
|
||||
**/
|
||||
List<ChatExcelMainVO> listChatMain(ChatMainVO chatMainVO);
|
||||
|
||||
/**
|
||||
* 校验是否需要新增
|
||||
*
|
||||
|
||||
@ -13,7 +13,7 @@ import com.ruoyi.busi.vo.BusiKeywordRankStatVO;
|
||||
|
||||
/**
|
||||
* 关键词排名明细Service接口
|
||||
*
|
||||
*
|
||||
* @author vinjor-m
|
||||
* @date 2025-08-21
|
||||
*/
|
||||
@ -26,7 +26,7 @@ public interface IBusiKeywordItemService extends IService<BusiKeywordItem>
|
||||
* @author vinjor-M
|
||||
* @date 15:10 2025/8/21
|
||||
**/
|
||||
void getKeywordRanking();
|
||||
void getKeywordRanking() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* 分页查询关键词排名统计
|
||||
@ -38,7 +38,6 @@ public interface IBusiKeywordItemService extends IService<BusiKeywordItem>
|
||||
|
||||
/**
|
||||
* 统计当天1-10名和11-20名的关键词数量
|
||||
* @param selectDate 选择日期
|
||||
* @param tenantId 租户ID
|
||||
* @return Map形式的统计结果 {key1: 1-10名数量, key2: 11-20名数量}
|
||||
*/
|
||||
|
||||
@ -54,7 +54,7 @@ public interface IBusiProdNewService extends IService<BusiProdNew>
|
||||
* @param tenantId 租户id
|
||||
* @return java.util.List<com.ruoyi.busi.domain.BusiProdNew>
|
||||
**/
|
||||
List<BusiProdNew> hotProdOrNews(String tenantId,String dateType,Boolean ifHot);
|
||||
List<BusiProdNew> hotProdOrNews(String tenantId,String dateType,Boolean ifHot,String showPlat);
|
||||
|
||||
/**
|
||||
* web站点查看详情
|
||||
@ -74,7 +74,7 @@ public interface IBusiProdNewService extends IService<BusiProdNew>
|
||||
* @param page 分页对象
|
||||
* @return com.baomidou.mybatisplus.core.metadata.IPage<com.ruoyi.busi.vo.ProdNewVO>
|
||||
**/
|
||||
IPage<BusiProdNew> searchTextAll(String tenantId, String text,Page<BusiProdNew> page);
|
||||
IPage<BusiProdNew> searchTextAll(String tenantId, String text,Page<BusiProdNew> page,String showPlat);
|
||||
|
||||
/**
|
||||
* 相似度检测
|
||||
|
||||
@ -40,20 +40,18 @@ public class BusiCategoryServiceImpl extends ServiceImpl<BusiCategoryMapper, Bus
|
||||
public List<BusiCategoryVO> treeCategory(BusiCategory category) {
|
||||
//查询全部栏目
|
||||
LambdaQueryWrapper<BusiCategory> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(DlBaseEntity::getDelFlag,0)
|
||||
.eq(BusiCategory::getTenantId,category.getTenantId());
|
||||
if(StringUtils.isNotEmpty(category.getCatgType())){
|
||||
lambdaQueryWrapper.eq(BusiCategory::getCatgType,category.getCatgType());
|
||||
lambdaQueryWrapper.eq(DlBaseEntity::getDelFlag, 0)
|
||||
.eq(BusiCategory::getTenantId, category.getTenantId());
|
||||
if (StringUtils.isNotEmpty(category.getCatgType())) {
|
||||
lambdaQueryWrapper.eq(BusiCategory::getCatgType, category.getCatgType());
|
||||
}
|
||||
if (!StringUtils.isEmpty(category.getCatgName())) {
|
||||
lambdaQueryWrapper.like(BusiCategory::getCatgName, category.getCatgName());
|
||||
}
|
||||
lambdaQueryWrapper.orderByAsc(BusiCategory::getSort);
|
||||
lambdaQueryWrapper.orderByDesc(BusiCategory::getSort);
|
||||
List<BusiCategory> list = list(lambdaQueryWrapper);
|
||||
List<BusiCategoryVO> rtnList = buildCategoryTree(list);
|
||||
return rtnList.stream().sorted(Comparator.comparing(BusiCategoryVO::getSort,
|
||||
Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.collect(Collectors.toList());
|
||||
return rtnList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,12 +150,10 @@ public class BusiCategoryServiceImpl extends ServiceImpl<BusiCategoryMapper, Bus
|
||||
|
||||
|
||||
/**
|
||||
* 生成树结构
|
||||
* 生成树结构(修改版)
|
||||
*
|
||||
* @param list 网站栏目列表
|
||||
* @return java.util.List<com.ruoyi.busi.vo.BusiCategoryVO>
|
||||
* @author PQZ
|
||||
* @date 14:11 2025/6/23
|
||||
**/
|
||||
private List<BusiCategoryVO> buildCategoryTree(List<BusiCategory> list) {
|
||||
// Map存放id到VO的映射
|
||||
@ -165,7 +161,7 @@ public class BusiCategoryServiceImpl extends ServiceImpl<BusiCategoryMapper, Bus
|
||||
// 先将所有节点转换为VO,并放入Map
|
||||
for (BusiCategory category : list) {
|
||||
BusiCategoryVO vo = new BusiCategoryVO();
|
||||
BeanUtils.copyProperties(category,vo);
|
||||
BeanUtils.copyProperties(category, vo);
|
||||
vo.setId(category.getId());
|
||||
vo.setLabel(category.getCatgName());
|
||||
idToNodeMap.put(vo.getId(), vo);
|
||||
@ -183,9 +179,36 @@ public class BusiCategoryServiceImpl extends ServiceImpl<BusiCategoryMapper, Bus
|
||||
parent.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
|
||||
// 对所有层级节点进行排序
|
||||
sortTreeNodes(roots);
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归对树节点进行排序
|
||||
*
|
||||
* @param nodes 节点列表
|
||||
*/
|
||||
private void sortTreeNodes(List<BusiCategoryVO> nodes) {
|
||||
if (nodes == null || nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 对当前层级节点排序
|
||||
nodes.sort(Comparator.comparing(BusiCategoryVO::getSort,
|
||||
Comparator.nullsLast(Comparator.reverseOrder())));
|
||||
|
||||
// 递归对子节点排序
|
||||
for (BusiCategoryVO node : nodes) {
|
||||
if (node.getChildren() != null && !node.getChildren().isEmpty()) {
|
||||
sortTreeNodes(node.getChildren());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param id 查询的栏目ID
|
||||
* @return java.util.List<java.lang.String>
|
||||
@ -207,54 +230,55 @@ public class BusiCategoryServiceImpl extends ServiceImpl<BusiCategoryMapper, Bus
|
||||
**/
|
||||
@Override
|
||||
public List<BusiCategoryVO> dealFirstId(List<BusiCategoryVO> busiCategoryVOList) {
|
||||
busiCategoryVOList.forEach(item->{
|
||||
busiCategoryVOList.forEach(item -> {
|
||||
String thisMaxParentId = item.getId();
|
||||
item.setMaxParentId(thisMaxParentId);
|
||||
if(null!=item.getChildren() && !item.getChildren().isEmpty()){
|
||||
if (null != item.getChildren() && !item.getChildren().isEmpty()) {
|
||||
//有子级
|
||||
this.setChildMaxParentId(item.getChildren(),thisMaxParentId);
|
||||
this.setChildMaxParentId(item.getChildren(), thisMaxParentId);
|
||||
}
|
||||
});
|
||||
return busiCategoryVOList;
|
||||
}
|
||||
|
||||
private void setChildMaxParentId(List<BusiCategoryVO> childList,String maxParentId){
|
||||
childList.forEach(item->{
|
||||
private void setChildMaxParentId(List<BusiCategoryVO> childList, String maxParentId) {
|
||||
childList.forEach(item -> {
|
||||
item.setMaxParentId(maxParentId);
|
||||
if(null!=item.getChildren()&& !item.getChildren().isEmpty()){
|
||||
this.setChildMaxParentId(item.getChildren(),maxParentId);
|
||||
if (null != item.getChildren() && !item.getChildren().isEmpty()) {
|
||||
this.setChildMaxParentId(item.getChildren(), maxParentId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 给所有子级设置最父级ID并且反回map格式
|
||||
* @author vinjor-M
|
||||
* @date 11:23 2025/7/19
|
||||
*
|
||||
* @param busiCategoryVOList 栏目树
|
||||
* @return java.util.List<com.ruoyi.busi.vo.BusiCategoryVO>
|
||||
* @author vinjor-M
|
||||
* @date 11:23 2025/7/19
|
||||
**/
|
||||
@Override
|
||||
public Map<String,String> dealFirstIdRtnMap(List<BusiCategoryVO> busiCategoryVOList){
|
||||
Map<String,String> rtnMap = new HashMap<>();
|
||||
busiCategoryVOList.forEach(item->{
|
||||
public Map<String, String> dealFirstIdRtnMap(List<BusiCategoryVO> busiCategoryVOList) {
|
||||
Map<String, String> rtnMap = new HashMap<>();
|
||||
busiCategoryVOList.forEach(item -> {
|
||||
String thisMaxParentId = item.getId();
|
||||
item.setMaxParentId(thisMaxParentId);
|
||||
rtnMap.put(item.getId(),thisMaxParentId);
|
||||
if(null!=item.getChildren() && !item.getChildren().isEmpty()){
|
||||
rtnMap.put(item.getId(), thisMaxParentId);
|
||||
if (null != item.getChildren() && !item.getChildren().isEmpty()) {
|
||||
//有子级
|
||||
this.setChildMaxParentIdMap(item.getChildren(),thisMaxParentId,rtnMap);
|
||||
this.setChildMaxParentIdMap(item.getChildren(), thisMaxParentId, rtnMap);
|
||||
}
|
||||
});
|
||||
return rtnMap;
|
||||
}
|
||||
|
||||
private void setChildMaxParentIdMap(List<BusiCategoryVO> childList,String maxParentId,Map<String,String> rtnMap){
|
||||
childList.forEach(item->{
|
||||
private void setChildMaxParentIdMap(List<BusiCategoryVO> childList, String maxParentId, Map<String, String> rtnMap) {
|
||||
childList.forEach(item -> {
|
||||
item.setMaxParentId(maxParentId);
|
||||
rtnMap.put(item.getId(),maxParentId);
|
||||
if(null!=item.getChildren()&& !item.getChildren().isEmpty()){
|
||||
this.setChildMaxParentIdMap(item.getChildren(),maxParentId,rtnMap);
|
||||
rtnMap.put(item.getId(), maxParentId);
|
||||
if (null != item.getChildren() && !item.getChildren().isEmpty()) {
|
||||
this.setChildMaxParentIdMap(item.getChildren(), maxParentId, rtnMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.base.service.IBaseManagerService;
|
||||
import com.ruoyi.busi.domain.BusiChatItem;
|
||||
import com.ruoyi.busi.mapper.BusiChatItemMapper;
|
||||
import com.ruoyi.busi.service.IBusiChatItemService;
|
||||
import com.ruoyi.busi.vo.ChatExcelMainVO;
|
||||
import com.ruoyi.busi.vo.ChatMainVO;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
@ -53,6 +55,43 @@ public class BusiChatMainServiceImpl extends ServiceImpl<BusiChatMainMapper,Busi
|
||||
return busiChatMainMapper.queryListPage(pageReqVO, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不分页查询聊天记录适配导出
|
||||
*
|
||||
* @param chatMainVO {@link ChatMainVO}
|
||||
* @return java.util.List<com.ruoyi.busi.vo.ChatMainVO>
|
||||
* @author PQZ
|
||||
* @date 14:03 2025/10/21
|
||||
**/
|
||||
@Override
|
||||
public List<ChatExcelMainVO> listChatMain(ChatMainVO chatMainVO) {
|
||||
List<ChatExcelMainVO> result = busiChatMainMapper.selectChatList(chatMainVO);
|
||||
result.forEach(item -> {
|
||||
item.setCreateTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",item.getCreateTime()));
|
||||
item.setUpdateTimeStr(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",item.getUpdateTime()));
|
||||
// 将chatItemList转换为指定格式的字符串
|
||||
if (item.getChatItemList() != null && !item.getChatItemList().isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < item.getChatItemList().size(); i++) {
|
||||
BusiChatItem chatItem = item.getChatItemList().get(i);
|
||||
String dataFromDisplay = "customer".equals(chatItem.getDataFrom()) ? "客户" : "平台";
|
||||
sb.append(dataFromDisplay)
|
||||
.append(":")
|
||||
.append(chatItem.getContent())
|
||||
.append("(")
|
||||
.append(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", chatItem.getCreateTime()))
|
||||
.append(")");
|
||||
// 如果不是最后一个元素,添加换行符
|
||||
if (i < item.getChatItemList().size() - 1) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
item.setChatHistory(sb.toString());
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验是否需要新增
|
||||
*
|
||||
|
||||
@ -4,9 +4,10 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.base.domain.BaseSite;
|
||||
import com.ruoyi.base.service.IBaseSiteService;
|
||||
import com.ruoyi.busi.domain.BusiKeyword;
|
||||
import com.ruoyi.busi.service.IBusiKeywordService;
|
||||
import com.ruoyi.busi.vo.BusiKeywordItemQueryVO;
|
||||
@ -18,9 +19,11 @@ import com.ruoyi.busi.mapper.BusiKeywordItemMapper;
|
||||
import com.ruoyi.busi.domain.BusiKeywordItem;
|
||||
import com.ruoyi.busi.service.IBusiKeywordItemService;
|
||||
|
||||
import static com.ruoyi.common.utils.GoogleRankUtil.getGoogleRankMain;
|
||||
|
||||
/**
|
||||
* 关键词排名明细Service业务层处理
|
||||
*
|
||||
*
|
||||
* @author vinjor-m
|
||||
* @date 2025-08-21
|
||||
*/
|
||||
@ -31,6 +34,8 @@ public class BusiKeywordItemServiceImpl extends ServiceImpl<BusiKeywordItemMappe
|
||||
private BusiKeywordItemMapper busiKeywordItemMapper;
|
||||
@Autowired
|
||||
private IBusiKeywordService busiKeywordService;
|
||||
@Autowired
|
||||
private IBaseSiteService baseSiteService;
|
||||
|
||||
@Override
|
||||
public IPage<BusiKeywordItem> queryListPage(BusiKeywordItem pageReqVO, Page<BusiKeywordItem> page) {
|
||||
@ -44,20 +49,40 @@ public class BusiKeywordItemServiceImpl extends ServiceImpl<BusiKeywordItemMappe
|
||||
* @date 15:10 2025/8/21
|
||||
**/
|
||||
@Override
|
||||
public void getKeywordRanking() {
|
||||
public void getKeywordRanking() throws InterruptedException {
|
||||
Date nowDate = new Date();
|
||||
//所有网站
|
||||
List<BaseSite> siteList = baseSiteService.list();
|
||||
Map<String,String> siteMap = siteList.stream().collect(Collectors.toMap(BaseSite::getId, BaseSite::getSiteUrl));
|
||||
List<BusiKeyword> keywordList = busiKeywordService.list();
|
||||
//删除今日所有的排名数据
|
||||
busiKeywordItemMapper.deleteBySelectDateInt(DateUtil.formatDate(nowDate));
|
||||
List<BusiKeywordItem> insertList = new ArrayList<>();
|
||||
int i = 0;
|
||||
for (BusiKeyword keyword : keywordList) {
|
||||
BusiKeywordItem busiKeywordItem = new BusiKeywordItem();
|
||||
busiKeywordItem.setTitle(keyword.getId());
|
||||
busiKeywordItem.setSelectDate(nowDate);
|
||||
//TODO 调朱哥的接口获取排名
|
||||
busiKeywordItem.setRanking(1);
|
||||
busiKeywordItem.setTenantId(keyword.getTenantId());
|
||||
insertList.add(busiKeywordItem);
|
||||
System.out.println("第" + (i+1) + "次搜索: 关键词=" + keyword.getId() + ", 目标网站=" + siteMap.get(keyword.getTenantId()));
|
||||
int rank = 0;
|
||||
try {
|
||||
// 测试用例:搜索关键词,查找特定网站的排名
|
||||
rank = getGoogleRankMain( keyword.getId(), siteMap.get(keyword.getTenantId()));
|
||||
System.out.println("第" + (i+1) + "次搜索:"+"排名:" + rank);
|
||||
} catch (Exception e) {
|
||||
System.err.println("搜索过程中发生异常: " + e.getMessage());
|
||||
}
|
||||
// 模拟用户行为:随机休眠5-15秒
|
||||
int randomSleep = 10000 + (int) (Math.random() * 20000);
|
||||
System.out.println("等待 " + (randomSleep / 1000) + " 秒后进行下次搜索...");
|
||||
Thread.sleep(randomSleep);
|
||||
if(rank>0 && rank<=20){
|
||||
//找到今天的排名
|
||||
busiKeywordItem.setRanking(rank);
|
||||
busiKeywordItem.setTenantId(keyword.getTenantId());
|
||||
insertList.add(busiKeywordItem);
|
||||
//删除这个关键词今天的排名
|
||||
busiKeywordItemMapper.deleteBySelectDateInt(DateUtil.formatDate(nowDate),busiKeywordItem.getTitle());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(!insertList.isEmpty()){
|
||||
this.saveBatch(insertList);
|
||||
|
||||
@ -69,6 +69,8 @@ public class BusiKeywordServiceImpl extends ServiceImpl<BusiKeywordMapper,BusiKe
|
||||
keywordItem.setTenantId(prodNew.getTenantId());
|
||||
keywordItem.setCreateTime(nowDate);
|
||||
insertList.add(keywordItem);
|
||||
//根据id和tenantId删除对应的关键词
|
||||
busiKeywordMapper.deleteByIdAndTenantId(item,prodNew.getTenantId());
|
||||
});
|
||||
}
|
||||
if(!insertList.isEmpty()){
|
||||
|
||||
@ -146,13 +146,14 @@ public class BusiProdNewServiceImpl extends ServiceImpl<BusiProdNewMapper,BusiPr
|
||||
* @date 11:33 2025/7/8
|
||||
**/
|
||||
@Override
|
||||
public List<BusiProdNew> hotProdOrNews(String tenantId,String dateType,Boolean ifHot) {
|
||||
public List<BusiProdNew> hotProdOrNews(String tenantId,String dateType,Boolean ifHot,String showPlat) {
|
||||
Page<BusiProdNew> page = new Page<>(1, 10);
|
||||
LambdaQueryWrapper<BusiProdNew> queryWrapper = new LambdaQueryWrapper<BusiProdNew>()
|
||||
.eq(BusiProdNew::getTenantId,tenantId)
|
||||
.eq(BusiProdNew::getDataType,dateType)
|
||||
.eq(BusiProdNew::getIfPublic,true)
|
||||
.eq(BusiProdNew::getIfReco,ifHot)
|
||||
.like(BusiProdNew::getShowPlat,showPlat)
|
||||
.orderByDesc(BusiProdNew::getSort);
|
||||
//查所有栏目
|
||||
BusiCategory category = new BusiCategory();
|
||||
@ -202,10 +203,11 @@ public class BusiProdNewServiceImpl extends ServiceImpl<BusiProdNewMapper,BusiPr
|
||||
* @date 13:55 2025/7/9
|
||||
**/
|
||||
@Override
|
||||
public IPage<BusiProdNew> searchTextAll(String tenantId, String text, Page<BusiProdNew> page) {
|
||||
public IPage<BusiProdNew> searchTextAll(String tenantId, String text, Page<BusiProdNew> page,String showPlat) {
|
||||
LambdaQueryWrapper<BusiProdNew> queryWrapper = new LambdaQueryWrapper<BusiProdNew>()
|
||||
.eq(BusiProdNew::getTenantId,tenantId)
|
||||
.eq(BusiProdNew::getIfPublic,true)
|
||||
.like(BusiProdNew::getShowPlat,showPlat)
|
||||
.and(wq->wq
|
||||
.like(BusiProdNew::getTitle,text)
|
||||
.or().like(BusiProdNew::getDescription,text)
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
package com.ruoyi.busi.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.busi.domain.BusiChatItem;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ChatExcelMainVO{
|
||||
private String id;
|
||||
/** 产品名称 */
|
||||
@Excel(name = "产品名称")
|
||||
private String prodName;
|
||||
/** 来源IP */
|
||||
@Excel(name = "IP")
|
||||
private String ip;
|
||||
/** 来源国家 */
|
||||
@Excel(name = "国家")
|
||||
private String national;
|
||||
/** 来源洲 */
|
||||
@Excel(name = "洲")
|
||||
private String oceania;
|
||||
/** 设备类型 */
|
||||
@Excel(name = "设备类型")
|
||||
private String equipment;
|
||||
/** 用户名称 */
|
||||
@Excel(name = "负责员工")
|
||||
private String userName;
|
||||
|
||||
/** 创建时间 */
|
||||
@Excel(name = "最早聊天时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String createTimeStr;
|
||||
/** 创建时间 */
|
||||
@Excel(name = "最近聊天时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private String updateTimeStr;
|
||||
/** 聊天记录 */
|
||||
@Excel(name = "聊天记录")
|
||||
private String chatHistory;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
private List<BusiChatItem> chatItemList;
|
||||
|
||||
}
|
||||
@ -32,7 +32,7 @@ public class BusiTask {
|
||||
* @author vinjor-M
|
||||
* @date 14:51 2025/8/21
|
||||
**/
|
||||
public void updateKeywordRanking() {
|
||||
public void updateKeywordRanking() throws InterruptedException {
|
||||
busiKeywordItemService.getKeywordRanking();
|
||||
System.out.println("【"+ DateUtil.now() +"】执行更新本站使用关键词google排名成功");
|
||||
}
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package com.ruoyi.utils;
|
||||
|
||||
import com.aliyun.oss.ClientBuilderConfiguration;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.model.ObjectMetadata;
|
||||
import com.aliyuncs.utils.IOUtils;
|
||||
import com.ruoyi.common.config.OssConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class OssUtil {
|
||||
@Autowired
|
||||
private OssConfig ossConfig;
|
||||
|
||||
/**
|
||||
* 上传文件(fileKey-InputStream)
|
||||
*/
|
||||
public void uploadFile(String fileKey, InputStream stream) throws IOException {
|
||||
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
|
||||
OSS client = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret(), conf);
|
||||
|
||||
try {
|
||||
client.putObject(ossConfig.getBucketName(), fileKey, stream);
|
||||
} finally {
|
||||
stream.close();
|
||||
if (client != null) {
|
||||
client.shutdown();
|
||||
}
|
||||
IOUtils.closeQuietly(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*/
|
||||
public void downloadFile(HttpServletResponse response, String fileKey, String fileName) throws IOException {
|
||||
fileKey = fileKey.replace("https://"+ossConfig.getBucketName()+"."+ossConfig.getEndPoint()+"/","");
|
||||
InputStream stream = null;
|
||||
BufferedInputStream bufferedInputStream = null;
|
||||
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
|
||||
OSS client = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret(), conf);
|
||||
try {
|
||||
// 在获取文件流之前,先获取文件元数据
|
||||
ObjectMetadata metadata = client.getObjectMetadata(ossConfig.getBucketName(), fileKey);
|
||||
long contentLength = metadata.getContentLength();
|
||||
stream = client.getObject(ossConfig.getBucketName(), fileKey).getObjectContent();
|
||||
response.reset();
|
||||
// 设置Content-Length响应头
|
||||
response.setContentLengthLong(contentLength);
|
||||
response.setContentType("application/octet-stream");
|
||||
response.addHeader("Content-Disposition", "attachment;filename=CDbay-" + URLEncoder.encode(fileName, "UTF-8")
|
||||
.replace("+", "%20")+".apk");
|
||||
OutputStream outputStream = response.getOutputStream();
|
||||
bufferedInputStream = new BufferedInputStream(stream);
|
||||
byte[] buf = new byte[16384];
|
||||
int bytesRead;
|
||||
while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
|
||||
outputStream.write(buf, 0, bytesRead);
|
||||
outputStream.flush();
|
||||
}
|
||||
} finally {
|
||||
if (client != null) {
|
||||
client.shutdown();
|
||||
}
|
||||
|
||||
if (bufferedInputStream != null || stream != null) {
|
||||
try {
|
||||
bufferedInputStream.close();
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Oss Download IOException,fileKey:" + fileKey, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,16 +4,16 @@ spring:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源-点亮开发库
|
||||
# # 主库数据源-成达服务器-测试库
|
||||
master:
|
||||
url: jdbc:mysql://82.156.161.160:3306/dl_site_system?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: site
|
||||
password: 123456
|
||||
#主库数据源-客户测试服务器
|
||||
url: jdbc:mysql://8.220.74.244:3306/dl_test_site?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: dl_test_site
|
||||
password: Aa123456.
|
||||
# 主库数据源-成达服务器-生产库
|
||||
# master:
|
||||
# url: jdbc:mysql://127.0.0.1:3306/dl_site_system?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
# url: jdbc:mysql://8.220.74.244:3306/dl_site_system?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
# username: site
|
||||
# password: 123456
|
||||
# password: Chengda@2025~
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
|
||||
@ -7,7 +7,7 @@ ruoyi:
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
|
||||
profile: D:/ruoyi/uploadPath
|
||||
profile: /uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
@ -146,10 +146,10 @@ xss:
|
||||
# 阿里云OSS配置
|
||||
aliyun:
|
||||
oss:
|
||||
end-point: oss-cn-qingdao.aliyuncs.com
|
||||
access-key-id: LTAI5tLThQFWgMLRTf3siNjb
|
||||
access-key-secret: M5HjOyB8ir5tYEPFOQwImfJNgsumaG
|
||||
bucket-name: dianliang123
|
||||
end-point: oss-eu-central-1.aliyuncs.com
|
||||
access-key-id: LTAI5tB7zL8KuHDnMsdUhXRy
|
||||
access-key-secret: bZ28G69DLR6Q3WhvvrWyxWw3lEbfzk
|
||||
bucket-name: sd-chengda
|
||||
#google ads配置
|
||||
google:
|
||||
ads:
|
||||
|
||||
@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<resultMap type="BaseApp" id="BaseAppResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="version" column="version" />
|
||||
<result property="apkUrl" column="apk_url" />
|
||||
<result property="content" column="content" />
|
||||
<result property="creator" column="creator" />
|
||||
<result property="createTime" column="create_time" />
|
||||
@ -16,7 +17,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectBaseAppVo">
|
||||
select id, version, content, creator, create_time, updater, update_time, del_flag from dl_base_app
|
||||
select id, version, apk_url, content, creator, create_time, updater, update_time, del_flag from dl_base_app
|
||||
</sql>
|
||||
|
||||
<select id="queryListPage" parameterType="BaseApp" resultMap="BaseAppResult">
|
||||
@ -24,6 +25,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<where>
|
||||
<if test="entity.version != null "> and version like concat('%', #{entity.version}, '%')</if>
|
||||
</where>
|
||||
order by version DESC,create_time desc
|
||||
order by create_time desc
|
||||
</select>
|
||||
</mapper>
|
||||
@ -28,6 +28,23 @@
|
||||
<result property="siteName" column="site_name"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="com.ruoyi.busi.vo.ChatExcelMainVO" id="ChatExcelMainResult">
|
||||
<result property="ip" column="ip"/>
|
||||
<result property="national" column="national"/>
|
||||
<result property="oceania" column="oceania"/>
|
||||
<result property="equipment" column="equipment"/>
|
||||
<result property="prodName" column="prod_name"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<!-- 添加集合映射 -->
|
||||
<collection select="getChatItems"
|
||||
column="id"
|
||||
property="chatItemList"
|
||||
javaType="java.util.List"
|
||||
ofType="com.ruoyi.busi.domain.BusiChatItem"/>
|
||||
</resultMap>
|
||||
|
||||
|
||||
<select id="queryListPage" parameterType="BusiChatMain" resultMap="BusiChatMainResult">
|
||||
select dbcm.*,dbpn.title AS prod_name,su.nick_name AS user_name,dbs.site_name AS site_name
|
||||
@ -58,6 +75,41 @@
|
||||
</where>
|
||||
order BY dbcm.create_time DESC,dbcm.update_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectChatList" parameterType="BusiChatMain" resultMap="ChatExcelMainResult">
|
||||
select dbcm.*,dbpn.title AS prod_name,su.nick_name AS user_name,dbs.site_name AS site_name
|
||||
from dl_busi_chat_main dbcm
|
||||
left join dl_busi_prod_new dbpn on dbcm.prod_id = dbpn.id
|
||||
left join sys_user su on dbcm.user_id = su.user_id
|
||||
left join dl_base_site dbs ON dbcm.tenant_id = dbs.id
|
||||
<where>
|
||||
<if test="entity.prodName != null and entity.prodName != ''">and dbpn.title LIKE
|
||||
CONCAT('%',#{entity.prodName},'%')
|
||||
</if>
|
||||
<if test="entity.ip != null and entity.ip != ''">and dbcm.ip = #{entity.ip}</if>
|
||||
<if test="entity.equipment != null and entity.equipment != ''">and dbcm.equipment = #{entity.equipment}</if>
|
||||
<if test="entity.national != null and entity.national != ''">and dbcm.national LIKE
|
||||
CONCAT('%',#{entity.national},'%')
|
||||
</if>
|
||||
<if test="entity.oceania != null and entity.oceania != ''">and dbcm.oceania = #{entity.oceania}</if>
|
||||
<if test="entity.userName != null and entity.userName != ''">and (su.nick_name LIKE
|
||||
CONCAT('%',#{entity.userName},'%') OR su.user_name LIKE CONCAT('%',#{entity.userName},'%'))
|
||||
</if>
|
||||
<if test="entity.tenantId != null and entity.tenantId != ''">and dbcm.tenant_id = #{entity.tenantId}</if>
|
||||
<if test="entity.startDate != null and entity.startDate != ''">and (dbcm.create_time >=
|
||||
#{entity.startDate} OR dbcm.update_time >= #{entity.startDate})
|
||||
</if>
|
||||
<if test="entity.endDate != null and entity.endDate != ''">and (dbcm.create_time <= #{entity.endDate} OR
|
||||
dbcm.update_time >= #{entity.startDate})
|
||||
</if>
|
||||
</where>
|
||||
order BY dbcm.create_time DESC,dbcm.update_time DESC
|
||||
</select>
|
||||
|
||||
<select id="getChatItems" resultType="com.ruoyi.busi.domain.BusiChatItem">
|
||||
select * from dl_busi_chat_item where main_id = #{id} order by create_time asc
|
||||
</select>
|
||||
|
||||
<select id="selectIpCount" resultType="java.lang.Integer">
|
||||
SELECT
|
||||
COUNT( id )
|
||||
|
||||
@ -16,7 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
select id, title, select_date, ranking, tenant_id from dl_busi_keyword_item
|
||||
</sql>
|
||||
<delete id="deleteBySelectDateInt">
|
||||
delete from dl_busi_keyword_item where select_date = #{date}
|
||||
delete from dl_busi_keyword_item where select_date = #{date} AND title = #{title}
|
||||
</delete>
|
||||
|
||||
<select id="queryListPage" parameterType="BusiKeywordItem" resultMap="BusiKeywordItemResult">
|
||||
|
||||
@ -12,6 +12,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<sql id="selectBusiKeywordVo">
|
||||
select id, tenant_id from dl_busi_keyword
|
||||
</sql>
|
||||
<delete id="deleteByIdAndTenantId">
|
||||
DELETE FROM dl_busi_keyword WHERE id =#{id} AND tenant_id=#{tenantId}
|
||||
</delete>
|
||||
|
||||
<select id="queryListPage" parameterType="BusiKeyword" resultMap="BusiKeywordResult">
|
||||
<include refid="selectBusiKeywordVo"/>
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
<result property="prodTitle" column="prod_title"/>
|
||||
<result property="prodKeyword" column="prod_keyword"/>
|
||||
<result property="prodDescription" column="prod_description"/>
|
||||
<result property="showPlat" column="show_plat"/>
|
||||
<result property="newsFrom" column="news_from"/>
|
||||
<result property="publicDate" column="public_date"/>
|
||||
<result property="mainPic" column="main_pic"/>
|
||||
@ -42,6 +43,7 @@
|
||||
prod_title,
|
||||
prod_keyword,
|
||||
prod_description,
|
||||
show_plat,
|
||||
news_from,
|
||||
public_date,
|
||||
main_pic,
|
||||
@ -106,6 +108,10 @@
|
||||
AND product.news_from like concat('%',
|
||||
#{entity.newsFrom}, '%')
|
||||
</if>
|
||||
<if test="entity.showPlat != null and entity.showPlat != ''">
|
||||
AND product.show_plat like concat('%',
|
||||
#{entity.showPlat}, '%')
|
||||
</if>
|
||||
</where>
|
||||
GROUP BY
|
||||
product.id
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<result property="prodId" column="prod_id"/>
|
||||
<result property="thirdSoft" column="third_soft"/>
|
||||
<result property="national" column="national"/>
|
||||
<result property="oceania" column="oceania"/>
|
||||
<result property="thirdAccount" column="third_account"/>
|
||||
<result property="viewType" column="view_type"/>
|
||||
<result property="pageUrl" column="page_url"/>
|
||||
@ -27,7 +28,7 @@
|
||||
<sql id="selectBusiThirdItemVo">
|
||||
select id,
|
||||
prod_id,
|
||||
third_soft, national, third_account, view_type, page_url, equipment, ip, tenant_id, creator, create_time, updater, update_time, del_flag
|
||||
third_soft, national, oceania,third_account, view_type, page_url, equipment, ip, tenant_id, creator, create_time, updater, update_time, del_flag
|
||||
from dl_busi_third_item
|
||||
</sql>
|
||||
|
||||
@ -39,6 +40,7 @@
|
||||
<if test="entity.prodName != null and entity.prodName != ''">and dbpn.title LIKE CONCAT('%',#{entity.prodName},'%')</if>
|
||||
<if test="entity.thirdSoft != null and entity.thirdSoft != ''">and dbti.third_soft = #{entity.thirdSoft}</if>
|
||||
<if test="entity.national != null and entity.national != ''">and dbti.national LIKE CONCAT('%',#{entity.national},'%')</if>
|
||||
<if test="entity.oceania != null and entity.oceania != ''">and dbti.national LIKE CONCAT('%',#{entity.oceania},'%')</if>
|
||||
<if test="entity.thirdAccount != null and entity.thirdAccount != ''">and dbti.third_account LIKE CONCAT('%',#{entity.thirdAccount},'%')</if>
|
||||
<if test="entity.viewType != null and entity.viewType != ''">and dbti.view_type = #{entity.viewType}</if>
|
||||
<if test="entity.pageUrl != null and entity.pageUrl != ''">and dbti.page_url LIKE CONCAT('%',#{entity.pageUrl},'%')</if>
|
||||
|
||||
@ -101,6 +101,9 @@ public class SysUser extends BaseEntity
|
||||
/** 角色ID */
|
||||
private Long roleId;
|
||||
|
||||
/** 站点唯一编码(租户id) */
|
||||
private String tenantId;
|
||||
|
||||
public SysUser()
|
||||
{
|
||||
|
||||
@ -364,4 +367,12 @@ public class SysUser extends BaseEntity
|
||||
public void setInviteId(Long inviteId) {
|
||||
this.inviteId = inviteId;
|
||||
}
|
||||
|
||||
public String getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(String tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ public class GoogleRankUtil {
|
||||
private static volatile int MAX_RETRIES = 3;
|
||||
private static volatile int BASE_BACKOFF_MS = 10000;
|
||||
private static volatile boolean KEEP_BROWSER_OPEN = false;
|
||||
private static volatile String GOOGLE_REGION = "GH"; // Google地理位置(如:US, CN, ZA等)
|
||||
|
||||
// 线程本地变量
|
||||
private static final ThreadLocal<WebDriver> TL_DRIVER = new ThreadLocal<>();
|
||||
@ -86,6 +87,14 @@ public class GoogleRankUtil {
|
||||
KEEP_BROWSER_OPEN = keep;
|
||||
}
|
||||
|
||||
public static void setGoogleRegion(String region) {
|
||||
GOOGLE_REGION = (region == null || region.trim().isEmpty()) ? null : region.trim().toUpperCase();
|
||||
}
|
||||
|
||||
public static String getGoogleRegion() {
|
||||
return GOOGLE_REGION;
|
||||
}
|
||||
|
||||
public static void shutdownDriver() {
|
||||
WebDriver d = TL_DRIVER.get();
|
||||
if (d != null) {
|
||||
@ -148,6 +157,13 @@ public class GoogleRankUtil {
|
||||
|
||||
// 构建基础搜索URL(使用udm=14参数强制网页结果)
|
||||
String baseUrl = GOOGLE_SEARCH_URL + encodedSearchText + "&newwindow=1&hl=zh-CN&pws=0&udm=14";
|
||||
|
||||
// 添加地理位置参数(如果配置了)
|
||||
if (GOOGLE_REGION != null && !GOOGLE_REGION.isEmpty()) {
|
||||
baseUrl += "&gl=" + GOOGLE_REGION;
|
||||
log.info("设置Google地理位置:gl={}", GOOGLE_REGION);
|
||||
}
|
||||
|
||||
log.info("发起Google搜索请求:url={}, 目标网站={}", baseUrl, targetSite);
|
||||
|
||||
WebDriver driver = null;
|
||||
@ -587,6 +603,50 @@ public class GoogleRankUtil {
|
||||
else return "查询失败";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询谷歌关键词排名主体方法
|
||||
* @author vinjor-M
|
||||
* @date 11:17 2025/10/24
|
||||
* @param searchText TODO
|
||||
* @param site TODO
|
||||
* @return int
|
||||
**/
|
||||
public static int getGoogleRankMain(String searchText, String site) {
|
||||
int rank = -1;
|
||||
// 配置参数
|
||||
GoogleRankUtil.setHeadless(false); // Mac环境建议 false
|
||||
GoogleRankUtil.setSessionReuse(true); // 复用浏览器会话
|
||||
GoogleRankUtil.setGlobalRequestInterval(8000, 5000); // 8s + 抖动 0~5s
|
||||
GoogleRankUtil.setRetryPolicy(3, 10000); // 重试3次,递增退避
|
||||
GoogleRankUtil.setKeepBrowserOpen(false); // 结束后关闭
|
||||
|
||||
// 【新增】设置Google地理位置
|
||||
// 常见代码:US=美国, CN=中国, ZA=南非, EG=埃及, NG=尼日利亚,GH=加纳,
|
||||
GoogleRankUtil.setGoogleRegion("GH"); // 设置为加纳
|
||||
|
||||
// 测试关键词
|
||||
List<String> keywords = new ArrayList<>();
|
||||
keywords.add(searchText);
|
||||
// System.out.println("========== GoogleRankUtil 测试 ==========");
|
||||
// System.out.println("解析方案:speculationrules(稳定、准确)");
|
||||
// System.out.println("目标站点: " + site);
|
||||
// System.out.println("地理位置: " + (GoogleRankUtil.getGoogleRegion() != null ? GoogleRankUtil.getGoogleRegion() : "默认"));
|
||||
// System.out.println("关键词数量: " + keywords.size());
|
||||
// System.out.println("=========================================\n");
|
||||
for (String kw : keywords) {
|
||||
// System.out.println("[" + (i + 1) + "/" + keywords.size() + "] 正在采集关键词: " + kw);
|
||||
// long startTime = System.currentTimeMillis();
|
||||
rank = getGoogleRank(kw, site);
|
||||
// long elapsed = System.currentTimeMillis() - startTime;
|
||||
// System.out.println("关键词[" + kw + "] 排名: " + formatRank(rank));
|
||||
// System.out.println("耗时: " + elapsed + "ms");
|
||||
// System.out.println("-----------------------------------\n");
|
||||
}
|
||||
// System.out.println("========== 采集完成 ==========");
|
||||
// 清理
|
||||
GoogleRankUtil.shutdownDriver();
|
||||
return rank ;
|
||||
}
|
||||
// ==================== 测试方法 ====================
|
||||
|
||||
/**
|
||||
@ -600,13 +660,18 @@ public class GoogleRankUtil {
|
||||
GoogleRankUtil.setRetryPolicy(3, 10000); // 重试3次,递增退避
|
||||
GoogleRankUtil.setKeepBrowserOpen(false); // 结束后关闭
|
||||
|
||||
// 测试关键词(先测试1个)
|
||||
List<String> keywords = Arrays.asList("货车","大卡车");
|
||||
String site = "zh.wikipedia.org";
|
||||
// 【新增】设置Google地理位置
|
||||
// 常见代码:US=美国, CN=中国, ZA=南非, EG=埃及, NG=尼日利亚,GH=加纳,
|
||||
GoogleRankUtil.setGoogleRegion("GH"); // 设置为加纳
|
||||
|
||||
// 测试关键词
|
||||
List<String> keywords = Arrays.asList("cd truck");
|
||||
String site = "www.cdtrucktralier.com";
|
||||
|
||||
System.out.println("========== GoogleRankUtil 测试 ==========");
|
||||
System.out.println("解析方案:speculationrules(稳定、准确)");
|
||||
System.out.println("目标站点: " + site);
|
||||
System.out.println("地理位置: " + (GoogleRankUtil.getGoogleRegion() != null ? GoogleRankUtil.getGoogleRegion() : "默认"));
|
||||
System.out.println("关键词数量: " + keywords.size());
|
||||
System.out.println("=========================================\n");
|
||||
|
||||
@ -618,7 +683,7 @@ public class GoogleRankUtil {
|
||||
int rank = getGoogleRank(kw, site);
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
|
||||
System.out.println("关键词[" + kw + "] 维基百科排名: " + formatRank(rank));
|
||||
System.out.println("关键词[" + kw + "] 排名: " + formatRank(rank));
|
||||
System.out.println("耗时: " + elapsed + "ms");
|
||||
System.out.println("-----------------------------------\n");
|
||||
}
|
||||
|
||||
@ -1,360 +0,0 @@
|
||||
package com.ruoyi.common.utils;
|
||||
|
||||
import com.github.rholder.retry.Retryer;
|
||||
import com.github.rholder.retry.RetryerBuilder;
|
||||
import com.github.rholder.retry.StopStrategies;
|
||||
import com.github.rholder.retry.WaitStrategies;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.chrome.ChromeOptions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GoogleUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(GoogleUtil.class);
|
||||
// 可配置参数(Ruoyi项目建议用@Value从application.yml读取)
|
||||
private static final String GOOGLE_SEARCH_URL = "https://www.google.com/search?q=";
|
||||
private static final String PROXY_HOST = "127.0.0.1";
|
||||
private static final int PROXY_PORT = 7897;
|
||||
private static final int CONNECT_TIMEOUT = 10000;
|
||||
private static final int READ_TIMEOUT = 15000;
|
||||
// 重试机制
|
||||
private static final Retryer<Boolean> RETRYER = RetryerBuilder.<Boolean>newBuilder()
|
||||
.retryIfExceptionOfType(Exception.class)
|
||||
.retryIfResult(result -> result != null && !result)
|
||||
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
|
||||
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
|
||||
.build();
|
||||
|
||||
// 扩展User-Agent池(增加移动端标识,反爬更友好)
|
||||
private static final List<String> USER_AGENTS = Arrays.asList(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (Android 14; Mobile; rv:120.0) Gecko/120.0 Firefox/120.0"
|
||||
);
|
||||
|
||||
/**
|
||||
* 核心方法:获取Google搜索排名(使用Selenium实现)
|
||||
*/
|
||||
public static int getGoogleRank(String searchText, String webSite) {
|
||||
// 入参校验
|
||||
if (searchText == null || searchText.trim().isEmpty() || webSite == null || webSite.trim().isEmpty()) {
|
||||
log.error("入参非法:searchText={}, webSite={}", searchText, webSite);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 最多重试3次
|
||||
int maxRetries = 3;
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
int result = getGoogleRankInternal(searchText, webSite);
|
||||
if (result != -2) { // 不是验证码错误
|
||||
return result;
|
||||
}
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
log.info("遇到验证码,{}秒后进行第{}次重试", 5 * attempt, attempt + 1);
|
||||
try {
|
||||
Thread.sleep(5000 * attempt); // 递增延迟重试
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.error("经过{}次尝试后仍然遇到验证码,搜索失败", maxRetries);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部方法:执行Google搜索排名获取
|
||||
*/
|
||||
private static int getGoogleRankInternal(String searchText, String webSite) {
|
||||
webSite = webSite.trim();
|
||||
String encodedSearchText = encodeSearchText(searchText);
|
||||
if (encodedSearchText == null) {
|
||||
return 0;
|
||||
}
|
||||
String finalUrl = GOOGLE_SEARCH_URL + encodedSearchText;
|
||||
log.info("发起Google搜索请求:url={}, 目标网站={}", finalUrl, webSite);
|
||||
|
||||
WebDriver driver = null;
|
||||
try {
|
||||
// 初始化WebDriver
|
||||
driver = createWebDriver();
|
||||
|
||||
int rank = -1;
|
||||
// 搜索前三页
|
||||
for (int page = 1; page <= 3; page++) {
|
||||
String pageUrl = page == 1 ? finalUrl : finalUrl + "&start=" + ((page - 1) * 10);
|
||||
log.info("搜索第{}页: {}", page, pageUrl);
|
||||
|
||||
// 访问Google搜索页面
|
||||
driver.get(pageUrl);
|
||||
|
||||
// 随机延时,模拟人类行为(增加延时以减少被识别为机器人的可能性)
|
||||
Thread.sleep((long) (3000 + Math.random() * 5000));
|
||||
|
||||
// 检查是否出现了验证码页面
|
||||
if (isCaptchaPage(driver)) {
|
||||
log.warn("检测到验证码页面,本次请求失败");
|
||||
return -2; // 特殊返回值表示遇到验证码
|
||||
}
|
||||
|
||||
// 获取页面源码
|
||||
String html = driver.getPageSource();
|
||||
log.debug("第{}页请求成功:响应长度={}字节", page, html.length());
|
||||
|
||||
// 解析当前页的排名
|
||||
int pageRank = parseRankFromHtml(html, webSite, (page - 1) * 10);
|
||||
if (pageRank > 0) {
|
||||
rank = pageRank;
|
||||
break;
|
||||
}
|
||||
|
||||
// 页面间增加随机延时
|
||||
if (page < 3) {
|
||||
Thread.sleep((long) (2000 + Math.random() * 3000));
|
||||
}
|
||||
}
|
||||
|
||||
return rank;
|
||||
} catch (Exception e) {
|
||||
log.error("获取排名异常:url={}, 原因={}", finalUrl, e.getMessage(), e);
|
||||
return 0;
|
||||
} finally {
|
||||
// 关闭浏览器
|
||||
if (driver != null) {
|
||||
try {
|
||||
driver.quit();
|
||||
} catch (Exception e) {
|
||||
log.error("关闭浏览器失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建WebDriver实例
|
||||
* @return WebDriver
|
||||
*/
|
||||
private static WebDriver createWebDriver() {
|
||||
// 设置ChromeDriver路径(根据实际路径调整)
|
||||
System.setProperty("webdriver.chrome.driver", "D:/chromedriver-win64/chromedriver.exe");
|
||||
|
||||
ChromeOptions options = new ChromeOptions();
|
||||
// 设置无头模式 (Selenium 3.x语法)
|
||||
options.addArguments("--headless");
|
||||
// 设置User-Agent
|
||||
String randomUserAgent = USER_AGENTS.get((int) (Math.random() * USER_AGENTS.size()));
|
||||
options.addArguments("--user-agent=" + randomUserAgent);
|
||||
// 禁用图片加载提高速度
|
||||
options.addArguments("--blink-settings=imagesEnabled=false");
|
||||
// 设置窗口大小
|
||||
options.addArguments("--window-size=1920,1080");
|
||||
// 禁用自动化控制特征
|
||||
options.addArguments("--disable-blink-features=AutomationControlled");
|
||||
options.setExperimentalOption("excludeSwitches", Arrays.asList("enable-automation"));
|
||||
// 禁用自动化标志
|
||||
options.addArguments("--disable-extensions");
|
||||
options.addArguments("--no-sandbox");
|
||||
options.addArguments("--disable-dev-shm-usage");
|
||||
// 禁用SSL错误
|
||||
options.addArguments("--ignore-ssl-errors");
|
||||
options.addArguments("--ignore-certificate-errors");
|
||||
// 禁用日志
|
||||
options.addArguments("--log-level=3");
|
||||
options.addArguments("--silent");
|
||||
|
||||
// 如果需要使用代理(轮换代理IP可以有效避免验证码)
|
||||
/*
|
||||
if (PROXY_HOST != null && !PROXY_HOST.isEmpty()) {
|
||||
// 可以在这里集成代理IP服务,每次使用不同的IP
|
||||
options.addArguments("--proxy-server=http://" + PROXY_HOST + ":" + PROXY_PORT);
|
||||
}
|
||||
*/
|
||||
|
||||
WebDriver driver = new ChromeDriver(options);
|
||||
// 执行JavaScript隐藏webdriver属性
|
||||
((org.openqa.selenium.JavascriptExecutor) driver).executeScript(
|
||||
"Object.defineProperty(navigator, 'webdriver', {get: () => undefined})");
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码搜索关键词
|
||||
*/
|
||||
private static String encodeSearchText(String searchText) {
|
||||
try {
|
||||
return URLEncoder.encode(searchText.trim(), StandardCharsets.UTF_8.name());
|
||||
} catch (Exception e) {
|
||||
log.error("关键词编码失败:searchText={}, 编码格式={}", searchText, StandardCharsets.UTF_8.name(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析排名
|
||||
*/
|
||||
private static int parseRankFromHtml(String html, String targetWebSite, int baseRank) {
|
||||
Document doc = Jsoup.parse(html);
|
||||
|
||||
// 获取所有可能的搜索结果容器
|
||||
Elements resultContainers = doc.select("div.g");
|
||||
|
||||
if (resultContainers.isEmpty()) {
|
||||
log.warn("未找到任何搜索结果容器");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log.debug("找到 {} 个搜索结果容器", resultContainers.size());
|
||||
|
||||
String cleanTarget = targetWebSite
|
||||
.replace("https://", "")
|
||||
.replace("http://", "")
|
||||
.replace("www.", "");
|
||||
|
||||
// 如果目标网站包含路径,则只取域名部分进行比较
|
||||
if (cleanTarget.contains("/")) {
|
||||
cleanTarget = cleanTarget.substring(0, cleanTarget.indexOf("/"));
|
||||
}
|
||||
|
||||
int validResultCount = 0;
|
||||
|
||||
for (Element container : resultContainers) {
|
||||
// 跳过图片和视频区块
|
||||
if (container.select("div.XaIwc, div.islrc, div.JTuIPc, div.PiKbc, div[jscontroller]").size() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 查找容器中的链接
|
||||
Elements links = container.select("a[href]");
|
||||
if (links.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean isSearchResult = false;
|
||||
String resultUrl = "";
|
||||
|
||||
// 查找有效的搜索结果链接
|
||||
for (Element link : links) {
|
||||
String href = link.attr("href");
|
||||
|
||||
// 跳过Google内部链接
|
||||
if (href.contains("google.com") || href.startsWith("/url?") || href.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否是标题链接(通常在h3标签内)
|
||||
if (link.parent() != null && link.parent().tagName().equals("h3")) {
|
||||
isSearchResult = true;
|
||||
resultUrl = href;
|
||||
break;
|
||||
}
|
||||
|
||||
// 或者检查是否在常见的搜索结果区块中
|
||||
Element parent = link.parent();
|
||||
while (parent != null) {
|
||||
if (parent.hasClass("yuRUbf") || parent.hasClass("tF2Cxc")) {
|
||||
isSearchResult = true;
|
||||
resultUrl = href;
|
||||
break;
|
||||
}
|
||||
parent = parent.parent();
|
||||
}
|
||||
|
||||
if (isSearchResult) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSearchResult) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validResultCount++;
|
||||
|
||||
String cleanResult = resultUrl
|
||||
.replace("https://", "")
|
||||
.replace("http://", "")
|
||||
.replace("www.", "");
|
||||
|
||||
// 如果结果URL包含路径,则只取域名部分进行比较
|
||||
if (cleanResult.contains("/")) {
|
||||
int firstSlash = cleanResult.indexOf("/");
|
||||
if (firstSlash > 0) {
|
||||
cleanResult = cleanResult.substring(0, firstSlash);
|
||||
}
|
||||
}
|
||||
|
||||
// 匹配目标网站
|
||||
if (cleanResult.contains(cleanTarget) || cleanTarget.contains(cleanResult)) {
|
||||
int actualRank = baseRank + validResultCount;
|
||||
log.info("找到目标网站:排名={}, 结果URL={}, 目标网站={}", actualRank, resultUrl, targetWebSite);
|
||||
return actualRank;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("在当前页面未找到目标网站:targetWebSite={}", targetWebSite);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为验证码页面
|
||||
* @param driver WebDriver实例
|
||||
* @return 是否为验证码页面
|
||||
*/
|
||||
private static boolean isCaptchaPage(WebDriver driver) {
|
||||
try {
|
||||
String pageSource = driver.getPageSource().toLowerCase();
|
||||
String currentUrl = driver.getCurrentUrl().toLowerCase();
|
||||
|
||||
// 检查页面是否包含验证码相关关键词
|
||||
boolean hasCaptchaKeywords = pageSource.contains("captcha") ||
|
||||
pageSource.contains("recaptcha") ||
|
||||
pageSource.contains("人机验证") ||
|
||||
pageSource.contains("异常流量") ||
|
||||
pageSource.contains("security check") ||
|
||||
pageSource.contains("sorry/index") ||
|
||||
pageSource.contains("before we can serve your request");
|
||||
|
||||
// 检查URL是否为验证码页面
|
||||
boolean isCaptchaUrl = currentUrl.contains("sorry/index") ||
|
||||
currentUrl.contains("security-check") ||
|
||||
currentUrl.contains("captcha");
|
||||
|
||||
return hasCaptchaKeywords || isCaptchaUrl;
|
||||
} catch (Exception e) {
|
||||
log.error("检查验证码页面时出错", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试方法
|
||||
public static void main(String[] args) {
|
||||
// 测试用例:搜索关键词,查找特定网站的排名
|
||||
int rank1 = getGoogleRank("大卡车", "zh.wikipedia.org");
|
||||
System.out.println("维基百科排名:" + formatRank(rank1));
|
||||
}
|
||||
|
||||
// 辅助方法:格式化排名输出
|
||||
private static String formatRank(int rank) {
|
||||
if (rank > 0) return rank + "名";
|
||||
else if (rank == -1) return "未找到";
|
||||
else if (rank == -2) return "遇到验证码";
|
||||
else return "查询失败";
|
||||
}
|
||||
}
|
||||
@ -27,6 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<association property="dept" javaType="SysDept" resultMap="deptResult" />
|
||||
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
|
||||
</resultMap>
|
||||
@ -51,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectUserVo">
|
||||
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
|
||||
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,u.tenant_id,
|
||||
d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
|
||||
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
|
||||
from sys_user u
|
||||
@ -61,7 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</sql>
|
||||
|
||||
<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
|
||||
select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
|
||||
select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, u.tenant_id,d.dept_name, d.leader from sys_user u
|
||||
left join sys_dept d on u.dept_id = d.dept_id
|
||||
where u.del_flag = '0'
|
||||
<if test="userId != null and userId != 0">
|
||||
@ -73,6 +74,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="status != null and status != ''">
|
||||
AND u.status = #{status}
|
||||
</if>
|
||||
<if test="tenantId != null and tenantId != ''">
|
||||
AND u.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<if test="phonenumber != null and phonenumber != ''">
|
||||
AND u.phonenumber like concat('%', #{phonenumber}, '%')
|
||||
</if>
|
||||
@ -90,7 +94,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
|
||||
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.create_time
|
||||
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.create_time,u.tenant_id
|
||||
from sys_user u
|
||||
left join sys_dept d on u.dept_id = d.dept_id
|
||||
left join sys_user_role ur on u.user_id = ur.user_id
|
||||
@ -107,7 +111,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</select>
|
||||
|
||||
<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
|
||||
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.create_time
|
||||
select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status,u.open_id,u.wx_open_id,u.union_id,u.invite_id,u.create_time,u.tenant_id
|
||||
from sys_user u
|
||||
left join sys_dept d on u.dept_id = d.dept_id
|
||||
left join sys_user_role ur on u.user_id = ur.user_id
|
||||
@ -117,6 +121,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="userName != null and userName != ''">
|
||||
AND u.user_name like concat('%', #{userName}, '%')
|
||||
</if>
|
||||
<if test="tenantId != null and tenantId != ''">
|
||||
AND u.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<if test="phonenumber != null and phonenumber != ''">
|
||||
AND u.phonenumber like concat('%', #{phonenumber}, '%')
|
||||
</if>
|
||||
@ -164,6 +171,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="inviteId != null and inviteId != ''">invite_id,</if>
|
||||
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||
<if test="remark != null and remark != ''">remark,</if>
|
||||
<if test="tenantId != null and tenantId != ''">tenant_id,</if>
|
||||
create_time
|
||||
)values(
|
||||
<if test="userId != null and userId != ''">#{userId},</if>
|
||||
@ -182,6 +190,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="inviteId != null and inviteId != ''">#{inviteId},</if>
|
||||
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||
<if test="remark != null and remark != ''">#{remark},</if>
|
||||
<if test="tenantId != null and tenantId != ''">#{tenantId},</if>
|
||||
sysdate()
|
||||
)
|
||||
</insert>
|
||||
@ -205,6 +214,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="loginDate != null">login_date = #{loginDate},</if>
|
||||
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="tenantId != null and tenantId != ''">tenant_id = #{tenantId},</if>
|
||||
update_time = sysdate()
|
||||
</set>
|
||||
where user_id = #{userId}
|
||||
|
||||
@ -4,14 +4,14 @@ VUE_APP_TITLE = 成事达管理平台
|
||||
# 开发环境配置
|
||||
ENV = 'development'
|
||||
|
||||
# 成事达管理平台/开发环境
|
||||
VUE_APP_BASE_API = 'http://192.168.1.13:8099'
|
||||
# 成事达管理平台/生产环境
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:8099'
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
# websocket
|
||||
VUE_APP_WEBSOCKET = 'ws://localhost:8099/ws/asset/'
|
||||
VUE_APP_WEBSOCKET = 'ws://127.0.0.1:8099/ws/asset/'
|
||||
|
||||
# 产品、文章预览
|
||||
VUE_APP_PREVIEW = 'http://192.168.1.13:3001/admin-preview/'
|
||||
VUE_APP_PREVIEW = 'https://www.cdtrucktralier.com/admin-preview/'
|
||||
|
||||
@ -5,10 +5,13 @@ VUE_APP_TITLE = 成事达管理平台
|
||||
ENV = 'production'
|
||||
|
||||
# 成事达管理平台/生产环境
|
||||
VUE_APP_BASE_API = 'http://1.92.99.15:8099'
|
||||
VUE_APP_BASE_API = 'https://admin.cdtrucktralier.com'
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
# websocket
|
||||
VUE_APP_WEBSOCKET = 'ws://1.92.99.15:8099/ws/asset/'
|
||||
VUE_APP_WEBSOCKET = 'wss://admin.cdtrucktralier.com/ws/asset/'
|
||||
|
||||
# 产品、文章预览
|
||||
VUE_APP_PREVIEW = 'http://www.lighting-it.cn/admin-preview/'
|
||||
VUE_APP_PREVIEW = 'https://www.cdtrucktralier.com/admin-preview/'
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
<theme-picker />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ThemePicker from "@/components/ThemePicker";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
@ -1,46 +1,184 @@
|
||||
|
||||
<template>
|
||||
<div class="content">
|
||||
<!-- 压缩比例设置 -->
|
||||
<div class="compression-setting">
|
||||
<div class="compression-info">
|
||||
图片压缩比例: {{ compressionRatio.toFixed(1) }}x
|
||||
<el-tooltip class="item" effect="dark" content="值越小压缩率越高,图片质量越低"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-slider
|
||||
v-model="compressionRatio"
|
||||
:min="0.1"
|
||||
:max="1.0"
|
||||
:step="0.1"
|
||||
:show-stops="true"
|
||||
:tooltip-format="formatCompressionRatio"
|
||||
></el-slider>
|
||||
</div>
|
||||
<vue-ueditor-wrap v-model="value"
|
||||
:destroy="true"
|
||||
:config="editorConfig"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:editorDependencies="['ueditor.config.js','ueditor.all.js']"
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import VueUeditorWrap from 'vue-ueditor-wrap';
|
||||
import VueUeditorWrap from 'vue-ueditor-wrap'
|
||||
|
||||
export default {
|
||||
components:{
|
||||
components: {
|
||||
VueUeditorWrap
|
||||
},
|
||||
props: {
|
||||
/* 编辑器的内容 */
|
||||
value: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newVaue,oldValue){
|
||||
this.$emit('input', newVaue);
|
||||
value(newVaue, oldValue) {
|
||||
this.$emit('input', newVaue)
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
mounted() {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editorConfig: {
|
||||
// 编辑器后端服务接口,参考后端规范 https://open-doc.modstart.com/ueditor-plus/backend.html
|
||||
serverUrl: process.env.VUE_APP_BASE_API+'/sys/ueditor/exec',
|
||||
serverUrl: process.env.VUE_APP_BASE_API + '/sys/ueditor/exec',
|
||||
UEDITOR_HOME_URL: '/UEditor/',
|
||||
//**代码补充231218**
|
||||
UEDITOR_CORS_URL: '/UEditor/',
|
||||
zIndex: 999,//设置z轴顺序值,避免工具栏下拉组件被遮挡
|
||||
// 图片上传相关配置
|
||||
imageMaxSize: 5 * 1024 * 1024, // 5MB,这里只是限制,实际压缩还需处理
|
||||
imageAllowFiles: ['.png', '.jpg', '.jpeg', '.gif', '.bmp']
|
||||
},
|
||||
// 压缩比例 (0.1-1.0)
|
||||
compressionRatio: 0.9
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 格式化压缩比例显示
|
||||
formatCompressionRatio(value) {
|
||||
return `${value.toFixed(1)}x`
|
||||
},
|
||||
/**
|
||||
* 上传前处理图片压缩
|
||||
* @param {File} file 原始文件
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
handleBeforeUpload(file, callback) {
|
||||
debugger
|
||||
// 只处理图片文件
|
||||
if (!file.type.match(/image\/\w+/)) {
|
||||
return callback(file, true) // 非图片直接上传
|
||||
}
|
||||
|
||||
// 小于100KB的图片不压缩
|
||||
if (file.size < 100 * 1024) {
|
||||
return callback(file, true)
|
||||
}
|
||||
|
||||
// 进行图片压缩
|
||||
this.compressImage(file).then(compressedFile => {
|
||||
callback(compressedFile, true)
|
||||
}).catch(err => {
|
||||
console.error('图片压缩失败:', err)
|
||||
callback(file, true) // 压缩失败则上传原图
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 图片压缩处理
|
||||
* @param {File} file 原始图片文件
|
||||
* @returns {Promise<File>} 压缩后的文件
|
||||
*/
|
||||
compressImage(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = (e) => {
|
||||
img.src = e.target.result
|
||||
}
|
||||
|
||||
img.onload = () => {
|
||||
// 创建canvas元素
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
|
||||
// 计算压缩后的尺寸
|
||||
let width = img.width
|
||||
let height = img.height
|
||||
|
||||
// 设置canvas尺寸
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
|
||||
// 绘制图片到canvas
|
||||
ctx.drawImage(img, 0, 0, width, height)
|
||||
|
||||
// 将canvas内容转为Blob
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (!blob) {
|
||||
reject(new Error('压缩失败'))
|
||||
return
|
||||
}
|
||||
|
||||
// 构建新的File对象
|
||||
const compressedFile = new File(
|
||||
[blob],
|
||||
file.name,
|
||||
{
|
||||
type: blob.type || file.type,
|
||||
lastModified: Date.now()
|
||||
}
|
||||
)
|
||||
|
||||
resolve(compressedFile)
|
||||
},
|
||||
file.type || 'image/jpeg',
|
||||
this.compressionRatio
|
||||
)
|
||||
}
|
||||
|
||||
img.onerror = (err) => {
|
||||
reject(err)
|
||||
}
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
// 压缩设置样式
|
||||
.compression-setting {
|
||||
width: 300px;
|
||||
margin-bottom: 15px;
|
||||
padding: 0 10px 8px 10px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.compression-info {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-slider__runway {
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,5 +1,25 @@
|
||||
<template>
|
||||
<div class="component-upload-image">
|
||||
<!-- 压缩比例设置 -->
|
||||
<div class="compression-setting" v-if="showCompressionSetting">
|
||||
<div class="compression-info">
|
||||
压缩比例: {{ compressionRatio.toFixed(1) }}x
|
||||
<el-tooltip class="item" effect="dark" content="值越小压缩率越高,图片质量越低"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-slider
|
||||
v-model="compressionRatio"
|
||||
:min="0.1"
|
||||
:max="1.0"
|
||||
:step="0.1"
|
||||
:show-stops="true"
|
||||
:tooltip-format="formatCompressionRatio"
|
||||
></el-slider>
|
||||
</div>
|
||||
|
||||
<el-upload
|
||||
multiple
|
||||
:action="uploadImgUrl"
|
||||
@ -17,8 +37,9 @@
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:disabled="disabled"
|
||||
:class="{hide: this.fileList.length >= this.limit}"
|
||||
:http-request="customUpload"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
|
||||
<!-- 上传提示 -->
|
||||
@ -64,7 +85,7 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
// 文件类型, 例如['png', 'jpeg', 'jpg']
|
||||
fileType: {
|
||||
type: Array,
|
||||
default: () => ["png", "jpg", "jpeg"],
|
||||
@ -73,6 +94,16 @@ export default {
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示压缩设置
|
||||
showCompression: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 默认压缩比例
|
||||
defaultCompressionRatio: {
|
||||
type: Number,
|
||||
default: 0.9
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -87,9 +118,21 @@ export default {
|
||||
headers: {
|
||||
Authorization: "Bearer " + getToken(),
|
||||
},
|
||||
fileList: []
|
||||
fileList: [],
|
||||
// 压缩比例 (0.1-1.0)
|
||||
compressionRatio: this.defaultCompressionRatio
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 是否显示提示
|
||||
showTip() {
|
||||
return this.isShowTip && (this.fileType || this.fileSize);
|
||||
},
|
||||
// 是否显示压缩设置
|
||||
showCompressionSetting() {
|
||||
return this.showCompression && !this.disabled && this.fileList.length < this.limit;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
@ -114,26 +157,32 @@ export default {
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
// 监听默认压缩比例变化
|
||||
defaultCompressionRatio: {
|
||||
handler(val) {
|
||||
this.compressionRatio = val;
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 是否显示提示
|
||||
showTip() {
|
||||
return this.isShowTip && (this.fileType || this.fileSize);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 上传前loading加载
|
||||
handleBeforeUpload(file) {
|
||||
// 格式化压缩比例显示
|
||||
formatCompressionRatio(value) {
|
||||
return `${value.toFixed(1)}x`;
|
||||
},
|
||||
|
||||
// 上传前验证
|
||||
async handleBeforeUpload(file) {
|
||||
let isImg = false;
|
||||
if (this.fileType.length) {
|
||||
let fileExtension = "";
|
||||
if (file.name.lastIndexOf(".") > -1) {
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1).toLowerCase();
|
||||
}
|
||||
isImg = this.fileType.some(type => {
|
||||
if (file.type.indexOf(type) > -1) return true;
|
||||
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
||||
if (fileExtension && fileExtension === type.toLowerCase()) return true;
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
@ -144,28 +193,151 @@ export default {
|
||||
this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}图片格式文件!`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.name.includes(',')) {
|
||||
this.$modal.msgError('文件名不正确,不能包含英文逗号!');
|
||||
return false;
|
||||
}
|
||||
if (this.fileSize) {
|
||||
const isLt = file.size / 1024 / 1024 < this.fileSize;
|
||||
if (!isLt) {
|
||||
this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.$modal.loading("正在上传图片,请稍候...");
|
||||
|
||||
// 这里只做验证,不限制大小,因为用户可以通过压缩来减小文件大小
|
||||
this.$modal.loading("正在处理图片,请稍候...");
|
||||
this.number++;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// 自定义上传方法,包含压缩逻辑
|
||||
customUpload(options) {
|
||||
const file = options.file;
|
||||
|
||||
// 调用图片压缩方法
|
||||
this.compressImage(file, this.compressionRatio)
|
||||
.then(compressedFile => {
|
||||
// 创建FormData对象,模拟表单提交
|
||||
const formData = new FormData();
|
||||
formData.append('file', compressedFile, file.name);
|
||||
|
||||
// 创建XMLHttpRequest对象
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('post', this.uploadImgUrl, true);
|
||||
|
||||
// 设置请求头
|
||||
Object.keys(this.headers).forEach(key => {
|
||||
xhr.setRequestHeader(key, this.headers[key]);
|
||||
});
|
||||
|
||||
// 上传进度处理
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.total > 0) {
|
||||
e.percent = e.loaded / e.total * 100;
|
||||
}
|
||||
options.onProgress(e);
|
||||
});
|
||||
|
||||
// 上传成功处理
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
options.onSuccess(response);
|
||||
} else {
|
||||
options.onError(xhr.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
// 上传错误处理
|
||||
xhr.addEventListener('error', () => {
|
||||
options.onError(xhr.responseText);
|
||||
});
|
||||
|
||||
// 发送请求
|
||||
xhr.send(formData);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$modal.msgError('图片压缩失败: ' + error.message);
|
||||
this.$modal.closeLoading();
|
||||
this.number--;
|
||||
options.onError(error);
|
||||
});
|
||||
},
|
||||
|
||||
// 图片压缩核心方法
|
||||
compressImage(file, quality = 0.8) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 如果不是图片,直接返回原文件
|
||||
if (!file.type.match(/image.*/)) {
|
||||
resolve(file);
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (e) => {
|
||||
const img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
// 创建canvas元素
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 设置canvas尺寸,保持原图比例
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// 在canvas上绘制图片
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
// 获取图片类型
|
||||
const mimeType = file.type || 'image/jpeg';
|
||||
|
||||
// 将canvas内容转为Blob对象
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) {
|
||||
reject(new Error('无法压缩图片'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 将Blob转为File对象
|
||||
const compressedFile = new File([blob], file.name, {
|
||||
type: mimeType,
|
||||
lastModified: Date.now()
|
||||
});
|
||||
|
||||
resolve(compressedFile);
|
||||
}, mimeType, quality);
|
||||
};
|
||||
|
||||
img.onerror = (error) => {
|
||||
reject(new Error('无法加载图片进行压缩'));
|
||||
};
|
||||
|
||||
// 加载图片
|
||||
img.src = e.target.result;
|
||||
};
|
||||
|
||||
reader.onerror = (error) => {
|
||||
reject(new Error('无法读取图片文件'));
|
||||
};
|
||||
|
||||
// 读取文件
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
},
|
||||
|
||||
// 文件个数超出
|
||||
handleExceed() {
|
||||
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
|
||||
},
|
||||
|
||||
// 上传成功回调
|
||||
handleUploadSuccess(res, file) {
|
||||
if (res.code === 200) {
|
||||
this.uploadList.push({ name: res.name, url: res.fileName,size:res.size,width:res.width,height:res.height });
|
||||
this.uploadList.push({
|
||||
name: res.name,
|
||||
url: res.fileName,
|
||||
size: res.size,
|
||||
width: res.width,
|
||||
height: res.height
|
||||
});
|
||||
this.uploadedSuccessfully();
|
||||
} else {
|
||||
this.number--;
|
||||
@ -175,6 +347,7 @@ export default {
|
||||
this.uploadedSuccessfully();
|
||||
}
|
||||
},
|
||||
|
||||
// 删除图片
|
||||
handleDelete(file) {
|
||||
const findex = this.fileList.map(f => f.name).indexOf(file.name);
|
||||
@ -183,27 +356,31 @@ export default {
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
}
|
||||
},
|
||||
|
||||
// 上传失败
|
||||
handleUploadError() {
|
||||
this.$modal.msgError("上传图片失败,请重试");
|
||||
this.$modal.closeLoading();
|
||||
},
|
||||
|
||||
// 上传结束处理
|
||||
uploadedSuccessfully() {
|
||||
if (this.number > 0 && this.uploadList.length === this.number) {
|
||||
this.fileList = this.fileList.concat(this.uploadList);
|
||||
this.$emit('uploadedImg',this.fileList)
|
||||
this.$emit('uploadedImg', this.fileList);
|
||||
this.uploadList = [];
|
||||
this.number = 0;
|
||||
this.$emit("input", this.listToString(this.fileList));
|
||||
this.$modal.closeLoading();
|
||||
}
|
||||
},
|
||||
|
||||
// 预览
|
||||
handlePictureCardPreview(file) {
|
||||
this.dialogImageUrl = file.url;
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
|
||||
// 对象转成指定字符串分隔
|
||||
listToString(list, separator) {
|
||||
let strs = "";
|
||||
@ -213,7 +390,7 @@ export default {
|
||||
strs += list[i].url.replace(this.baseUrl, "") + separator;
|
||||
}
|
||||
}
|
||||
return strs != '' ? strs.substr(0, strs.length - 1) : '';
|
||||
return strs !== '' ? strs.substr(0, strs.length - 1) : '';
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -223,6 +400,7 @@ export default {
|
||||
::v-deep.hide .el-upload--picture-card {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 去掉动画效果
|
||||
::v-deep .el-list-enter-active,
|
||||
::v-deep .el-list-leave-active {
|
||||
@ -233,6 +411,21 @@ export default {
|
||||
opacity: 0;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
// 压缩设置样式
|
||||
.compression-setting {
|
||||
margin-bottom: 15px;
|
||||
padding: 0 10px 8px 10px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.compression-info {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
::v-deep .el-slider__runway{
|
||||
margin:0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@ -23,14 +23,18 @@ const websocket = {
|
||||
console.log(e.data)
|
||||
}else {
|
||||
console.log(e.data,'消息内容')
|
||||
let messageData;
|
||||
//这里捕获消息
|
||||
const messageData = JSON.parse(e.data)
|
||||
// 触发事件通知
|
||||
EventBus.$emit('newMessage', messageData);
|
||||
//存储消息
|
||||
state.message.push(messageData);
|
||||
try {
|
||||
messageData = JSON.parse(e.data)
|
||||
// 触发事件通知
|
||||
EventBus.$emit('newMessage', messageData);
|
||||
//存储消息
|
||||
state.message.push(messageData);
|
||||
}catch (e) {
|
||||
console.log("无法识别的消息");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
state.socket.onerror= function () {
|
||||
console.log("WebSocket连接发生错误");
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['base:app:edit']"
|
||||
>修改</el-button>
|
||||
>下载</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
@ -69,7 +69,10 @@
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="版本" prop="version">
|
||||
<el-input v-model="form.version" placeholder="请输入版本" />
|
||||
<el-input type="input" v-model="form.version" placeholder="请输入版本" />
|
||||
</el-form-item>
|
||||
<el-form-item label="app包" prop="apkUrl">
|
||||
<file-upload v-model="form.apkUrl" :limit="1" :fileType="fileType" :fileSize="50"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本次升级描述" prop="content">
|
||||
<el-input v-model="form.content" type="textarea" placeholder="请输入内容" />
|
||||
@ -122,7 +125,11 @@ export default {
|
||||
version: [
|
||||
{ required: true, message: '请输入版本号', trigger: 'blur' }
|
||||
],
|
||||
}
|
||||
apkUrl: [
|
||||
{ required: true, message: '请上传程序包', trigger: 'blur' }
|
||||
],
|
||||
},
|
||||
baseUrl: process.env.VUE_APP_BASE_API,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@ -148,6 +155,7 @@ export default {
|
||||
this.form = {
|
||||
id: null,
|
||||
version: null,
|
||||
apkUrl: null,
|
||||
content: null,
|
||||
creator: null,
|
||||
createTime: null,
|
||||
@ -179,15 +187,18 @@ export default {
|
||||
this.open = true;
|
||||
this.title = "添加app版本管理";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
/** 下载 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id || this.ids
|
||||
getApp(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改app版本管理";
|
||||
});
|
||||
let a = document.createElement("a"); // 创建a标签
|
||||
a.style.display = "none";
|
||||
a.href = this.baseUrl + "/web/downloadApk?id="+row.id;
|
||||
a.setAttribute(
|
||||
"download",
|
||||
a.href.split("/")[a.href.split("/").length - 1]
|
||||
); // 给a标签设置download属性值,为从接口中获取到的需要下载的文件地址
|
||||
document.body.appendChild(a); // 将标签添加到页面
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
<!-- 添加或修改站点管理对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="站点编码" prop="siteName">
|
||||
<el-form-item label="站点编码" prop="id">
|
||||
<el-input v-model="form.id" placeholder="请输入站点编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="站点名称" prop="siteName">
|
||||
@ -179,7 +179,15 @@ export default {
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
|
||||
id: [
|
||||
{ required: true, message: '请输入站点编码', trigger: 'blur' }
|
||||
],
|
||||
siteName: [
|
||||
{ required: true, message: '请输入站点名称', trigger: 'blur' }
|
||||
],
|
||||
siteUrl: [
|
||||
{ required: true, message: '请输入站点网址', trigger: 'blur' }
|
||||
],
|
||||
},
|
||||
//当前处理的数据id
|
||||
dealId:null,
|
||||
|
||||
@ -24,62 +24,62 @@
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToTwitter"
|
||||
>Twitter</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToFacebook"
|
||||
>Facebook</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToLinkedin"
|
||||
>Linkedin</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToPinterest"
|
||||
>Pinterest</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToWhatsapp"
|
||||
>Whatsapp</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToWhatsapp2"
|
||||
>Whatsapp8618253112969</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="shareToEmail"
|
||||
>E-mail:alicesales@scdtrailer.com</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToTwitter"-->
|
||||
<!-- >Twitter</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToFacebook"-->
|
||||
<!-- >Facebook</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToLinkedin"-->
|
||||
<!-- >Linkedin</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToPinterest"-->
|
||||
<!-- >Pinterest</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToWhatsapp"-->
|
||||
<!-- >Whatsapp</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToWhatsapp2"-->
|
||||
<!-- >Whatsapp8618253112969</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="shareToEmail"-->
|
||||
<!-- >E-mail:alicesales@scdtrailer.com</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
<el-table
|
||||
@ -87,7 +87,12 @@
|
||||
border
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
v-loading="loading" :data="categoryList" >
|
||||
<el-table-column label="栏目名称" align="left" prop="catgName" />
|
||||
<el-table-column label="栏目名称" align="left" prop="catgName" >
|
||||
<template slot-scope="scope" >
|
||||
{{scope.row.catgName}}
|
||||
<template v-if="checkIfAppCatg(scope.row.id)"><el-tag>APP</el-tag></template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="栏目级别" align="center" prop="catgLevel">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.catgLevel}}级栏目
|
||||
@ -161,7 +166,7 @@ import { listCategory,delCategory} from "@/api/busi/category";
|
||||
export default {
|
||||
name: "Category",
|
||||
components:{},
|
||||
dicts: ['category_type'],
|
||||
dicts: ['category_type','app_menu'],
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
@ -233,7 +238,18 @@ export default {
|
||||
const url = `https://www.cdtruck.com/OutOpen/AddEmailRecord?callback=result&fromEmail=alicesales@scdtrailer.com&pathPage=https://www.cdtruck.com/&typeid=F9&_=1751524873382`
|
||||
window.open(url, "_blank");
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断是否APP栏目
|
||||
*/
|
||||
checkIfAppCatg(catgId){
|
||||
let arra = this.dict.type.app_menu
|
||||
for(let i=0;i<arra.length;i++){
|
||||
if(arra[i].label == catgId){
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
/** 查询网站栏目列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
|
||||
@ -48,16 +48,16 @@
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="primary"-->
|
||||
<!-- plain-->
|
||||
<!-- icon="el-icon-plus"-->
|
||||
<!-- size="mini"-->
|
||||
<!-- @click="handleAdd"-->
|
||||
<!-- v-hasPermi="['busi:chatMain:add']"-->
|
||||
<!-- >新增</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button-->
|
||||
<!-- type="success"-->
|
||||
|
||||
@ -215,6 +215,7 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
.session-list {
|
||||
z-index: 999;
|
||||
max-width: 350px;
|
||||
max-height: 400px;
|
||||
position: absolute;
|
||||
|
||||
@ -4,6 +4,16 @@
|
||||
<el-form-item label="分类" prop="catgId">
|
||||
<treeselect style="width: 200px" v-model="queryParams.catgId" :options="catgOptions" :normalizer="normalizer" :noResultsText="'暂无数据'" placeholder="选择分类" />
|
||||
</el-form-item>
|
||||
<el-form-item label="展示平台" prop="showPlat">
|
||||
<el-select v-model="queryParams.showPlat" placeholder="请选择展示平台" clearable>
|
||||
<el-option
|
||||
v-for="dict in dict.type.show_plateform"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="新闻标题" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.title"
|
||||
@ -75,6 +85,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="新闻负责人" align="center" prop="leaderName" />
|
||||
<el-table-column label="展示平台" align="center" prop="showPlat" />
|
||||
<!-- <el-table-column label="产品简介" align="center" prop="description" />-->
|
||||
<el-table-column width="100" label="排序" align="center" prop="sort">
|
||||
<template slot="header" slot-scope="scope">
|
||||
@ -190,7 +201,7 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
|
||||
export default {
|
||||
name: "New",
|
||||
dicts: ['sys_yes_no'],
|
||||
dicts: ['sys_yes_no','show_plateform'],
|
||||
components: { selectAllUser,selectProduct,randomProduct ,Treeselect},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<el-button type="success" @click="saveTmp">暂 存</el-button>
|
||||
<el-button type="primary" @click="submitForm">发 布</el-button>
|
||||
<el-button type="warning" @click="checkContent">相似度检测</el-button>
|
||||
<el-button @click="preview">文章预览</el-button>
|
||||
<el-button @click="toggleSideBar">{{ showKeywords ? '关闭' : '打开' }}关键词推荐</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -104,7 +105,7 @@
|
||||
<el-form-item label="所属分类" prop="catgId">
|
||||
<div class="dl-flex-column">
|
||||
<treeselect style="width: 200px" v-model="form.catgId" :options="catgOptions" :normalizer="normalizer"
|
||||
:noResultsText="'暂无数据'" placeholder="请选择新闻分类"
|
||||
:noResultsText="'暂无数据'" placeholder="请选择新闻分类" :disable-branch-nodes="true"
|
||||
/>
|
||||
<div class="dl-add-catg" @click="goCatgView">添加新闻分类</div>
|
||||
</div>
|
||||
@ -183,7 +184,7 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-col :span="9">
|
||||
<el-form-item label="新闻图" prop="mainPic">
|
||||
<el-tag v-if="!form.mainPic" style="cursor: pointer" @click="choosePic('mainPic',1)">图片库选择</el-tag>
|
||||
<image-upload @uploadedImg="uploadedImg" v-model="form.mainPic" :limit="1"/>
|
||||
@ -201,10 +202,21 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="展示平台" prop="showPlat">
|
||||
<el-checkbox-group v-model="showPlatList" @change="changeCheckBox">
|
||||
<el-checkbox v-for="dict in dict.type.show_plateform" :label="dict.label" :value="dict.value"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="新闻内容">
|
||||
<editor :key="showKeywords" v-model="form.content" :min-height="192"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="新闻内容">
|
||||
<editor :key="showKeywords" v-model="form.content" :min-height="192"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -215,6 +227,7 @@
|
||||
<el-button type="success" @click="saveTmp">暂 存</el-button>
|
||||
<el-button type="primary" @click="submitForm">发 布</el-button>
|
||||
<el-button type="warning" @click="checkContent">相似度检测</el-button>
|
||||
<el-button @click="preview">文章预览</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@ -246,6 +259,7 @@ import SimilarityNew from './similarityNew'
|
||||
export default {
|
||||
name: 'newForm',
|
||||
components: { SimilarityNew, Treeselect, selectPic , Hamburger , countTo},
|
||||
dicts: ['show_plateform'],
|
||||
data() {
|
||||
return {
|
||||
//光标位置--简介
|
||||
@ -267,6 +281,7 @@ export default {
|
||||
prodTitle: null,
|
||||
prodKeyword: null,
|
||||
prodDescription: null,
|
||||
showPlat: '网站,App',
|
||||
newsFrom: null,
|
||||
publicDate: null,
|
||||
mainPic: null,
|
||||
@ -285,6 +300,8 @@ export default {
|
||||
//当前上传的所有图片
|
||||
fileList: []
|
||||
},
|
||||
//选中的展示平台
|
||||
showPlatList:['网站','App'],
|
||||
formSeo: {
|
||||
title: '',
|
||||
needUrl: true,
|
||||
@ -325,6 +342,9 @@ export default {
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: '请输入新闻简介', trigger: 'blur' }
|
||||
],
|
||||
showPlat: [
|
||||
{ required: true, message: '请选择展示平台', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
rulesSeo:{
|
||||
@ -356,6 +376,12 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 选中展示平台
|
||||
*/
|
||||
changeCheckBox(value){
|
||||
this.form.showPlat = value.join(",")
|
||||
},
|
||||
useProdName(){
|
||||
this.formSeo.title = this.form.title
|
||||
},
|
||||
@ -393,6 +419,17 @@ export default {
|
||||
toggleSideBar() {
|
||||
this.showKeywords = !this.showKeywords
|
||||
},
|
||||
/**
|
||||
* 预览文章
|
||||
*/
|
||||
preview(){
|
||||
if(!this.form.id){
|
||||
this.$modal.msgWarning("请先保存或暂存新闻信息!")
|
||||
return
|
||||
}
|
||||
let url =this.previewPrex+this.form.id+"?private=1BC0FFEC2294283E9BDB89E188FCA574"
|
||||
window.open(url)
|
||||
},
|
||||
// 更多操作触发
|
||||
handleCommand(command, row) {
|
||||
switch (command) {
|
||||
@ -458,6 +495,7 @@ export default {
|
||||
getProdInfo(id, type) {
|
||||
getProdNew(id).then(response => {
|
||||
this.form = response.data
|
||||
this.showPlatList = this.form.showPlat.split(',')
|
||||
if (this.form.pics && this.form.pics.length > 0) {
|
||||
this.canPicsNum = this.picsNum - this.form.pics.split(',').length
|
||||
}
|
||||
|
||||
@ -4,6 +4,16 @@
|
||||
<el-form-item label="分类" prop="catgId">
|
||||
<treeselect style="width: 200px" v-model="queryParams.catgId" :options="catgOptions" :normalizer="normalizer" :noResultsText="'暂无数据'" placeholder="选择分类" />
|
||||
</el-form-item>
|
||||
<el-form-item label="展示平台" prop="showPlat">
|
||||
<el-select v-model="queryParams.showPlat" placeholder="请选择展示平台" clearable>
|
||||
<el-option
|
||||
v-for="dict in dict.type.show_plateform"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称" prop="title">
|
||||
<el-input
|
||||
v-model="queryParams.title"
|
||||
@ -74,7 +84,8 @@
|
||||
<image-preview :src="scope.row.mainPic" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品负责人" align="center" prop="leaderName" :min-width="200" />
|
||||
<el-table-column label="产品负责人" align="center" prop="leaderName" :min-width="100" />
|
||||
<el-table-column label="展示平台" align="center" prop="showPlat" />
|
||||
<!-- <el-table-column label="产品简介" align="center" prop="description" />-->
|
||||
<el-table-column width="100" label="排序" align="center" prop="sort">
|
||||
<template slot="header" slot-scope="scope">
|
||||
@ -190,7 +201,7 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
|
||||
export default {
|
||||
name: "Prod",
|
||||
dicts: ['sys_yes_no'],
|
||||
dicts: ['sys_yes_no','show_plateform'],
|
||||
components: { selectAllUser ,selectProduct,randomProduct,Treeselect},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<el-button type="success" @click="saveTmp">暂 存</el-button>
|
||||
<el-button type="primary" @click="submitForm">发 布</el-button>
|
||||
<el-button type="warning" @click="checkContent">相似度检测</el-button>
|
||||
<el-button @click="preview">产品预览</el-button>
|
||||
<el-button @click="toggleSideBar">{{ showKeywords ? '关闭' : '打开' }}关键词推荐</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -101,7 +102,7 @@
|
||||
<el-form-item label="所属分类" prop="catgId">
|
||||
<div class="dl-flex-column">
|
||||
<treeselect style="width: 200px" v-model="form.catgId" :options="catgOptions" :normalizer="normalizer"
|
||||
:noResultsText="'暂无数据'" placeholder="请选择产品分类"
|
||||
:noResultsText="'暂无数据'" placeholder="请选择产品分类" :disable-branch-nodes="true"
|
||||
/>
|
||||
<div class="dl-add-catg" @click="goCatgView">添加产品分类</div>
|
||||
</div>
|
||||
@ -171,11 +172,20 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="首页显示" prop="ifReco">
|
||||
<el-form-item label="展示平台" prop="showPlat">
|
||||
<el-checkbox-group v-model="showPlatList" @change="changeCheckBox">
|
||||
<el-checkbox v-for="dict in dict.type.show_plateform" :label="dict.label" :value="dict.value"></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="网站首页显示" prop="ifReco">
|
||||
<template v-slot:label>
|
||||
<span>首页显示</span>
|
||||
<el-tooltip class="item" effect="dark" content="开启后将在首页优先显示"
|
||||
<span>网站首页显示</span>
|
||||
<el-tooltip class="item" effect="dark" content="开启后将在网站首页优先显示"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-question"></i>
|
||||
@ -188,9 +198,13 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="产品内容">
|
||||
<editor :key="showKeywords" v-model="form.content" :min-height="192"/>
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="产品内容">
|
||||
<editor :key="showKeywords" v-model="form.content" :min-height="192"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -201,6 +215,7 @@
|
||||
<el-button type="success" @click="saveTmp">暂 存</el-button>
|
||||
<el-button type="primary" @click="submitForm">发 布</el-button>
|
||||
<el-button type="warning" @click="checkContent">相似度检测</el-button>
|
||||
<el-button @click="preview">产品预览</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@ -232,6 +247,7 @@ import SimilarityProduct from './similarityProduct'
|
||||
export default {
|
||||
name: 'prodForm',
|
||||
components: { SimilarityProduct, Treeselect, selectPic, Hamburger , countTo},
|
||||
dicts: ['show_plateform'],
|
||||
data() {
|
||||
return {
|
||||
//光标位置--简介
|
||||
@ -253,6 +269,7 @@ export default {
|
||||
prodTitle: null,
|
||||
prodKeyword: null,
|
||||
prodDescription: null,
|
||||
showPlat: '网站,App',
|
||||
newsFrom: null,
|
||||
mainPic: null,
|
||||
pics: null,
|
||||
@ -270,6 +287,8 @@ export default {
|
||||
//当前上传的所有图片
|
||||
fileList: []
|
||||
},
|
||||
//选中的展示平台
|
||||
showPlatList:['网站','App'],
|
||||
formSeo: {
|
||||
title: '',
|
||||
needUrl: true,
|
||||
@ -304,6 +323,9 @@ export default {
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: '请输入产品简介', trigger: 'blur' }
|
||||
],
|
||||
showPlat: [
|
||||
{ required: true, message: '请选择展示平台', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
rulesSeo:{
|
||||
@ -335,6 +357,12 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 选中展示平台
|
||||
*/
|
||||
changeCheckBox(value){
|
||||
this.form.showPlat = value.join(",")
|
||||
},
|
||||
useProdName(){
|
||||
this.formSeo.title = this.form.title
|
||||
},
|
||||
@ -372,6 +400,17 @@ export default {
|
||||
toggleSideBar() {
|
||||
this.showKeywords = !this.showKeywords
|
||||
},
|
||||
/**
|
||||
* 预览产品
|
||||
*/
|
||||
preview(){
|
||||
if(!this.form.id){
|
||||
this.$modal.msgWarning("请先保存或暂存产品信息!")
|
||||
return
|
||||
}
|
||||
let url =this.previewPrex+this.form.id+"?private=CAC8F0807B8FB7EA72AF3596600F888A"
|
||||
window.open(url)
|
||||
},
|
||||
// 更多操作触发
|
||||
handleCommand(command, row) {
|
||||
switch (command) {
|
||||
@ -437,6 +476,7 @@ export default {
|
||||
getProdInfo(id, type) {
|
||||
getProdNew(id).then(response => {
|
||||
this.form = response.data
|
||||
this.showPlatList = this.form.showPlat.split(',')
|
||||
if (this.form.pics && this.form.pics.length > 0) {
|
||||
this.canPicsNum = this.picsNum - this.form.pics.split(',').length
|
||||
}
|
||||
|
||||
@ -31,14 +31,14 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="请输入产品名称" prop="prodName">
|
||||
<el-input
|
||||
v-model="queryParams.prodName"
|
||||
placeholder="请输入产品名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="请输入产品名称" prop="prodName">-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="queryParams.prodName"-->
|
||||
<!-- placeholder="请输入产品名称"-->
|
||||
<!-- clearable-->
|
||||
<!-- @keyup.enter.native="handleQuery"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="来源国家" prop="national">
|
||||
<el-input
|
||||
v-model="queryParams.national"
|
||||
@ -132,20 +132,20 @@
|
||||
<el-table v-loading="loading" :data="thirdItemList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="index" width="60" label="序号" align="center"/>
|
||||
<!-- <el-table-column type="selection" width="55" align="center" />-->
|
||||
<el-table-column label="产品名称" align="center" prop="prodName" :min-width="120">
|
||||
<template slot="header" slot-scope="scope">
|
||||
<span>产品名称</span>
|
||||
<el-tooltip class="item" effect="dark" content="鼠标单机数据可查看产品详情"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<span @click="goProdDetail(scope.row.prodId)" style="color: #1890ff;cursor: pointer"
|
||||
>{{ scope.row.prodName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="产品名称" align="center" prop="prodName" :min-width="120">-->
|
||||
<!-- <template slot="header" slot-scope="scope">-->
|
||||
<!-- <span>产品名称</span>-->
|
||||
<!-- <el-tooltip class="item" effect="dark" content="鼠标单机数据可查看产品详情"-->
|
||||
<!-- placement="bottom"-->
|
||||
<!-- >-->
|
||||
<!-- <i class="el-icon-question"></i>-->
|
||||
<!-- </el-tooltip>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template slot-scope="scope">-->
|
||||
<!-- <span @click="goProdDetail(scope.row.prodId)" style="color: #1890ff;cursor: pointer"-->
|
||||
<!-- >{{ scope.row.prodName }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column label="三方程序类型" align="center" prop="thirdSoft" width="100">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.third_soft" :value="scope.row.thirdSoft"/>
|
||||
|
||||
@ -47,19 +47,19 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
|
||||
</el-col>
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<!-- <el-col :span="1.5">-->
|
||||
<!-- <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>-->
|
||||
<!-- </el-col>-->
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
||||
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="登录账户" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
|
||||
@ -123,8 +123,8 @@
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
||||
<el-form-item v-if="form.userId == undefined" label="登录账户" prop="userName">
|
||||
<el-input v-model="form.userName" placeholder="请输入登录账户" maxlength="30" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@ -395,6 +395,7 @@ export default {
|
||||
nickName: undefined,
|
||||
password: undefined,
|
||||
phonenumber: undefined,
|
||||
tenantId: undefined,
|
||||
email: undefined,
|
||||
sex: undefined,
|
||||
status: "0",
|
||||
@ -550,4 +551,4 @@ export default {
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user