diff --git a/src/main/java/com/cjy/back/ybsjAppointment/controller/YbsjyAppletsAppointmentController.java b/src/main/java/com/cjy/back/ybsjAppointment/controller/YbsjyAppletsAppointmentController.java index 6c95824..f830fe1 100644 --- a/src/main/java/com/cjy/back/ybsjAppointment/controller/YbsjyAppletsAppointmentController.java +++ b/src/main/java/com/cjy/back/ybsjAppointment/controller/YbsjyAppletsAppointmentController.java @@ -6,6 +6,10 @@ import com.cjy.back.ybsjAppointment.entity.vo.ReservationNowVO; import com.cjy.back.ybsjAppointment.service.YbsjyAppointmentRecordService; import com.cjy.back.ybsjAppointment.service.YbsjyAppointmentSettingService; import com.cjy.util.ServerResponse; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.io.FileUtils; import org.json.JSONArray; import org.json.JSONObject; import org.junit.jupiter.api.extension.MediaType; @@ -16,17 +20,18 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; import sun.net.www.http.HttpClient; -import java.io.OutputStream; +import java.io.*; import java.net.HttpURLConnection; import javax.servlet.http.HttpServletRequest; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author liangjiawei @@ -180,63 +185,176 @@ public class YbsjyAppletsAppointmentController { return ServerResponse.createBySuccess(response); } - // public static String uploadImage(String accessToken, File imageFile) throws IOException { -// String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken + "&type=image"; -// OkHttpClient client = new OkHttpClient(); -// RequestBody body = new MultipartBody.Builder() -// .setType(MultipartBody.FORM) -// .addFormDataPart("media", imageFile.getName(), -// RequestBody.create(imageFile, MediaType.parse("image/*"))) -// .build(); -// Request request = new Request.Builder().url(url).post(body).build(); -// try (Response response = client.newCall(request).execute()) { -// JSONObject result = new JSONObject(response.body().string()); -// return result.getString("media_id"); // 返回永久素材ID -// } -// } - @RequestMapping("/createDraft") - public ServerResponse createDraft(String accessToken, String title, String content, String thumbMediaId) throws IOException { - String url = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=" + accessToken; - // 构建请求体 - JSONObject article = new JSONObject(); - article.put("title", title); - article.put("content", content); - article.put("thumb_media_id", thumbMediaId); - article.put("need_open_comment", 0); - JSONArray articles = new JSONArray(); - articles.put(article); - JSONObject requestBody = new JSONObject().put("articles", articles); - // 创建连接 + // 1. 下载网络图片(支持自动重试) + private static File downloadImage(String imageUrl) throws IOException, InterruptedException { + File tempFile = File.createTempFile("wx_", ".tmp"); // 先创建临时文件 + + // 下载文件内容 + FileUtils.copyURLToFile(new URL(imageUrl), tempFile); + + // 验证文件头 + try (InputStream is = new FileInputStream(tempFile)) { + byte[] header = new byte[8]; + is.read(header); + + // PNG头: 89 50 4E 47 0D 0A 1A 0A + // JPEG头: FF D8 FF + if (!(header[0] == (byte) 0x89 && header[1] == 'P' && header[2] == 'N' && header[3] == 'G') && + !(header[0] == (byte) 0xFF && header[1] == (byte) 0xD8 && header[2] == (byte) 0xFF)) { + throw new IOException("无效的图片格式"); + } + } + + return tempFile; + } + + // 2. 微信图片上传(修复41005错误) + private static String uploadToWeChat(String accessToken, File file) throws IOException { + String newName =""; + // 1. 验证文件类型 + String fileName = file.getName().toLowerCase(); + if (!fileName.endsWith(".jpg") && !fileName.endsWith(".jpeg") && !fileName.endsWith(".png")) { + // 重命名临时文件为有效扩展名 + newName = fileName.split("\\.")[0] + ".jpg"; + File newFile = new File(file.getParent(), newName); + file.renameTo(newFile); + file = newFile; + } + FileInputStream input = new FileInputStream(file); + String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken + "&type=image"; + + String boundary = "----WebKitFormBoundary" + System.currentTimeMillis(); + String lineEnd = "\r\n"; + String twoHyphens = "--"; + + HttpURLConnection connection = null; + try { + URL requestUrl = new URL(url); + connection = (HttpURLConnection) requestUrl.openConnection(); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Connection", "Keep-Alive"); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + + OutputStream outputStream = connection.getOutputStream(); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"), true); + + // 添加文件部分 + writer.append(twoHyphens + boundary + lineEnd); + writer.append("Content-Disposition: form-data; name=\"media\"; filename=\"" + newName + "\"" + lineEnd); + writer.append("Content-Type: image/*" + lineEnd); + writer.append(lineEnd); + writer.flush(); + + // 写入文件内容(使用 MultipartFile.getInputStream()) + InputStream inputStream = input; // 关键修改点! + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + inputStream.close(); + + // 结束部分 + writer.append(lineEnd); + writer.append(twoHyphens + boundary + twoHyphens + lineEnd); + writer.close(); + + // 获取响应 + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + JSONObject result = new JSONObject(response.toString()); + return result.getString("url"); + } else { + throw new IOException("Server returned non-OK status: " + responseCode); + } + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + + // 3. 替换内容中的图片链接 + private static String processContent(String html, String accessToken) throws Exception { + Pattern pattern = Pattern.compile("]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>"); + Matcher matcher = pattern.matcher(html); + StringBuffer result = new StringBuffer(); + + while (matcher.find()) { + String imgUrl = matcher.group(1); + File tempFile = downloadImage(imgUrl); + String wechatUrl = uploadToWeChat(accessToken, tempFile); + matcher.appendReplacement(result, ""); + tempFile.delete(); + } + matcher.appendTail(result); + return result.toString(); + } + + // 4. 创建草稿 + private static void createDraft(String accessToken, String title, String content) throws IOException { + String url = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=" + accessToken; + + JSONObject article = new JSONObject() + .put("title", title) + .put("content", content) + .put("thumb_media_id", "qR_BnS7D9o1TqpJLTGV3Pmbnz48dU3zFGu6Y_9ws5iKDXNFBGdIHIyRXJVuIjK1b") + .put("show_cover_pic", 1); + JSONArray articles = new JSONArray().put(article); + String requestBody = new JSONObject().put("articles", articles).toString(); + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "application/json"); - // 发送请求 try (OutputStream os = conn.getOutputStream()) { - os.write(requestBody.toString().getBytes("UTF-8")); + os.write(requestBody.getBytes("UTF-8")); } - // 处理响应 - int responseCode = conn.getResponseCode(); - if (responseCode != HttpURLConnection.HTTP_OK) { - throw new IOException("HTTP error code: " + responseCode); - } - - try (BufferedReader br = new BufferedReader( - new InputStreamReader(conn.getInputStream(), "UTF-8"))) { - StringBuilder response = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String line; + StringBuilder response = new StringBuilder(); while ((line = br.readLine()) != null) { response.append(line); } - JSONObject result = new JSONObject(response.toString()); - return result.getString("media_id"); - } finally { - conn.disconnect(); + System.out.println("草稿创建结果: " + response); + } + } + + // 完整流程执行 + public static void main(String[] args) { + String accessToken = "91_ylo5YKGyByedvMot_MpRHPR-sECJQR5rJP0AkZUUIxQF4hlmboAj3KHbKu5NhdX-Z4YXMFerlcymRYIuzxczqvrX01iLZHEu1SLRD4Lf7tbuTNIQWN0JXlPJeVEXDRgAHAQWK"; + String originalContent = "

