项目更新,增加了商品展示图片在线马赛克设置

This commit is contained in:
1215525055@qq.com 2025-05-28 15:25:27 +08:00
parent cbccbb925f
commit 173e0517f5
15 changed files with 701 additions and 51 deletions

View File

@ -17,6 +17,7 @@ import com.alibaba.fastjson.JSONArray;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.common.component.SecurityComponent;
import ink.wgink.exceptions.SaveException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.file.enums.UploadTypeEnum;
import ink.wgink.module.file.service.IDefaultFileService;
@ -52,7 +53,7 @@ import java.util.*;
* @Date: 2025-05-20 14:10:16
* @Version: 3.0
**/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "APP电子软著接口")
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "电子软著接口")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/apporder")
public class AppOrderController extends DefaultBaseController {
@ -73,9 +74,9 @@ public class AppOrderController extends DefaultBaseController {
@Autowired
private IDefaultFileService iFileService2;
/* @ApiOperation(value = "价格列表", notes = "价格列表接口")*/
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("money-list")
@CheckRequestBodyAnnotation
public JSONArray moneyList() {
return JSON.parseArray(ProjectConfigUtil.getText("MoneyAndDate").trim());
}
@ -143,8 +144,8 @@ public class AppOrderController extends DefaultBaseController {
response.flushBuffer();
}
@ApiOperation(value = "转让协议书", notes = "转让协议书接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "转让协议书", notes = "转让协议书接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@GetMapping("create-file/{templateCode}/{id}")
public FilePO createXieYi(@PathVariable("templateCode") String templateCode, @PathVariable("id") String id, String name, HttpServletRequest request, HttpServletResponse response) throws Exception {
// CBC 其他模块批量生成示例代码, 遍历您的业务数据集循环调用下列代码, 如果需要实时生成, 请在您的新增修改的结尾调用下面代码 17691030315
@ -189,8 +190,8 @@ public class AppOrderController extends DefaultBaseController {
return iFileService2.getPO(fileId);
}
@ApiOperation(value = "付款", notes = "付款接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "付款", notes = "付款接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("pay/{orderMoneyId}")
@CheckRequestBodyAnnotation
public SuccessResultData<String> save(@PathVariable("orderMoneyId") String orderMoneyId) {
@ -198,8 +199,8 @@ public class AppOrderController extends DefaultBaseController {
return new SuccessResultData<>(orderId);
}
@ApiOperation(value = "下证上传", notes = "下证上传接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "下证上传", notes = "下证上传接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/success/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult updateCheck(@PathVariable("appOrderId") String appOrderId, @RequestBody AppOrderSuccessVO appOrderSuccessVO) {
@ -207,8 +208,8 @@ public class AppOrderController extends DefaultBaseController {
return new SuccessResult();
}
@ApiOperation(value = "后台审核", notes = "后台审核接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "后台审核", notes = "后台审核接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/check/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult updateCheck(@PathVariable("appOrderId") String appOrderId, @RequestBody AppOrderCheckVO appOrderCheckVO) {
@ -216,8 +217,8 @@ public class AppOrderController extends DefaultBaseController {
return new SuccessResult();
}
@ApiOperation(value = "提交审核", notes = "提交审核接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "提交审核", notes = "提交审核接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/sub-check/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult updateSubCheck(@PathVariable("appOrderId") String appOrderId) {
@ -225,8 +226,8 @@ public class AppOrderController extends DefaultBaseController {
return new SuccessResult();
}
@ApiOperation(value = "鉴别材料", notes = "鉴别材料接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "鉴别材料", notes = "鉴别材料接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/3/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult save(@PathVariable("appOrderId") String appOrderId, @RequestBody AppOrder3VO vo) {
@ -235,18 +236,23 @@ public class AppOrderController extends DefaultBaseController {
return new SuccessResult();
}
@ApiOperation(value = "软件基本信息", notes = "软件基本信息接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "软件基本信息", notes = "软件基本信息接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/2/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult save(@PathVariable("appOrderId") String appOrderId, @RequestBody AppOrder2VO vo) {
if(!vo.getDevelopWay().equals("独立开发")) {
if(StringUtils.isEmpty(vo.getGetFile())) {
throw new SaveException("合作协议不能为空");
}
}
Map<String, Object> params = HashMapUtil.beanToMap(vo);
appOrderService.saveData(appOrderId, 2, params);
return new SuccessResult();
}
@ApiOperation(value = "企业/机构认证", notes = "企业/机构认证接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
/* @ApiOperation(value = "企业/机构认证", notes = "企业/机构认证接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})*/
@PostMapping("update/1/{appOrderId}")
@CheckRequestBodyAnnotation
public SuccessResult save(@PathVariable("appOrderId") String appOrderId, @RequestBody AppOrder1VO vo) {

View File

@ -40,10 +40,13 @@ public class GoodsonlineController extends DefaultBaseController {
@ApiImplicitParam(name = "keywords", value = "关键字", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "startTime", value = "开始时间", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "endTime", value = "结束时间", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "goodsGetTime'", value = "取得时间 年", paramType = "query", dataType = "String"),
/* @ApiImplicitParam(name = "goodsGetTime'", value = "取得时间 年", paramType = "query", dataType = "String"),*/
@ApiImplicitParam(name = "goodsGetType", value = "所有者类型", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "goodsDevelop", value = "软著开发语言", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "goodsType", value = "软著类型", paramType = "query", dataType = "String")
@ApiImplicitParam(name = "goodsType", value = "软著类型", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "priceRangeStart", value = "价格区间", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "priceRangeEnd", value = "价格区间", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "priceOrder", value = "DESC或ASC", paramType = "query", dataType = "String")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("listpage")

View File

@ -44,6 +44,10 @@ public class GoodsRouteController extends DefaultBaseController {
public ModelAndView image() {
return new ModelAndView("goods/image");
}
@GetMapping("image2")
public ModelAndView image2() {
return new ModelAndView("goods/image2");
}
@GetMapping("update")

View File

@ -1,5 +1,6 @@
package cn.com.tenlion.aishop.pojo.dtos.goods;
import cn.com.tenlion.aishop.util.ShopDateUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -47,11 +48,22 @@ public class GoodsSimpleDTO {
private String goodsStatusTime;
@ApiModelProperty(name = "goodsLastTime", value = "软件截止售卖时间")
private String goodsLastTime;
@ApiModelProperty(name = "goodsLastDay", value = "软件截止售卖天数")
private Long goodsLastDay;
@ApiModelProperty(name = "goodsVnumber", value = "版本")
private Integer goodsVnumber;
@ApiModelProperty(name = "goodsFlag", value = "商品标签")
private String goodsFlag;
public Long getGoodsLastDay() {
long lastDay = ShopDateUtils.calculateDaysDifference(goodsLastTime);
return lastDay;
}
public void setGoodsLastDay(Long goodsLastDay) {
this.goodsLastDay = goodsLastDay;
}
public String getGoodsFlag() {
return goodsFlag == null ? "" : goodsFlag.trim();
}

View File

@ -23,7 +23,6 @@ public class AppOrder2VO {
@CheckEmptyAnnotation(name = "软件名称")
private String appName;
@ApiModelProperty(name = "subName", value = "软件简称")
@CheckEmptyAnnotation(name = "软件简称")
private String subName;
@ApiModelProperty(name = "versionName", value = "版本号")
@CheckEmptyAnnotation(name = "版本号")
@ -54,7 +53,6 @@ public class AppOrder2VO {
@ApiModelProperty(name = "projOwnerIdentity", value = "著作权人证件号")
private String projOwnerIdentity;
@ApiModelProperty(name = "getFile", value = "合作协议")
@CheckEmptyAnnotation(name = "合作协议")
private String getFile;
public String getProjOwnerId() {

View File

@ -91,7 +91,7 @@ public class AppOrderServiceImpl extends DefaultBaseService implements IAppOrder
// 获取第 i 个元素JSONObject 类型
JSONObject obj = jsonArray.getJSONObject(i);
String id = obj.getString("id");
if(id == orderMoneyId) {
if(id.equals(orderMoneyId)) {
data = obj;
}
}
@ -103,7 +103,7 @@ public class AppOrderServiceImpl extends DefaultBaseService implements IAppOrder
throw new SaveException("价格配置异常");
}
Integer day = data.getInteger("day");
Integer title = data.getInteger("title");
String title = data.getString("title");
UserInfoBO userInfoBO = this.securityComponent.getCurrentUser();
String userId = userInfoBO.getUserId();
String orderNO = generateOrderNumber();

View File

@ -3,6 +3,7 @@ package cn.com.tenlion.aishop.service.goodsonline.impl;
import cn.com.tenlion.aishop.pojo.dtos.goods.GoodsDTO;
import cn.com.tenlion.aishop.pojo.dtos.goods.GoodsSimpleDTO;
import cn.com.tenlion.aishop.service.goods.IGoodsService;
import cn.com.tenlion.aishop.util.ShopDateUtils;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.module.dictionary.pojo.dtos.AreaDTO;
import ink.wgink.module.dictionary.pojo.dtos.DataDTO;

View File

@ -0,0 +1,45 @@
package cn.com.tenlion.aishop.util;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
public class ShopDateUtils {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* 计算当前日期与指定日期之间的天数差
* @param dateStr 格式为"yyyy-MM-dd"的日期字符串
* @return 天数差当前日期在前时返回负数目标日期在前时返回正数
* @throws DateTimeParseException 当日期格式不正确时抛出
*/
public static long calculateDaysDifference(String dateStr) {
LocalDate targetDate = LocalDate.parse(dateStr, FORMATTER);
LocalDate currentDate = LocalDate.now();
return ChronoUnit.DAYS.between(currentDate, targetDate);
}
/**
* 获取两个日期之间的绝对天数差不考虑顺序
* @param dateStr 格式为"yyyy-MM-dd"的日期字符串
* @return 绝对天数差
* @throws DateTimeParseException 当日期格式不正确时抛出
*/
public static long getAbsoluteDaysDifference(String dateStr) {
return Math.abs(calculateDaysDifference(dateStr));
}
public static void main(String[] args) {
// 示例用法
try {
System.out.println(calculateDaysDifference("2025-05-28")); // 输出 0同一天
System.out.println(calculateDaysDifference("2025-05-30")); // 输出 2未来日期
System.out.println(calculateDaysDifference("2025-05-25")); // 输出 -3过去日期
System.out.println(getAbsoluteDaysDifference("2025-05-25")); // 输出 3绝对值
} catch (DateTimeParseException e) {
System.err.println("日期格式错误: " + e.getMessage());
}
}
}

View File

@ -139,9 +139,6 @@ logging:
root: error
ink.wgink: debug
cn.com.tenlion.*: debug
# 开启JDBC和MyBatis日志显示SQL执行详情
org.springframework.jdbc: DEBUG
org.mybatis.spring: DEBUG
aishop:
# 账户系统地址

View File

@ -350,9 +350,6 @@
<if test="scopeOfPower != null and scopeOfPower != ''">
scope_of_power = #{scopeOfPower},
</if>
<if test="getFile != null and getFile != ''">
get_file = #{getFile},
</if>
<if test="sourceCodeDocFile != null and sourceCodeDocFile != ''">
source_code_doc_file = #{sourceCodeDocFile},
</if>
@ -413,6 +410,7 @@
<if test="checkTime != null and checkTime != ''">
check_time = #{checkTime},
</if>
get_file = #{getFile},
app_order_id = app_order_id
WHERE
app_order_id = #{appOrderId}

View File

@ -164,10 +164,13 @@
{field: 'appOrderPayDay', width: 280, title: '处理时效', align:'center',
templet: function(row) {
var rowData = row[this.field];
if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
/* if(typeof(rowData) === 'undefined' || rowData == null || rowData == '') {
return '-';
}*/
if(rowData == 0) {
return "当天下证【截止" + row["appOrderPayEndTime"] + "】";
}
return rowData + "个工作日【需在" + row["appOrderPayEndTime"] + "前下证】";
return rowData + "个工作日【截止" + row["appOrderPayEndTime"] + "前下证】";
}
}
]

View File

@ -48,7 +48,7 @@
<img id="logoImage" src="assets/images/ruanzhu.jpg" style="height:74px;width:74px;" title="点击查看 上架软著电子版">
<input type="hidden" id="goodsPhoto" name="goodsPhoto" >
</br>
<span style="white-space: nowrap; font-size: 11px" id="basicsLogoSpan">点击查看 上架软著电子版</span>
<span style="white-space: nowrap; font-size: 11px" id="basicsLogoSpan">点击编辑 上架软著电子版</span>
<button type="button" class="layui-btn layui-btn-danger layui-btn-xs" style="top: 5px;position: absolute;right: 5px;" id="basicsLogoSpanDelete">
<i class="fa fa-lg fa-remove"></i> 删除
</button>
@ -333,14 +333,15 @@
});
$('#logoImage').on('click', function() {
top.dialog.dialogData.uploadImage = "";
localStorage.setItem('uploadImage', '');
top.dialog.open({
url: 'route/goods/image?fileId='+ $('#goodsPhoto').val(),
url: 'route/goods/image2?fileId='+ $('#goodsPhoto').val(),
title: '上传软著上架电子版',
width: '850px',
height: '500px',
width: '950px',
height: '600px',
onClose: function() {
var uploadImage = top.dialog.dialogData.uploadImage;
var uploadImage = localStorage.getItem('uploadImage');
console.log('uploadImage', uploadImage);
if(typeof(uploadImage) != 'undefined' && null != uploadImage && '' != uploadImage) {
$('#logoImage').attr('src', 'route/file/download/false/' + uploadImage);
$('#goodsPhoto').val(uploadImage);

View File

@ -0,0 +1,578 @@
<!doctype html>
<html lang="en">
<head>
<base href="/aishop/">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8"/>
<link rel="stylesheet" type="text/css" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" type="text/css" href="assets/js/vendor/bootstrap/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="assets/js/vendor/cropper/cropper.min.css"/>
<style>
.upload-image {height: 100%; opacity: 0;}
.upload-image-preview {width: 200px;height: 200px;overflow: hidden;margin: 0 20px;display: inline-block;}
#imageBox {height: 451px;overflow: auto;background-color: #F1F1F1;}
#imagePreviewBox .upload-image-preview {background-color: #F1F1F1;}
.cropper-container {
height:432px!important;
width: 529px!important;
}
.cropper-crop-box{
max-height:430px!important;
max-width:527px!important;
}
.mosaic-canvas {
position: absolute;
top: 0;
left: 0;
pointer-events: auto; /* 改为auto允许鼠标事件 */
z-index: 1000;
}
.mosaic-active {
cursor: crosshair !important;
}
</style>
</head>
<div>
<div id="content" class="edit-content" style="padding: 5px; opacity: 0;">
<div id="imageBox" class="col-xs-8" style="position: relative;">
<img id="image" class="upload-image" src="assets/images/ruanzhu.jpg">
<canvas id="mosaicCanvas" class="mosaic-canvas" style="display:none;"></canvas>
</div>
<div id="imagePreviewBox" class="col-xs-4">
<div class="upload-image-preview"></div>
</div>
<div class="col-xs-4" style="text-align: center;">
<button id="dragBtn" type="button" class="btn btn-danger fa fa-arrows" onclick="dragImage()" title="移动"></button>
<button type="button" class="btn btn-danger fa fa-search-plus" onclick="zoomPlus()" title="放大图片"></button>
<button type="button" class="btn btn-danger fa fa-search-minus" onclick="zoomMinus()" title="缩小图片"></button>
<button type="button" class="btn btn-danger fa fa-refresh" onclick="reset()" title="重置图片"></button>
<button id="mosaicBtn" type="button" class="btn btn-warning fa fa-th" onclick="toggleMosaic()" title="马赛克"></button>
<button type="button" class="btn btn-info fa fa-reply" onclick="undoEdit()" title="撤销" id="undoBtn" disabled></button>
</div>
<div class="col-xs-4" style="margin-top: 5px; text-align: center;">
<div class="btn-group">
<button class="btn btn-danger fa fa-undo" onclick="rateLeft()" type="button" title="向左旋转90°"> 向左旋转
</button>
</div>
<div class="btn-group">
<button class="btn btn-danger fa fa-repeat" onclick="rateRight()" type="button" title="向右旋转90°"> 向右旋转
</button>
</div>
</div>
<div class="col-xs-4" style="margin-top: 5px; text-align: center;">
<div class="btn-group">
<form id="uploadFileForm" action="#" style="display: none;">
<input type="file" id="uploadImage" name="image" accept="image/jpeg,image/gif,image/png,image/jpg" onchange="doUploadFile()"/>
</form>
<button class="btn btn-primary btn-block fa fa-upload" type="button" onclick="openUploadImage()"> 上传图片
</button>
</div>
<div class="btn-group">
<button class="btn btn-primary btn-block fa fa-save" type="button" onclick="doCrop()"> 裁剪上传</button>
</div>
</div>
<div class="col-xs-12" style="margin-top: 5px; text-align: center;">
<div class="form-group">
<label for="mosaicSize">马赛克大小:</label>
<input type="range" id="mosaicSize" min="5" max="30" value="10" class="form-control">
<span id="mosaicSizeValue">10px</span>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="assets/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="assets/js/vendor/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/js/vendor/cropper/cropper.min.js"></script>
<script type="text/javascript" src="assets/js/common.js"></script>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script type="text/javascript">
var toggleMosaic = function() {}
var undoEdit = function() {}
var doCrop = function() {}
var zoomPlus= function() {}
var zoomMinus= function() {}
var reset= function() {}
var rateLeft= function() {}
var rateRight= function() {}
var dragImage= function() {}
var openUploadImage= function() {}
var doUploadFile= function() {}
layui.config({
base: 'assets/layuiadmin/'
}).extend({
index: 'lib/index'
}).use(['index', 'restajax', 'datamessage', 'dialog'], function() {
var restAjax = layui.restajax;
var dialog = layui.dialog;
var dataMessage = layui.datamessage;
function doSubmitForm() {
return false;
}
var cropper;
var isMosaicMode = false;
var mosaicCanvas = document.getElementById('mosaicCanvas');
var mosaicCtx = mosaicCanvas.getContext('2d');
var isDrawing = false;
var lastX, lastY;
var editHistory = [];
var currentHistoryIndex = -1;
var maxHistorySteps = 10;
// 放大
zoomPlus = function () {
cropper.zoom(0.1);
}
// 缩小
zoomMinus = function () {
cropper.zoom(-0.1);
}
// 逆时针90
rateLeft = function () {
cropper.rotate(-90);
}
// 顺时针90
rateRight = function () {
cropper.rotate(90);
}
// 重置
reset = function () {
cropper.reset();
}
// 图片移动
var isDrag = false;
dragImage = function () {
if (!isDrag) {
cropper.setDragMode('move');
isDrag = true;
$('#dragBtn').addClass('btn-default');
$('#dragBtn').removeClass('btn-danger');
} else {
cropper.setDragMode('crop');
isDrag = false;
$('#dragBtn').addClass('btn-danger');
$('#dragBtn').removeClass('btn-default');
}
}
// 切换马赛克模式
toggleMosaic = function() {
isMosaicMode = !isMosaicMode;
if (isMosaicMode) {
// 进入马赛克模式
$('#mosaicBtn').addClass('btn-success');
$('#mosaicBtn').removeClass('btn-warning');
// 保存当前状态到历史记录
saveToHistory();
// 显示马赛克画布
setupMosaicCanvas();
$('#mosaicCanvas').show();
// 重要:将画布设置为可接收鼠标事件
mosaicCanvas.style.pointerEvents = 'auto';
// 添加鼠标事件
$(mosaicCanvas).on('mousedown', startMosaic);
$(document).on('mousemove', drawMosaic);
$(document).on('mouseup mouseleave', stopMosaic);
// 添加触摸事件
$(mosaicCanvas).on('touchstart', handleTouchStart);
$(document).on('touchmove', handleTouchMove);
$(document).on('touchend touchcancel', handleTouchEnd);
// 添加马赛克模式样式
$('#imageBox').addClass('mosaic-active');
} else {
// 退出马赛克模式
$('#mosaicBtn').addClass('btn-warning');
$('#mosaicBtn').removeClass('btn-success');
// 重要:将画布设置为不可接收鼠标事件
mosaicCanvas.style.pointerEvents = 'none';
// 移除事件监听
$(mosaicCanvas).off('mousedown');
$(document).off('mousemove', drawMosaic);
$(document).off('mouseup mouseleave', stopMosaic);
$(mosaicCanvas).off('touchstart');
$(document).off('touchmove', handleTouchMove);
$(document).off('touchend touchcancel', handleTouchEnd);
// 移除马赛克模式样式
$('#imageBox').removeClass('mosaic-active');
}
}
// 设置马赛克画布
function setupMosaicCanvas() {
var cropperCanvas = $('.cropper-canvas')[0];
var cropperImage = $('.cropper-canvas img')[0];
if (cropperCanvas && cropperImage) {
var containerRect = cropperCanvas.getBoundingClientRect();
var imageBoxRect = $('#imageBox')[0].getBoundingClientRect();
// 设置画布尺寸
mosaicCanvas.width = containerRect.width;
mosaicCanvas.height = containerRect.height;
mosaicCanvas.style.width = containerRect.width + 'px';
mosaicCanvas.style.height = containerRect.height + 'px';
// 设置画布位置 - 相对于imageBox计算偏移
mosaicCanvas.style.position = 'absolute';
mosaicCanvas.style.top = (containerRect.top - imageBoxRect.top) + 'px';
mosaicCanvas.style.left = (containerRect.left - imageBoxRect.left) + 'px';
// 清除画布
mosaicCtx.clearRect(0, 0, mosaicCanvas.width, mosaicCanvas.height);
}
}
// 开始绘制马赛克
function startMosaic(e) {
e.preventDefault(); // 阻止默认行为
isDrawing = true;
var rect = mosaicCanvas.getBoundingClientRect();
lastX = e.clientX - rect.left;
lastY = e.clientY - rect.top;
// 立即开始绘制一个点
drawMosaicEffect(lastX, lastY, lastX, lastY);
}
// 处理触摸开始事件
function handleTouchStart(e) {
e.preventDefault();
var touch = e.originalEvent.touches[0];
var rect = mosaicCanvas.getBoundingClientRect();
lastX = touch.clientX - rect.left;
lastY = touch.clientY - rect.top;
isDrawing = true;
}
// 处理触摸移动事件
function handleTouchMove(e) {
if (!isDrawing || !isMosaicMode) return;
e.preventDefault();
var touch = e.originalEvent.touches[0];
var rect = mosaicCanvas.getBoundingClientRect();
var x = touch.clientX - rect.left;
var y = touch.clientY - rect.top;
drawMosaicEffect(lastX, lastY, x, y);
lastX = x;
lastY = y;
}
// 处理触摸结束事件
function handleTouchEnd(e) {
isDrawing = false;
}
// 绘制马赛克
function drawMosaic(e) {
if (!isDrawing || !isMosaicMode) return;
var rect = mosaicCanvas.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
drawMosaicEffect(lastX, lastY, x, y);
lastX = x;
lastY = y;
}
// 绘制马赛克效果
function drawMosaicEffect(startX, startY, endX, endY) {
var cropperImage = $('.cropper-canvas img')[0];
if (!cropperImage) return;
var mosaicSize = parseInt($('#mosaicSize').val());
var dx = endX - startX;
var dy = endY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var steps = Math.max(Math.floor(distance), 1);
for (var i = 0; i <= steps; i++) {
var x = startX + (dx * i / steps);
var y = startY + (dy * i / steps);
// 计算马赛克块的左上角坐标
var mosaicX = Math.floor(x / mosaicSize) * mosaicSize;
var mosaicY = Math.floor(y / mosaicSize) * mosaicSize;
// 从原始图像获取像素数据
var cropperRect = cropperImage.getBoundingClientRect();
var cropperCanvas = document.createElement('canvas');
cropperCanvas.width = mosaicSize;
cropperCanvas.height = mosaicSize;
var cropperCtx = cropperCanvas.getContext('2d');
try {
// 获取马赛克区域的图像数据
cropperCtx.drawImage(
cropperImage,
mosaicX, mosaicY, mosaicSize, mosaicSize,
0, 0, mosaicSize, mosaicSize
);
// 计算平均颜色
var imageData = cropperCtx.getImageData(0, 0, mosaicSize, mosaicSize);
var data = imageData.data;
var r = 0, g = 0, b = 0, a = 0, count = 0;
for (var j = 0; j < data.length; j += 4) {
r += data[j];
g += data[j + 1];
b += data[j + 2];
a += data[j + 3];
count++;
}
// 计算平均值
r = Math.round(r / count);
g = Math.round(g / count);
b = Math.round(b / count);
a = Math.round(a / count);
// 绘制马赛克块
mosaicCtx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a / 255})`;
mosaicCtx.fillRect(mosaicX, mosaicY, mosaicSize, mosaicSize);
} catch (error) {
console.error('马赛克绘制错误:', error);
}
}
}
// 停止绘制马赛克
function stopMosaic() {
if (isDrawing) {
isDrawing = false;
saveToHistory();
}
}
// 保存到历史记录
function saveToHistory() {
// 如果当前不是最新状态,删除后面的历史
if (currentHistoryIndex >= 0 && currentHistoryIndex < editHistory.length - 1) {
editHistory = editHistory.slice(0, currentHistoryIndex + 1);
}
// 获取当前画布状态
var imageData = null;
if (mosaicCanvas.width > 0 && mosaicCanvas.height > 0) {
try {
imageData = mosaicCtx.getImageData(0, 0, mosaicCanvas.width, mosaicCanvas.height);
} catch (e) {
console.error('获取画布数据失败:', e);
}
}
// 添加到历史记录
if (imageData) {
editHistory.push(imageData);
// 限制历史记录数量
if (editHistory.length > maxHistorySteps) {
editHistory.shift();
}
currentHistoryIndex = editHistory.length - 1;
// 启用撤销按钮
$('#undoBtn').prop('disabled', false);
}
}
// 撤销编辑
undoEdit = function () {
if (currentHistoryIndex > 0) {
currentHistoryIndex--;
var imageData = editHistory[currentHistoryIndex];
// 恢复到之前的状态
mosaicCtx.putImageData(imageData, 0, 0);
} else if (currentHistoryIndex === 0) {
// 恢复到初始状态(清空画布)
mosaicCtx.clearRect(0, 0, mosaicCanvas.width, mosaicCanvas.height);
currentHistoryIndex = -1;
$('#undoBtn').prop('disabled', true);
}
}
// 重置马赛克画布和历史记录
function resetMosaicCanvas() {
if (mosaicCanvas) {
mosaicCtx.clearRect(0, 0, mosaicCanvas.width, mosaicCanvas.height);
}
editHistory = [];
currentHistoryIndex = -1;
$('#undoBtn').prop('disabled', true);
}
// 打开上传图片
openUploadImage = function () {
$('#uploadImage').click();
}
// 添加键盘快捷键支持
$(document).on('keydown', function(e) {
// 检测 CTRL + Z
if (e.ctrlKey && e.keyCode === 90) {
// 阻止浏览器默认的撤销行为
e.preventDefault();
// 调用撤销函数
undoEdit();
}
});
// 上传文件
doUploadFile = function () {
var loadLayerIndex;
var formData = new FormData($('#uploadFileForm')[0]);
restAjax.postFile('api/file/uploadimage', formData, {}, function (code, data) {
dialog.msg('上传成功');
cropper.replace('route/file/download/false/' + data.data, false);
localStorage.setItem('uploadImage', data.data);
// 重置马赛克画布和历史记录
resetMosaicCanvas();
}, function(code, data) {
dialog.msg(data.msg);
}, function() {
loadLayerIndex = dialog.msg(dataMessage.uploading, {icon: 16, time: 0, shade: 0.3});
}, function() {
dialog.close(loadLayerIndex);
});
}
// 裁剪
doCrop = function () {
// 获取裁剪后的画布
var croppedCanvas = cropper.getCroppedCanvas();
// 如果有马赛克效果,将马赛克合并到裁剪后的图像上
if (mosaicCanvas.width > 0 && mosaicCanvas.height > 0) {
var cropperCanvas = $('.cropper-canvas')[0];
var cropBox = $('.cropper-crop-box')[0];
if (cropperCanvas && cropBox) {
var cropBoxRect = cropBox.getBoundingClientRect();
var cropperRect = cropperCanvas.getBoundingClientRect();
// 计算裁剪框相对于画布的位置
var left = cropBoxRect.left - cropperRect.left;
var top = cropBoxRect.top - cropperRect.top;
// 获取裁剪框的尺寸
var width = cropBoxRect.width;
var height = cropBoxRect.height;
// 在裁剪后的画布上绘制马赛克
var ctx = croppedCanvas.getContext('2d');
ctx.drawImage(
mosaicCanvas,
left, top, width, height,
0, 0, croppedCanvas.width, croppedCanvas.height
);
}
}
croppedCanvas.toBlob(function (cropBlob) {
var formData = new FormData();
formData.append("image", cropBlob);
var loadLayerIndex;
restAjax.postFile('api/file/uploadimage', formData, {}, function (code, data) {
dialog.msg('裁剪成功');
// 完全重置马赛克画布和历史记录
resetMosaicCanvas();
// 替换图像
cropper.replace('route/file/download/false/' + data.data, false);
localStorage.setItem('uploadImage', data.data);
// 在图像加载完成后重新设置马赛克画布
setTimeout(function() {
setupMosaicCanvas();
}, 500);
}, function(code, data) {
dialog.msg(data.msg);
}, function() {
loadLayerIndex = dialog.msg(dataMessage.uploading, {icon: 16, time: 0, shade: 0.3});
}, function() {
dialog.close(loadLayerIndex);
});
});
}
$(function () {
var image = document.getElementById('image');
cropper = new Cropper(image, {
aspectRatio: 1.5 / 2,
viewMode: 1,
minContainerHeight: 430,
maxContainerHeight: 430,
preview: '.upload-image-preview',
crop(event) {
// 如果在马赛克模式下,实时更新马赛克画布位置
if (isMosaicMode) {
setupMosaicCanvas();
}
},
ready() {
// 初始化马赛克画布
setTimeout(function() {
setupMosaicCanvas();
}, 500);
}
});
$('#content').fadeTo(1000, 1);
var fileId = restAjax.params(window.location.href).fileId;
if (fileId != 'undefined' && fileId != undefined && fileId.length > 1) {
localStorage.setItem('uploadImage', fileId);
cropper.replace('route/file/download/false/' + fileId, false);
}
// 马赛克大小滑块事件
$('#mosaicSize').on('input', function() {
var size = $(this).val();
$('#mosaicSizeValue').text(size + 'px');
});
// 确保马赛克画布初始化
setTimeout(function() {
setupMosaicCanvas();
}, 1000); // 延迟1秒确保cropper已完全初始化
})
});
</script>
</body>
</html>

View File

@ -25,9 +25,9 @@
<div class="layui-inline">
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入关键字">
</div>
<div class="layui-inline">
<!-- <div class="layui-inline">
<input type="text" id="goodsGetTime" class="layui-input search-item" placeholder="软著取得时间" style="cursor: pointer;" readonly>
</div>
</div>-->
<!-- <div class="layui-inline layui-form search-item" >
<select id="goodsGetType" name="goodsGetType">
<option value="">请选择所有者类型</option>
@ -36,6 +36,12 @@
<option value="3">继受取得</option>
</select>
</div>-->
<div class="layui-inline layui-form search-item" >
<select id="goodsFlag" name="goodsFlag">
<option value="">请选择</option>
<option value="特价">今日特价</option>
</select>
</div>
<div class="layui-inline layui-form search-item" >
<select id="goodsCheckStatus" name="goodsCheckStatus">
<option value="">请选择审核状态</option>
@ -314,7 +320,7 @@
where: {
keywords: $('#keywords').val(),
goodsGetTime: $('#goodsGetTime').val(),
goodsGetType: $('#goodsGetType').val(),
goodsFlag: $('#goodsFlag').val(),
goodsDevelop: $('#goodsDevelop').val(),
goodsType: $('#goodsType').val(),
goodsCheckStatus: $('#goodsCheckStatus').val()

View File

@ -25,17 +25,15 @@
<div class="layui-inline">
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入关键字">
</div>
<div class="layui-inline">
<!-- <div class="layui-inline">
<input type="text" id="goodsGetTime" class="layui-input search-item" placeholder="软著取得时间" style="cursor: pointer;" readonly>
</div>
<!-- <div class="layui-inline layui-form search-item" >
<select id="goodsGetType" name="goodsGetType">
<option value="">请选择获取方式</option>
<option value="1">平台申请</option>
<option value="2">原始取得</option>
<option value="3">继受取得</option>
</select>
</div>-->
<div class="layui-inline layui-form search-item" >
<select id="goodsFlag" name="goodsFlag">
<option value="">请选择/option>
<option value="特价">今日特价</option>
</select>
</div>
<!-- <div class="layui-inline layui-form search-item" id="goodsDevelopSelectTemplateBox" lay-filter="goodsDevelopSelectTemplateBox"></div>
<script type="text/html" id="goodsDevelopSelectTemplate">
<select id="goodsDevelop" name="goodsDevelop">
@ -306,7 +304,7 @@
where: {
keywords: $('#keywords').val(),
goodsGetTime: $('#goodsGetTime').val(),
goodsGetType: $('#goodsGetType').val(),
goodsFlag: $('#goodsFlag').val(),
goodsDevelop: $('#goodsDevelop').val(),
goodsType: $('#goodsType').val()
},