From e051878f73bb254c298438b657f361998abcc971 Mon Sep 17 00:00:00 2001 From: lzx_win <2602107437@qq.com> Date: Tue, 30 Sep 2025 16:40:41 +0800 Subject: [PATCH] Changes --- .gitignore | 3 +- admin-hanhai-vue/.gitignore | 21 -- .../controller/AppletArticleController.java | 171 +++++++++++++ .../appletArticle/entity/AppletArticle.java | 65 +++++ .../appletArticle/mapper/AppletArticleMapper.java | 17 ++ .../mapper/xml/AppletArticleMapper.xml | 5 + .../service/IAppletArticleService.java | 14 ++ .../service/impl/AppletArticleServiceImpl.java | 19 ++ .../appletArticle/vue/AppletArticleList.vue | 183 ++++++++++++++ .../vue/modules/AppletArticleForm.vue | 114 +++++++++ .../modules/AppletArticleModal.Style#Drawer.vue | 84 +++++++ .../vue/modules/AppletArticleModal.vue | 60 +++++ .../appletArticle/vue3/AppletArticle.api.ts | 61 +++++ .../appletArticle/vue3/AppletArticle.data.ts | 43 ++++ .../appletArticle/vue3/AppletArticleList.vue | 162 +++++++++++++ .../vue3/components/AppletArticleModal.vue | 58 +++++ .../modules/cityComment/entity/CityComment.java | 12 + .../org/jeecg/modules/api/bean/YaoDuOrderBean.java | 5 + .../jeecg/modules/api/service/YaoDuApiService.java | 3 +- .../modules/api/service/YaoDuOrderService.java | 1 + .../modules/api/service/YaoDuShopService.java | 9 + .../api/service/impl/YaoDuApiServiceImpl.java | 101 +++++--- .../api/service/impl/YaoDuOrderServiceImpl.java | 1 + .../api/service/impl/YaoDuShopServiceImpl.java | 222 +++++++++++++++++ .../jeecg/modules/api/utils/WxHttpClientUtil.java | 264 +++++++++++++++++++++ .../org/jeecg/modules/api/utils/WxHttpUtils.java | 179 ++++++++++++++ .../modules/api/yaoduapi/YaoDuApiController.java | 4 +- .../api/yaoduapi/YaoDuApiTokenController.java | 7 + .../api/yaoduapi/YaoDuArticleController.java | 35 +++ .../modules/api/yaoduapi/YaoDuOrderController.java | 2 + .../modules/api/yaoduapi/YaoDuShopController.java | 31 +++ 31 files changed, 1892 insertions(+), 64 deletions(-) delete mode 100644 admin-hanhai-vue/.gitignore create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/controller/AppletArticleController.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/entity/AppletArticle.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/AppletArticleMapper.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/xml/AppletArticleMapper.xml create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/IAppletArticleService.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/impl/AppletArticleServiceImpl.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/AppletArticleList.vue create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleForm.vue create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.Style#Drawer.vue create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.vue create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.api.ts create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.data.ts create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticleList.vue create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/components/AppletArticleModal.vue create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuShopService.java create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuShopServiceImpl.java create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpClientUtil.java create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpUtils.java create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuArticleController.java create mode 100644 jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuShopController.java diff --git a/.gitignore b/.gitignore index 9e8ec2a..2ca6429 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ yarn-error.log* *.njsproj *.sln *.sw* -target \ No newline at end of file +target +dist diff --git a/admin-hanhai-vue/.gitignore b/admin-hanhai-vue/.gitignore deleted file mode 100644 index 185e663..0000000 --- a/admin-hanhai-vue/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -.DS_Store -node_modules -/dist - -# local env files -.env.local -.env.*.local - -# Log files -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw* diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/controller/AppletArticleController.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/controller/AppletArticleController.java new file mode 100644 index 0000000..c2d8938 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/controller/AppletArticleController.java @@ -0,0 +1,171 @@ +package org.jeecg.modules.appletArticle.controller; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.appletArticle.entity.AppletArticle; +import org.jeecg.modules.appletArticle.service.IAppletArticleService; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; + +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; +import org.jeecg.common.system.base.controller.JeecgController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.servlet.ModelAndView; +import com.alibaba.fastjson.JSON; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.jeecg.common.aspect.annotation.AutoLog; + + /** + * @Description: 文章 + * @Author: jeecg-boot + * @Date: 2025-09-29 + * @Version: V1.0 + */ +@Api(tags="文章") +@RestController +@RequestMapping("/appletArticle/appletArticle") +@Slf4j +public class AppletArticleController extends JeecgController { + @Autowired + private IAppletArticleService appletArticleService; + + /** + * 分页列表查询 + * + * @param appletArticle + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "文章-分页列表查询") + @ApiOperation(value="文章-分页列表查询", notes="文章-分页列表查询") + @GetMapping(value = "/list") + public Result> queryPageList(AppletArticle appletArticle, + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(appletArticle, req.getParameterMap()); + Page page = new Page(pageNo, pageSize); + IPage pageList = appletArticleService.page(page, queryWrapper); + return Result.OK(pageList); + } + + /** + * 添加 + * + * @param appletArticle + * @return + */ + @AutoLog(value = "文章-添加") + @ApiOperation(value="文章-添加", notes="文章-添加") + @PostMapping(value = "/add") + public Result add(@RequestBody AppletArticle appletArticle) { + appletArticleService.save(appletArticle); + return Result.OK("添加成功!"); + } + + /** + * 编辑 + * + * @param appletArticle + * @return + */ + @AutoLog(value = "文章-编辑") + @ApiOperation(value="文章-编辑", notes="文章-编辑") + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) + public Result edit(@RequestBody AppletArticle appletArticle) { + appletArticleService.updateById(appletArticle); + return Result.OK("编辑成功!"); + } + + /** + * 通过id删除 + * + * @param id + * @return + */ + @AutoLog(value = "文章-通过id删除") + @ApiOperation(value="文章-通过id删除", notes="文章-通过id删除") + @DeleteMapping(value = "/delete") + public Result delete(@RequestParam(name="id",required=true) String id) { + appletArticleService.removeById(id); + return Result.OK("删除成功!"); + } + + /** + * 批量删除 + * + * @param ids + * @return + */ + @AutoLog(value = "文章-批量删除") + @ApiOperation(value="文章-批量删除", notes="文章-批量删除") + @DeleteMapping(value = "/deleteBatch") + public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { + this.appletArticleService.removeByIds(Arrays.asList(ids.split(","))); + return Result.OK("批量删除成功!"); + } + + /** + * 通过id查询 + * + * @param id + * @return + */ + //@AutoLog(value = "文章-通过id查询") + @ApiOperation(value="文章-通过id查询", notes="文章-通过id查询") + @GetMapping(value = "/queryById") + public Result queryById(@RequestParam(name="id",required=true) String id) { + AppletArticle appletArticle = appletArticleService.getById(id); + if(appletArticle==null) { + return Result.error("未找到对应数据"); + } + return Result.OK(appletArticle); + } + + /** + * 导出excel + * + * @param request + * @param appletArticle + */ + @RequestMapping(value = "/exportXls") + public ModelAndView exportXls(HttpServletRequest request, AppletArticle appletArticle) { + return super.exportXls(request, appletArticle, AppletArticle.class, "文章"); + } + + /** + * 通过excel导入数据 + * + * @param request + * @param response + * @return + */ + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) + public Result importExcel(HttpServletRequest request, HttpServletResponse response) { + return super.importExcel(request, response, AppletArticle.class); + } + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/entity/AppletArticle.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/entity/AppletArticle.java new file mode 100644 index 0000000..b25044d --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/entity/AppletArticle.java @@ -0,0 +1,65 @@ +package org.jeecg.modules.appletArticle.entity; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.math.BigDecimal; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.springframework.format.annotation.DateTimeFormat; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecg.common.aspect.annotation.Dict; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * @Description: 文章 + * @Author: jeecg-boot + * @Date: 2025-09-29 + * @Version: V1.0 + */ +@Data +@TableName("applet_article") +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@ApiModel(value="applet_article对象", description="文章") +public class AppletArticle implements Serializable { + private static final long serialVersionUID = 1L; + + /**主键*/ + @TableId(type = IdType.ASSIGN_ID) + @ApiModelProperty(value = "主键") + private java.lang.String id; + /**创建人*/ + @ApiModelProperty(value = "创建人") + private java.lang.String createBy; + /**创建日期*/ + @ApiModelProperty(value = "创建日期") + private java.util.Date createTime; + /**更新人*/ + @ApiModelProperty(value = "更新人") + private java.lang.String updateBy; + /**更新日期*/ + @ApiModelProperty(value = "更新日期") + private java.util.Date updateTime; + /**所属部门*/ + @ApiModelProperty(value = "所属部门") + private java.lang.String sysOrgCode; + /**标题*/ + @Excel(name = "标题", width = 15) + @ApiModelProperty(value = "标题") + private java.lang.String title; + /**内容*/ + @Excel(name = "内容", width = 15) + @ApiModelProperty(value = "内容") + private java.lang.String content; + /**封面*/ + @Excel(name = "封面", width = 15) + @ApiModelProperty(value = "封面") + private java.lang.String image; +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/AppletArticleMapper.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/AppletArticleMapper.java new file mode 100644 index 0000000..00a652d --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/AppletArticleMapper.java @@ -0,0 +1,17 @@ +package org.jeecg.modules.appletArticle.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; +import org.jeecg.modules.appletArticle.entity.AppletArticle; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @Description: 文章 + * @Author: jeecg-boot + * @Date: 2025-09-29 + * @Version: V1.0 + */ +public interface AppletArticleMapper extends BaseMapper { + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/xml/AppletArticleMapper.xml b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/xml/AppletArticleMapper.xml new file mode 100644 index 0000000..69d926a --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/mapper/xml/AppletArticleMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/IAppletArticleService.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/IAppletArticleService.java new file mode 100644 index 0000000..903a0a1 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/IAppletArticleService.java @@ -0,0 +1,14 @@ +package org.jeecg.modules.appletArticle.service; + +import org.jeecg.modules.appletArticle.entity.AppletArticle; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * @Description: 文章 + * @Author: jeecg-boot + * @Date: 2025-09-29 + * @Version: V1.0 + */ +public interface IAppletArticleService extends IService { + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/impl/AppletArticleServiceImpl.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/impl/AppletArticleServiceImpl.java new file mode 100644 index 0000000..db827fd --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/service/impl/AppletArticleServiceImpl.java @@ -0,0 +1,19 @@ +package org.jeecg.modules.appletArticle.service.impl; + +import org.jeecg.modules.appletArticle.entity.AppletArticle; +import org.jeecg.modules.appletArticle.mapper.AppletArticleMapper; +import org.jeecg.modules.appletArticle.service.IAppletArticleService; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +/** + * @Description: 文章 + * @Author: jeecg-boot + * @Date: 2025-09-29 + * @Version: V1.0 + */ +@Service +public class AppletArticleServiceImpl extends ServiceImpl implements IAppletArticleService { + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/AppletArticleList.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/AppletArticleList.vue new file mode 100644 index 0000000..f35b8ff --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/AppletArticleList.vue @@ -0,0 +1,183 @@ + + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleForm.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleForm.vue new file mode 100644 index 0000000..1c52957 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleForm.vue @@ -0,0 +1,114 @@ + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.Style#Drawer.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.Style#Drawer.vue new file mode 100644 index 0000000..d7087a6 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.Style#Drawer.vue @@ -0,0 +1,84 @@ + + + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.vue new file mode 100644 index 0000000..044362f --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue/modules/AppletArticleModal.vue @@ -0,0 +1,60 @@ + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.api.ts b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.api.ts new file mode 100644 index 0000000..66039ae --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.api.ts @@ -0,0 +1,61 @@ +import {defHttp} from '/@/utils/http/axios'; +import {Modal} from 'ant-design-vue'; + +enum Api { + list = '/appletArticle/appletArticle/list', + save='/appletArticle/appletArticle/add', + edit='/appletArticle/appletArticle/edit', + deleteOne = '/appletArticle/appletArticle/delete', + deleteBatch = '/appletArticle/appletArticle/deleteBatch', + importExcel = '/appletArticle/appletArticle/importExcel', + exportXls = '/appletArticle/appletArticle/exportXls', +} +/** + * 导出api + * @param params + */ +export const getExportUrl = Api.exportXls; +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; +/** + * 列表接口 + * @param params + */ +export const list = (params) => + defHttp.get({url: Api.list, params}); + +/** + * 删除单个 + */ +export const deleteOne = (params,handleSuccess) => { + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { + handleSuccess(); + }); +} +/** + * 批量删除 + * @param params + */ +export const batchDelete = (params, handleSuccess) => { + Modal.confirm({ + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { + handleSuccess(); + }); + } + }); +} +/** + * 保存或者更新 + * @param params + */ +export const saveOrUpdate = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({url: url, params}); +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.data.ts b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.data.ts new file mode 100644 index 0000000..4a9696f --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticle.data.ts @@ -0,0 +1,43 @@ +import {BasicColumn} from '/@/components/Table'; +import {FormSchema} from '/@/components/Table'; +import { rules} from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; +//列表数据 +export const columns: BasicColumn[] = [ + { + title: '标题', + align:"center", + dataIndex: 'title' + }, + { + title: '内容', + align:"center", + dataIndex: 'content' + }, + { + title: '封面', + align:"center", + dataIndex: 'image' + }, +]; +//查询数据 +export const searchFormSchema: FormSchema[] = [ +]; +//表单数据 +export const formSchema: FormSchema[] = [ + { + label: '标题', + field: 'title', + component: 'Input', + }, + { + label: '内容', + field: 'content', + component: 'Input', + }, + { + label: '封面', + field: 'image', + component: 'Input', + }, +]; diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticleList.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticleList.vue new file mode 100644 index 0000000..14defb4 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/AppletArticleList.vue @@ -0,0 +1,162 @@ + + + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/components/AppletArticleModal.vue b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/components/AppletArticleModal.vue new file mode 100644 index 0000000..7e4bdb9 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/appletArticle/vue3/components/AppletArticleModal.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityComment/entity/CityComment.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityComment/entity/CityComment.java index b5f622b..748db16 100644 --- a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityComment/entity/CityComment.java +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityComment/entity/CityComment.java @@ -4,7 +4,10 @@ import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.Date; import java.math.BigDecimal; +import java.util.List; + import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -79,4 +82,13 @@ public class CityComment implements Serializable { @Excel(name = "用户标识", width = 15) @ApiModelProperty(value = "用户标识") private java.lang.String userId; + + /**父级*/ + private java.lang.String pid; + + @TableField(exist = false) + private Long replyNum;//回复数量 + + @TableField(exist = false) + private List children; } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/bean/YaoDuOrderBean.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/bean/YaoDuOrderBean.java index d127602..ca23fd8 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/bean/YaoDuOrderBean.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/bean/YaoDuOrderBean.java @@ -1,5 +1,6 @@ package org.jeecg.modules.api.bean; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -20,4 +21,8 @@ public class YaoDuOrderBean { this.pageNo = 1; this.pageSize = 1000; } + + public Page getPage() { + return Page.of(this.pageNo, this.pageSize); + } } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuApiService.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuApiService.java index 2f06b30..8a03f2e 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuApiService.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuApiService.java @@ -84,7 +84,7 @@ public interface YaoDuApiService { //获取评论信息列表 - Result getCommentPage(String orderId,String type,PageBean pageBean); + Result getCommentPage(String pid, String orderId,String type,PageBean pageBean); //获取发布按钮列表 Result getPublishButtonList(); @@ -257,4 +257,5 @@ public interface YaoDuApiService { //新-大转抽奖 Result luckDraw(String token); + Result commentDetail(String id); } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuOrderService.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuOrderService.java index 547dc96..d0939fd 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuOrderService.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuOrderService.java @@ -41,4 +41,5 @@ public interface YaoDuOrderService { Result saveOrUpdate(String token, CityShopping cityShopping); Result update(String token,String id,String isOpen); + } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuShopService.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuShopService.java new file mode 100644 index 0000000..cffef7b --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/YaoDuShopService.java @@ -0,0 +1,9 @@ +package org.jeecg.modules.api.service; + +import org.jeecg.common.api.vo.Result; + +public interface YaoDuShopService { + + byte[] shopQrCode(String token, String id) throws Exception; + +} diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java index 3e28938..2618886 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuApiServiceImpl.java @@ -571,13 +571,20 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { //获取评论信息列表 @Override - public Result getCommentPage(String orderId,String type,PageBean pageBean){ + public Result getCommentPage(String pid, String orderId,String type,PageBean pageBean){ Page page = new Page(pageBean.getPageNo(), pageBean.getPageSize()); Page page1 = cityCommentService .lambdaQuery() .eq(CityComment::getOrderId,orderId) + .isNull(StringUtils.isBlank(pid), CityComment::getPid) + .eq(StringUtils.isNotEmpty(pid), CityComment::getId, pid) .orderByDesc(CityComment::getCreateTime) .page(page); + + page1.getRecords().forEach(cityComment -> { + cityComment.setReplyNum(cityCommentService.lambdaQuery().eq(CityComment::getPid,cityComment.getId()).count()); + }); + return Result.OK(page1); } @@ -636,25 +643,23 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { }else if(list.size() >= 2){ //查看积分是否充足 - if(hanHaiMember.getIntegerPrice().compareTo(new BigDecimal(2))==-1){ - return Result.error("积分不足"); - } - - //增加积分流水 - CityIntgerWater cityMoneyLog = new CityIntgerWater(); - cityMoneyLog.setCreateTime(new Date()); - cityMoneyLog.setType(0); - cityMoneyLog.setIntger(new BigDecimal(2)); - cityMoneyLog.setUserId(hanHaiMember.getId()); - cityMoneyLog.setTitle("查看联系方式"); - cityIntgerWaterService.save(cityMoneyLog); - - - //减少用户积分 - hanHaiMember.setIntegerPrice(hanHaiMember.getIntegerPrice().subtract(new BigDecimal(2))); - hanHaiMemberService.updateById(hanHaiMember); - - +// if(hanHaiMember.getIntegerPrice().compareTo(new BigDecimal(2))==-1){ +// return Result.error("积分不足"); +// } +// +// //增加积分流水 +// CityIntgerWater cityMoneyLog = new CityIntgerWater(); +// cityMoneyLog.setCreateTime(new Date()); +// cityMoneyLog.setType(0); +// cityMoneyLog.setIntger(new BigDecimal(2)); +// cityMoneyLog.setUserId(hanHaiMember.getId()); +// cityMoneyLog.setTitle("查看联系方式"); +// cityIntgerWaterService.save(cityMoneyLog); +// +// +// //减少用户积分 +// hanHaiMember.setIntegerPrice(hanHaiMember.getIntegerPrice().subtract(new BigDecimal(2))); +// hanHaiMemberService.updateById(hanHaiMember); } } @@ -1088,7 +1093,6 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token); - //验证 Integer i = this.sendMsgSecCheck(hanHaiMember.getAppletOpenid(), cityComment.getUserValue()); if(i>100){ @@ -1807,10 +1811,10 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { } // 2. 检查用户积分 - BigDecimal integral = hanHaiMember.getIntegerPrice(); - if (integral == null || integral.compareTo(new BigDecimal(1)) < 0) { - return Result.error("积分不足,需要1积分才能抽奖"); - } +// BigDecimal integral = hanHaiMember.getIntegerPrice(); +// if (integral == null || integral.compareTo(new BigDecimal(1)) < 0) { +// return Result.error("积分不足,需要1积分才能抽奖"); +// } try { // 3. 获取所有有效礼品(可以添加状态过滤) @@ -1846,24 +1850,24 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { // 8. 扣除用户积分 //增加流水记录 - CityIntgerWater intgerWater = new CityIntgerWater(); - intgerWater.setCreateTime(new Date()); - intgerWater.setIntger(new BigDecimal(5)); - intgerWater.setType(0); - intgerWater.setUserId(hanHaiMember.getId()); - intgerWater.setTitle("大转盘抽奖消耗积分"); - cityIntgerWaterService.save(intgerWater); +// CityIntgerWater intgerWater = new CityIntgerWater(); +// intgerWater.setCreateTime(new Date()); +// intgerWater.setIntger(new BigDecimal(5)); +// intgerWater.setType(0); +// intgerWater.setUserId(hanHaiMember.getId()); +// intgerWater.setTitle("大转盘抽奖消耗积分"); +// cityIntgerWaterService.save(intgerWater); - hanHaiMember.setIntegerPrice(integral.subtract(new BigDecimal(5))); - boolean updateSuccess = hanHaiMemberService.updateById(hanHaiMember); - if (!updateSuccess) { - throw new RuntimeException("积分扣除失败"); - } +// hanHaiMember.setIntegerPrice(integral.subtract(new BigDecimal(5))); +// boolean updateSuccess = hanHaiMemberService.updateById(hanHaiMember); +// if (!updateSuccess) { +// throw new RuntimeException("积分扣除失败"); +// } // 9. 记录中奖信息(如果需要) if (winningGift.getType() == 0) { @@ -1881,7 +1885,6 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { BigDecimal price = hanHaiMember.getPrice().add(winningGift.getPrice()); hanHaiMember.setPrice(price); hanHaiMemberService.updateById(hanHaiMember); - } // 如果是实物奖品,可能需要处理发货逻辑 @@ -1892,7 +1895,8 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { // 10. 返回结果 Map result = new HashMap<>(); result.put("gift", winningGift); - result.put("remainingIntegral", integral.subtract(new BigDecimal(1))); + result.put("remainingIntegral", 1); +// result.put("remainingIntegral", integral.subtract(new BigDecimal(1))); return Result.OK(result); @@ -1904,4 +1908,23 @@ public class YaoDuApiServiceImpl implements YaoDuApiService { } } + @Override + public Result commentDetail(String id) { + CityComment cityComment = cityCommentService.getById(id); + + if(cityComment==null){ + return Result.error("未找到对应数据"); + } + + cityComment.setReplyNum(cityCommentService.lambdaQuery() + .eq(CityComment::getPid, id) + .count()); + + cityComment.setChildren(cityCommentService.lambdaQuery() + .eq(CityComment::getPid, id) + .list()); + + return Result.OK(cityComment); + } + } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuOrderServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuOrderServiceImpl.java index 0287af8..36841dd 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuOrderServiceImpl.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuOrderServiceImpl.java @@ -633,4 +633,5 @@ public class YaoDuOrderServiceImpl implements YaoDuOrderService { cityShoppingService.updateById(byId); return Result.OK("操作成功"); } + } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuShopServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuShopServiceImpl.java new file mode 100644 index 0000000..2848017 --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/YaoDuShopServiceImpl.java @@ -0,0 +1,222 @@ +package org.jeecg.modules.api.service.impl; + +import com.alibaba.fastjson.JSON; +import lombok.extern.log4j.Log4j2; +import org.jeecg.common.util.oss.OssBootUtil; +import org.jeecg.config.shiro.ShiroRealm; +import org.jeecg.modules.api.service.YaoDuShopService; +import org.jeecg.modules.api.utils.WxHttpUtils; +import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.net.URL; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; + +@Log4j2 +@Service +public class YaoDuShopServiceImpl implements YaoDuShopService { + + //权限配置 + @Resource + private ShiroRealm shiroRealm; + + @Autowired + private WxHttpUtils wxHttpUtils; + + + @Override + public byte[] shopQrCode(String token, String id) throws Exception { +// HanHaiMember member = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token); + return generateWxQrCode("1", "pages_order/gourmet/gourmetDetail?id=" + id, "release"); + } + +// public byte[] getInviteCode(HanHaiMember user){ +// +// // 获取环境配置 +// String trial = "release"; +// +// // 获取必要的配置信息 +// String xcxSharePage = appletConfigService.getContentByCode("xcxSharePage"); +// String backgroundImageUrl = appletConfigService.getContentByCode("qr_code_bg"); +// +// // 获取二维码位置配置参数 +// int qrCodeX = appletConfigService.getContentByCodeAsInt("qr_code_x"); +// int qrCodeY = appletConfigService.getContentByCodeAsInt("qr_code_y"); +// +// // 优化缓存策略:使用更精确的缓存key,包含所有影响因素(包括背景图片URL和二维码位置配置) +// String cacheKey = String.format("inviteCode:final:%s:%s:%s:%s:%s:%s", +// user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY); +// +// // 移除图片数据的Redis缓存,避免类型转换错误 +// // 直接检查OSS中是否已存在最终图片 +// +// // 检查OSS中是否已存在最终图片 +// String finalPath = String.format("invite/final/%s_%s_%s_%s_%s_%s.jpg", +// user.getId(), trial, xcxSharePage.hashCode(), backgroundImageUrl.hashCode(), qrCodeX, qrCodeY); +// try { +// InputStream ossFile = OssBootUtil.getOssFile(finalPath, null); +// if (ossFile != null) { +// try { +// // 使用ByteArrayOutputStream读取InputStream中的所有字节 +// java.io.ByteArrayOutputStream buffer = new java.io.ByteArrayOutputStream(); +// int nRead; +// byte[] data = new byte[1024]; +// while ((nRead = ossFile.read(data, 0, data.length)) != -1) { +// buffer.write(data, 0, nRead); +// } +// buffer.flush(); +// byte[] ossImageBytes = buffer.toByteArray(); +// +// // 直接返回OSS中的图片,不再缓存到Redis +// log.info("从OSS返回邀请码图片,用户ID: {}", user.getId()); +// return ossImageBytes; +// } finally { +// ossFile.close(); +// } +// } +// } catch (Exception e) { +// log.debug("OSS中未找到最终图片,需要重新生成,用户ID: {}", user.getId()); +// } +// +// try { +// // 直接生成小程序码,移除Redis缓存避免类型转换错误 +// log.info("生成小程序码,用户ID: {}", user.getId()); +// byte[] qrCodeBytes = generateWxQrCode(user, xcxSharePage, trial); +// +// // 生成最终合成图片,传递已获取的配置参数避免重复调用 +// byte[] finalImage = this.generateAndCombineImagesFromUrl2(qrCodeBytes, backgroundImageUrl, qrCodeX, qrCodeY); +// +// // 异步上传到OSS(移除Redis缓存) +// uploadToOssAsync(finalImage, finalPath); +// +// return finalImage; +// } catch (Exception e) { +// log.error("生成邀请码失败,用户ID: {}", user.getId(), e); +// return null; +// } +// } + + /** + * 生成微信小程序码 + */ + private byte[] generateWxQrCode(String userId, String xcxSharePage, String trial) throws Exception { + // 准备微信API请求参数 + Map param = new HashMap<>(); + param.put("path", xcxSharePage); + param.put("scene", userId); + param.put("width", 150); + param.put("auto_color", false); + param.put("env_version", trial); + + Map line_color = new HashMap<>(); + line_color.put("r", 0); + line_color.put("g", 0); + line_color.put("b", 0); + param.put("line_color", line_color); +// param.put("is_hyaline", true); + + // 获取微信小程序码 + String accessToken = wxHttpUtils.getAccessToken(); + String url = "https://api.weixin.qq.com/wxa/getwxacode?access_token=" + accessToken; + + // 请求微信API获取二维码图片数据 + RestTemplate rest = new RestTemplate(); + MultiValueMap headers = new LinkedMultiValueMap<>(); + HttpEntity requestEntity = new HttpEntity(JSON.toJSONString(param), headers); + ResponseEntity entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]); + + return entity.getBody(); + } + +// /** +// * 异步上传到OSS +// */ +// private void uploadToOssAsync(byte[] imageBytes, String ossPath) { +// // 使用线程池异步执行上传操作 +// CompletableFuture.runAsync(() -> { +// try { +// // 上传到OSS +// OssBootUtil.upload(new ByteArrayInputStream(imageBytes), ossPath); +// log.info("异步上传OSS完成,路径: {}", ossPath); +// } catch (Exception e) { +// log.error("异步上传OSS失败,路径: {}", ossPath, e); +// } +// }, asyncExecutor); +// } + + + public byte[] generateAndCombineImagesFromUrl2(byte[] qrCodeImageByte, String backgroundUrl, int qr_code_x, int qr_code_y) { + File file = null; + try { + // 直接从URL加载背景图像,移除Redis缓存避免类型转换问题 + URL backgroundImageUrl = new URL(backgroundUrl); + BufferedImage backgroundImage = ImageIO.read(backgroundImageUrl); + log.debug("从URL加载背景图片: {}", backgroundUrl); + + // 从字节数组加载小程序码图像 + BufferedImage qrCodeImage = ImageIO.read(new ByteArrayInputStream(qrCodeImageByte)); + + // 使用传入的配置参数,避免重复调用配置服务 + + // 直接使用背景图片作为基础,避免创建新的图像导致黑边 + BufferedImage combinedImage = new BufferedImage( + backgroundImage.getWidth(), + backgroundImage.getHeight(), + backgroundImage.getType() // 使用背景图片的原始类型,保持透明度 + ); + + Graphics2D g2d = combinedImage.createGraphics(); + + // 设置高质量渲染 + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // 先绘制背景图像,完全覆盖画布 + g2d.drawImage(backgroundImage, 0, 0, backgroundImage.getWidth(), backgroundImage.getHeight(), null); + + int wh = backgroundImage.getWidth() / 3; + + // 计算小程序码放置的位置(这里以中心位置为例) + int qrCodeX = (backgroundImage.getWidth() - wh) / 2; + int qrCodeY = (int) ((backgroundImage.getHeight() - wh) * 0.6); + + // 绘制小程序码图像,使用传入的位置参数 + g2d.drawImage(qrCodeImage, qrCodeX + qr_code_x, qrCodeY + qr_code_y, wh, wh, null); + + // 释放Graphics2D资源 + g2d.dispose(); + + // 将合并后的图像保存到临时文件 + file = File.createTempFile("combined_", ".png"); + ImageIO.write(combinedImage, "png", file); + + // 读取文件字节并返回 + return Files.readAllBytes(file.toPath()); + } catch (Exception e) { + log.error("生成合并图片失败", e); + throw new RuntimeException("生成合并图片失败", e); + } finally { + // 删除临时文件 + if (file != null && file.exists()) { + file.delete(); + } + } + } + +} diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpClientUtil.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpClientUtil.java new file mode 100644 index 0000000..182c490 --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpClientUtil.java @@ -0,0 +1,264 @@ +package org.jeecg.modules.api.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpStatus; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLContextBuilder; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.URI; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; + +/** + * 微信API专用HTTP客户端工具类 + * 具有超时配置、重试机制和异常处理 + * + * @author system + * @date 2025-01-25 + */ +@Slf4j +public class WxHttpClientUtil { + + // 超时配置常量 + private static final int CONNECTION_REQUEST_TIMEOUT = 10000; // 10秒 + private static final int CONNECT_TIMEOUT = 15000; // 15秒 + private static final int SOCKET_TIMEOUT = 30000; // 30秒 + private static final int MAX_RETRY_COUNT = 3; // 最大重试次数 + + /** + * 创建带超时配置的SSL客户端 + */ + private static CloseableHttpClient createWxHttpClient() { + try { + // SSL配置 - 信任所有证书 + SSLContext sslContext = new SSLContextBuilder() + .loadTrustMaterial(null, new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }).build(); + + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + sslContext, + SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER + ); + + // 请求配置 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT) + .setConnectTimeout(CONNECT_TIMEOUT) + .setSocketTimeout(SOCKET_TIMEOUT) + .build(); + + // 重试处理器 + DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(MAX_RETRY_COUNT, true); + + return HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setDefaultRequestConfig(requestConfig) + .setRetryHandler(retryHandler) + .build(); + + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + log.error("创建SSL客户端失败: {}", e.getMessage(), e); + // 返回默认客户端作为后备 + return HttpClients.createDefault(); + } + } + + /** + * 执行GET请求(微信API专用) + * @param url 请求URL + * @param params 请求参数 + * @return 响应字符串 + */ + public static String doGet(String url, Map params) { + return doGetWithRetry(url, params, 0); + } + + /** + * 执行GET请求(微信API专用) + * @param url 请求URL + * @return 响应字符串 + */ + public static String doGet(String url) { + return doGet(url, null); + } + + /** + * 带重试机制的GET请求 + */ + private static String doGetWithRetry(String url, Map params, int retryCount) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + + try { + log.info("开始请求微信API: {}, 重试次数: {}", url, retryCount); + + httpClient = createWxHttpClient(); + + // 构建URI + URIBuilder builder = new URIBuilder(url); + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + builder.addParameter(entry.getKey(), entry.getValue()); + } + } + URI uri = builder.build(); + + // 创建GET请求 + HttpGet httpGet = new HttpGet(uri); + httpGet.setHeader("User-Agent", "WxHttpClient/1.0"); + httpGet.setHeader("Accept", "application/json, text/plain, */*"); + + // 执行请求 + response = httpClient.execute(httpGet); + + // 检查响应状态 + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + String result = EntityUtils.toString(response.getEntity(), "UTF-8"); + log.info("微信API请求成功: {}", url); + return result; + } else { + log.warn("微信API返回非200状态码: {}, URL: {}", statusCode, url); + throw new RuntimeException("HTTP状态码异常: " + statusCode); + } + + } catch (Exception e) { + log.error("微信API请求失败: {}, 错误: {}, 重试次数: {}", url, e.getMessage(), retryCount); + + // 如果还有重试机会,进行重试 + if (retryCount < MAX_RETRY_COUNT) { + log.info("准备进行第{}次重试...", retryCount + 1); + try { + Thread.sleep(1000 * (retryCount + 1)); // 递增延迟 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + return doGetWithRetry(url, params, retryCount + 1); + } + + // 重试次数用尽,抛出异常 + throw new RuntimeException("微信API请求失败,已重试" + MAX_RETRY_COUNT + "次: " + e.getMessage(), e); + + } finally { + // 关闭资源 + if (response != null) { + try { + response.close(); + } catch (IOException e) { + log.error("关闭响应失败: {}", e.getMessage()); + } + } + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + log.error("关闭客户端失败: {}", e.getMessage()); + } + } + } + } + + /** + * 执行POST请求(微信API专用) + * @param url 请求URL + * @param jsonBody JSON请求体 + * @return 响应字符串 + */ + public static String doPost(String url, String jsonBody) { + return doPostWithRetry(url, jsonBody, 0); + } + + /** + * 带重试机制的POST请求 + */ + private static String doPostWithRetry(String url, String jsonBody, int retryCount) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + + try { + log.info("开始POST请求微信API: {}, 重试次数: {}", url, retryCount); + + httpClient = createWxHttpClient(); + + // 创建POST请求 + HttpPost httpPost = new HttpPost(url); + httpPost.setHeader("Content-Type", "application/json; charset=UTF-8"); + httpPost.setHeader("User-Agent", "WxHttpClient/1.0"); + + // 设置请求体 + if (jsonBody != null) { + StringEntity entity = new StringEntity(jsonBody, "UTF-8"); + httpPost.setEntity(entity); + } + + // 执行请求 + response = httpClient.execute(httpPost); + + // 检查响应状态 + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + String result = EntityUtils.toString(response.getEntity(), "UTF-8"); + log.info("微信API POST请求成功: {}", url); + return result; + } else { + log.warn("微信API POST返回非200状态码: {}, URL: {}", statusCode, url); + throw new RuntimeException("HTTP状态码异常: " + statusCode); + } + + } catch (Exception e) { + log.error("微信API POST请求失败: {}, 错误: {}, 重试次数: {}", url, e.getMessage(), retryCount); + + // 如果还有重试机会,进行重试 + if (retryCount < MAX_RETRY_COUNT) { + log.info("准备进行第{}次重试...", retryCount + 1); + try { + Thread.sleep(1000 * (retryCount + 1)); // 递增延迟 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + return doPostWithRetry(url, jsonBody, retryCount + 1); + } + + // 重试次数用尽,抛出异常 + throw new RuntimeException("微信API POST请求失败,已重试" + MAX_RETRY_COUNT + "次: " + e.getMessage(), e); + + } finally { + // 关闭资源 + if (response != null) { + try { + response.close(); + } catch (IOException e) { + log.error("关闭响应失败: {}", e.getMessage()); + } + } + if (httpClient != null) { + try { + httpClient.close(); + } catch (IOException e) { + log.error("关闭客户端失败: {}", e.getMessage()); + } + } + } + } +} \ No newline at end of file diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpUtils.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpUtils.java new file mode 100644 index 0000000..81ba1e0 --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/utils/WxHttpUtils.java @@ -0,0 +1,179 @@ +package org.jeecg.modules.api.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.TreeMap; + +@Getter +@Component +public class WxHttpUtils { + + @Value("${wechat.mpAppId}") + private String appid; + @Value("${wechat.mpAppSecret}") + private String secret;// +// @Value("${wechat.merchantId}") +// private String mchId;// + + +// @Value("${wechat.official.appid}") +// private String officialAppid; +// @Value("${wechat.official.appsecret}") +// private String officialSecret;// + + private static String shipmentUrl = "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token="; + private static final String GET_USER_PHONE_NUMBER = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"; + + private static String jsapiTicket = null; // 用于缓存jsapi_ticket + + /** + * 获取令牌 + * + * @return + */ + public String getAccessToken(String mAppId, String mSecret) { + String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + mAppId + "&secret=" + mSecret; + + try { + // 使用增强版HTTP客户端,具有超时配置和重试机制 + String response = WxHttpClientUtil.doGet(requestUrl); + Map map = JSON.parseObject(response, new TypeReference>() {}); + + String accessToken = map.get("access_token"); + if (accessToken == null || accessToken.isEmpty()) { + throw new RuntimeException("获取access_token失败,响应: " + response); + } + + return accessToken; + } catch (Exception e) { + throw new RuntimeException("获取微信access_token失败: " + e.getMessage(), e); + } + } + + public String getAccessToken() { + return getAccessToken(appid, secret); + } + + public String getPhoneNumber(String code) throws Exception { + URL url = new URL(GET_USER_PHONE_NUMBER + "?access_token=" + this.getAccessToken()); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json; utf-8"); + conn.setRequestProperty("Accept", "application/json"); + conn.setDoOutput(true); + + JSONObject jsonInput = new JSONObject(); + jsonInput.put("code", code); + + try (DataOutputStream os = new DataOutputStream(conn.getOutputStream())) { + byte[] input = jsonInput.toString().getBytes(StandardCharsets.UTF_8); + os.write(input, 0, input.length); + } + + try (BufferedReader br = new BufferedReader( + new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) { + StringBuilder response = new StringBuilder(); + String responseLine; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + //获取手机号码 + return response.toString(); + } + } + + + // 获取jsapi_ticket + private String getJsApiTicket() throws Exception { + String accessToken = getAccessToken("officialAppid", "officialSecret"); + String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi"; + jsapiTicket = sendGet(url, "UTF-8"); + System.out.println("jsapiTicket=========="+jsapiTicket); + return jsapiTicket; + } + + // 发送GET请求并获取响应 + private String sendGet(String url, String encoding) throws Exception { + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setRequestMethod("GET"); + connection.connect(); + + BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), encoding)); + String inputLine; + StringBuilder content = new StringBuilder(); + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + } + in.close(); + connection.disconnect(); + return content.toString(); + } + + /** + * 获取公众号签名 + * + * @param url URL + * @return 结果 + */ + public Map getSignPackage(String url) throws Exception { + String jsapiTicket = getJsApiTicket(); + + + JSONObject jsonObject = JSONObject.parseObject(jsapiTicket); // 解析JSON字符串 + jsapiTicket = jsonObject.getString("ticket"); // 提取access_token + + + String nonceStr = createNonceStr(); + long timestamp = System.currentTimeMillis() / 1000; + + String string1 = "jsapi_ticket=" + jsapiTicket + + "&noncestr=" + nonceStr + + "×tamp=" + timestamp + + "&url=" + url; // 确保URL是编码过的 + + String signature = sha1(string1); + + Map ret = new TreeMap<>(); + ret.put("appId", "officialAppid"); + ret.put("timestamp", timestamp); + ret.put("nonceStr", nonceStr); + ret.put("signature", signature); + ret.put("jsapi_ticket", jsapiTicket); + ret.put("url",url); + + return ret; + } + + // 生成随机字符串 + private String createNonceStr() { + return String.valueOf((long) (Math.random() * 100000000)); + } + + // SHA1加密 + private String sha1(String input) throws NoSuchAlgorithmException, UnsupportedEncodingException { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] messageDigest = md.digest(input.getBytes("UTF-8")); + StringBuilder hexString = new StringBuilder(); + for (byte b : messageDigest) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java index e288cf0..14b91d5 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiController.java @@ -168,8 +168,8 @@ public class YaoDuApiController { //获取评论列表 @ApiOperation(value="获取评论列表type/0帖子/1租房/2工作/3景点/4美食/5活动") @GetMapping(value = "/getCommentPage") - public Result getCommentPage(String orderId,String type,PageBean pageBean) { - return yaoDuApiService.getCommentPage(orderId,type,pageBean); + public Result getCommentPage(String pid, String orderId, String type,PageBean pageBean) { + return yaoDuApiService.getCommentPage(pid, orderId, type, pageBean); } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiTokenController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiTokenController.java index 0fe3d96..39fd60b 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiTokenController.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuApiTokenController.java @@ -154,6 +154,13 @@ public class YaoDuApiTokenController { return yaoDuApiService.comment(token,cityComment); } + //获取评论详情 + @ApiOperation(value="获取评论详情") + @GetMapping("/commentDetail") + public Result commentDetail(String id) { + return yaoDuApiService.commentDetail(id); + } + //删除评论 @ApiOperation(value="删除评论") @PostMapping("/deleteComment") diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuArticleController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuArticleController.java new file mode 100644 index 0000000..b31adea --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuArticleController.java @@ -0,0 +1,35 @@ +package org.jeecg.modules.api.yaoduapi; + +import org.apache.commons.lang.StringUtils; +import org.jeecg.common.api.vo.Result; +import org.jeecg.modules.api.bean.YaoDuOrderBean; +import org.jeecg.modules.appletArticle.entity.AppletArticle; +import org.jeecg.modules.appletArticle.service.IAppletArticleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/city/article") +public class YaoDuArticleController { + + @Autowired + private IAppletArticleService appletArticleService; + + @GetMapping(value = "/list") + public Result list(String title, YaoDuOrderBean bean) { + return Result.OK(appletArticleService + .lambdaQuery() + .eq(StringUtils.isNotEmpty(title), AppletArticle::getTitle, title) + .select(AppletArticle::getId, AppletArticle::getTitle, AppletArticle::getImage) + .orderByDesc(AppletArticle::getCreateTime) + .page(bean.getPage())); + } + + @GetMapping(value = "/queryById") + public Result queryById(String id) { + return Result.OK(appletArticleService.getById(id)); + } + +} diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuOrderController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuOrderController.java index 99357b8..867546f 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuOrderController.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuOrderController.java @@ -120,4 +120,6 @@ public class YaoDuOrderController { return yaoDuOrderService.getMemberInfo(token); } + + } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuShopController.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuShopController.java new file mode 100644 index 0000000..269f52b --- /dev/null +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/YaoDuShopController.java @@ -0,0 +1,31 @@ +package org.jeecg.modules.api.yaoduapi; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.vo.Result; +import org.jeecg.modules.api.service.YaoDuShopService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags="店铺模块相关接口") +@RestController +@RequestMapping("/city/shop") +@Slf4j +public class YaoDuShopController { + + @Autowired + private YaoDuShopService yaoDuShopService; + + // 获取店铺二维码 + @ApiOperation(value="获取店铺二维码", notes="获取店铺二维码") + @GetMapping(value = "/shopQrCode", produces = MediaType.IMAGE_PNG_VALUE) + public byte[] shopQrCode(@RequestHeader(value = "X-Access-Token", required = false) String token, String id) throws Exception { + return yaoDuShopService.shopQrCode(token, id); + } + +}