测试

\"zhxh.png\"/

测试

\"zhxh.png\"/

"; + + try { + // 步骤1: 处理内容中的图片 + String processedContent = processContent(originalContent, accessToken); + System.out.println("处理后的内容:\n" + processedContent); + + // 步骤2: 创建草稿 + createDraft(accessToken, "测试文章1", processedContent); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("处理失败: " + e.getMessage()); } } } + + diff --git a/src/main/java/com/cjy/back/ybsjAppointment/dao/YbsjyAppointmentRecordMapper.xml b/src/main/java/com/cjy/back/ybsjAppointment/dao/YbsjyAppointmentRecordMapper.xml index 86a31da..25deece 100644 --- a/src/main/java/com/cjy/back/ybsjAppointment/dao/YbsjyAppointmentRecordMapper.xml +++ b/src/main/java/com/cjy/back/ybsjAppointment/dao/YbsjyAppointmentRecordMapper.xml @@ -442,8 +442,9 @@ + + + INSERT INTO ybsj_tk_content (messageInfoId, content, startTime, endTime) + VALUES (#{message_info_id}, #{content}, #{start_time}, #{end_time}) + + + + + UPDATE ybsj_tk_content + SET content = #{content}, + start_time = #{startTime}, + end_time = #{endTime} + WHERE message_info_id = #{messageInfoId} + + + diff --git a/src/main/java/com/cjy/back/ybsjMessageInfo/entity/YbsjTkContent.java b/src/main/java/com/cjy/back/ybsjMessageInfo/entity/YbsjTkContent.java new file mode 100644 index 0000000..89bd076 --- /dev/null +++ b/src/main/java/com/cjy/back/ybsjMessageInfo/entity/YbsjTkContent.java @@ -0,0 +1,51 @@ +package com.cjy.back.ybsjMessageInfo.entity; + +import java.util.Date; + +public class YbsjTkContent { + private Integer id; + private Integer messageInfoId; + private String content; + private String startTime; + private String endTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getMessageInfoId() { + return messageInfoId; + } + + public void setMessageInfoId(Integer messageInfoId) { + this.messageInfoId = messageInfoId; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } +} diff --git a/src/main/java/com/cjy/back/ybsjMessageInfo/service/YbsjMessageInfoService.java b/src/main/java/com/cjy/back/ybsjMessageInfo/service/YbsjMessageInfoService.java index 3f743a1..5b954d0 100644 --- a/src/main/java/com/cjy/back/ybsjMessageInfo/service/YbsjMessageInfoService.java +++ b/src/main/java/com/cjy/back/ybsjMessageInfo/service/YbsjMessageInfoService.java @@ -1,6 +1,7 @@ package com.cjy.back.ybsjMessageInfo.service; import com.cjy.back.ybsjMessageInfo.entity.YbsjMessageInfo; +import com.cjy.back.ybsjMessageInfo.entity.YbsjTkContent; import com.cjy.util.ServerResponse; import javax.servlet.http.HttpServletRequest; @@ -49,6 +50,10 @@ public interface YbsjMessageInfoService { * @date 2019/10/31 */ ServerResponse updateIspopupMessageInfo(HttpServletRequest request, HttpSession session); + + // 根据 message_info_id 查询记录 + YbsjTkContent selectContentById(Long message_info_id); + /** * * @Description: 修改假删除 diff --git a/src/main/java/com/cjy/back/ybsjMessageInfo/service/impl/YbsjMessageInfoServiceImpl.java b/src/main/java/com/cjy/back/ybsjMessageInfo/service/impl/YbsjMessageInfoServiceImpl.java index 1605f9e..6b3495a 100644 --- a/src/main/java/com/cjy/back/ybsjMessageInfo/service/impl/YbsjMessageInfoServiceImpl.java +++ b/src/main/java/com/cjy/back/ybsjMessageInfo/service/impl/YbsjMessageInfoServiceImpl.java @@ -8,6 +8,7 @@ import com.cjy.back.ybsjAllData.dao.YbsjAllDataMapper; import com.cjy.back.ybsjFoodSpecialgoodShop.dao.YbsjFoodSpecialgoodShopMapper; import com.cjy.back.ybsjMessageInfo.dao.YbsjMessageInfoMapper; import com.cjy.back.ybsjMessageInfo.entity.YbsjMessageInfo; +import com.cjy.back.ybsjMessageInfo.entity.YbsjTkContent; import com.cjy.back.ybsjMessageInfo.service.YbsjMessageInfoService; import com.cjy.back.ybsjMessageType.dao.YbsjMessageTypeMapper; import com.cjy.back.ybsjZdLine.dao.YbsjZdLineMapper; @@ -250,12 +251,31 @@ public class YbsjMessageInfoServiceImpl implements YbsjMessageInfoService { if (i <= 0) { return ServerResponse.createByErrorMessage("修改失败"); } + if (is){ + String tkId = request.getParameter("tkId"); + YbsjTkContent ybsjTkContent =new YbsjTkContent(); + ybsjTkContent.setMessageInfoId(Integer.valueOf(guid)); + ybsjTkContent.setStartTime(request.getParameter("startTime")); + ybsjTkContent.setEndTime(request.getParameter("endTime")); + ybsjTkContent.setContent(request.getParameter("popupContent")); + if (tkId != null && !tkId.equals("")) { + messageInfoMapper.updateContent(ybsjTkContent); + }else { + messageInfoMapper.insertContent(ybsjTkContent); + } + } //TODO 重新初始化相关message_info表的redis数据 CorrelationData correlationData = new CorrelationData(admin.getUserkey() + "_message_info_init_" + System.currentTimeMillis()); rabbitTemplate.convertAndSend(RabbitMQConfig.REDIS_EXCHANGE, RabbitMQConfig.MESSAGE_ROUT_KEY, admin.getUserkey(), correlationData); //initDataRedis.run(admin.getUserkey()); return ServerResponse.createBySuccessMessage(msg); } + + @Override + public YbsjTkContent selectContentById(Long message_info_id) { + return messageInfoMapper.selectContentById(message_info_id); + } + /** * @param request guid/is 主键和修改后的排序参数 * @return diff --git a/src/main/webapp/html/back/ybsjZdLine/list_ybsjZdLineList.js b/src/main/webapp/html/back/ybsjZdLine/list_ybsjZdLineList.js index 7b6263e..0553e59 100644 --- a/src/main/webapp/html/back/ybsjZdLine/list_ybsjZdLineList.js +++ b/src/main/webapp/html/back/ybsjZdLine/list_ybsjZdLineList.js @@ -386,32 +386,161 @@ layui.form.on('switch(isrecommend)', function(data) { } }); }); -//是否弹框 layui.form.on('switch(ispopup)', function(data) { - var checkbox = data.elem; // 获取当前操作的 checkbox 元素 - var originalState = checkbox.checked; // 记录原始状态(用于回滚) - $.ajax({ - url : ctx + '/messageInfo/updateIspopupMessageInfo.do', - type : 'post', - datatype : 'json', - data : { - guid : data.elem.value, - ispopup : data.elem.checked - }, - xhrFields: { - withCredentials: true // 这里设置了withCredentials - }, - success : function(res) { - if(res.success){ - layerMessage(res.msg); - }else{ - checkbox.checked = !originalState; // 回滚到之前的状态 + var checkbox = data.elem; + var originalState = checkbox.checked; + var guid = data.elem.value; + + if (data.elem.checked) { + // 先查询是否已有弹窗设置 + $.ajax({ + url: ctx + '/messageInfo/selectContentById.do?messageInfoId='+guid, + type: 'post', + dataType: 'json', + xhrFields: { withCredentials: true }, + success: function(res) { + if(res.success) { + var popupData = res.data || {}; + + // 弹出设置窗口并回显数据 + showPopupSetting(checkbox, guid, popupData); + } else { + checkbox.checked = false; + layui.form.render('checkbox'); + error(res); + } + }, + error: function() { + checkbox.checked = false; layui.form.render('checkbox'); - error(res); + layer.msg('查询弹窗设置失败'); } + }); + } else { + // 关闭弹窗时的处理 + $.ajax({ + url: ctx + '/messageInfo/updateIspopupMessageInfo.do', + type: 'post', + datatype: 'json', + data: { guid: guid, ispopup: false }, + xhrFields: { withCredentials: true }, + success: function(res) { + if(!res.success) { + checkbox.checked = originalState; + layui.form.render('checkbox'); + error(res); + } else { + layerMessage(res.msg); + } + } + }); + } +}); + +// 显示弹窗设置窗口 +function showPopupSetting(checkbox, guid, popupData) { + layer.open({ + type: 1, + title: '弹窗设置', + area: ['600px', '300px'], + content: ` +
+
+ +
+ +
+
+
+ +
+
+ +
+
-
+
+ +
+
+
+
+
+ + +
+
+
+ `, + success: function(layero, index) { + // 初始化日期选择器 + layui.laydate.render({ + elem: '#startTime', + type: 'date', // 只选择日期 + format: 'yyyy-MM-dd', // 格式化为年月日 + value: popupData.startTime || '' + }); + layui.laydate.render({ + elem: '#endTime', + type: 'date', // 只选择日期 + format: 'yyyy-MM-dd', // 格式化为年月日 + value: popupData.endTime || '' + }); + + // 保存按钮事件 + $('#savePopup').on('click', function() { + var popupContent = $('#popupContent').val(); + var startTime = $('#startTime').val(); + var endTime = $('#endTime').val(); + + if (!popupContent) { + layer.msg('请填写弹窗内容'); + return; + } + if (!startTime || !endTime) { + layer.msg('请选择弹窗期限'); + return; + } + + $.ajax({ + url: ctx + '/messageInfo/updateIspopupMessageInfo.do', + type: 'post', + datatype: 'json', + data: { + guid: guid, + ispopup: true, + popupContent: popupContent, + startTime: startTime, + endTime: endTime, + tkId:popupData.id + }, + xhrFields: { withCredentials: true }, + success: function(res) { + if(res.success) { + layer.close(index); + layerMessage(res.msg); + } else { + checkbox.checked = false; + layui.form.render('checkbox'); + error(res); + } + } + }); + }); + + // 取消按钮事件 + $('#cancelPopup').on('click', function() { + checkbox.checked = false; + layui.form.render('checkbox'); + layer.close(index); + }); + }, + cancel: function() { + // 关闭弹窗时恢复原始状态 + checkbox.checked = false; + layui.form.render('checkbox'); } }); -}); +} //是否假删除 layui.form.on('switch(isdel)', function(data) { $.ajax({ diff --git a/src/main/webapp/html/back/yuyue/reservationManagementAdd.js b/src/main/webapp/html/back/yuyue/reservationManagementAdd.js index f1b06fa..0be6485 100644 --- a/src/main/webapp/html/back/yuyue/reservationManagementAdd.js +++ b/src/main/webapp/html/back/yuyue/reservationManagementAdd.js @@ -41,20 +41,10 @@ $(function() { $("#isSubscribe").val(json.isSubscribe); Promise.all([ - getAppointmentTypes(), - getVisitLocations() + loadAppointmentTypes(json.bookingCategory), + loadVisitLocations(json.visitTypes) ]).then(function() { - // 设置选中状态 - if(json.bookingCategory) { - $('input[name="bookingCategory"][value="'+json.bookingCategory+'"]').prop('checked', true); - } - if(json.visitTypes) { - var locations = json.visitTypes.split(','); - locations.forEach(function(loc) { - $('input[name="visitTypes"][value="'+loc+'"]').prop('checked', true); - }); - } // 重新渲染表单 layui.form.render(); }) @@ -259,6 +249,71 @@ $(function() { }) } }) + +// 修改后的加载预约类型函数 +function loadAppointmentTypes(selectedValue) { + return new Promise(function(resolve, reject) { + $.ajax({ + url: ctx + "/appointmentSetting/selectDicByPid?dicpcode=57", + type: "GET", + dataType: "json", + success: function(res) { + if(res.success && res.data) { + var container = $('#appointmentTypeContainer'); + container.empty(); + + res.data.forEach(function(item) { + var checked = (selectedValue && selectedValue === item.dicnum) ? 'checked' : ''; + container.append( + '' + ); + }); + + resolve(); + } else { + reject('获取预约类型失败'); + } + }, + error: function() { + reject('获取预约类型失败'); + } + }); + }); +} + +// 修改后的加载参观地点函数 +function loadVisitLocations(selectedValues) { + return new Promise(function(resolve, reject) { + $.ajax({ + url: ctx + "/appointmentSetting/selectDicByPid?dicpcode=58", + type: "GET", + dataType: "json", + success: function(res) { + if(res.success && res.data) { + var container = $('#visitLocationsContainer'); + container.empty(); + + // 将选中的值转为数组 + var selectedArray = selectedValues ? selectedValues.split(',') : []; + + res.data.forEach(function(item) { + var checked = selectedArray.includes(item.dicnum) ? 'checked' : ''; + container.append( + '' + ); + }); + + resolve(); + } else { + reject('获取参观地点失败'); + } + }, + error: function() { + reject('获取参观地点失败'); + } + }); + }); +} function jingqu(){ $.ajax({ type: "post", diff --git a/src/main/webapp/html/back/yuyueList/reservationRecord.html b/src/main/webapp/html/back/yuyueList/reservationRecord.html index c1368cb..eec1108 100644 --- a/src/main/webapp/html/back/yuyueList/reservationRecord.html +++ b/src/main/webapp/html/back/yuyueList/reservationRecord.html @@ -55,6 +55,16 @@ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+