| @ -0,0 +1,156 @@ | |||
| package org.jeecg.modules.banner.controller; | |||
| import java.util.Arrays; | |||
| 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.modules.banner.entity.WebBanner; | |||
| import org.jeecg.modules.banner.service.IWebBannerService; | |||
| 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.jeecg.common.system.base.controller.JeecgController; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.servlet.ModelAndView; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.jeecg.common.aspect.annotation.AutoLog; | |||
| /** | |||
| * @Description: banner设置 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Api(tags="banner设置") | |||
| @RestController | |||
| @RequestMapping("/banner/webBanner") | |||
| @Slf4j | |||
| public class WebBannerController extends JeecgController<WebBanner, IWebBannerService> { | |||
| @Autowired | |||
| private IWebBannerService webBannerService; | |||
| /** | |||
| * 分页列表查询 | |||
| * | |||
| * @param webBanner | |||
| * @param pageNo | |||
| * @param pageSize | |||
| * @param req | |||
| * @return | |||
| */ | |||
| //@AutoLog(value = "banner设置-分页列表查询") | |||
| @ApiOperation(value="banner设置-分页列表查询", notes="banner设置-分页列表查询") | |||
| @GetMapping(value = "/list") | |||
| public Result<IPage<WebBanner>> queryPageList(WebBanner webBanner, | |||
| @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, | |||
| @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, | |||
| HttpServletRequest req) { | |||
| QueryWrapper<WebBanner> queryWrapper = QueryGenerator.initQueryWrapper(webBanner, req.getParameterMap()); | |||
| Page<WebBanner> page = new Page<WebBanner>(pageNo, pageSize); | |||
| IPage<WebBanner> pageList = webBannerService.page(page, queryWrapper); | |||
| return Result.OK(pageList); | |||
| } | |||
| /** | |||
| * 添加 | |||
| * | |||
| * @param webBanner | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "banner设置-添加") | |||
| @ApiOperation(value="banner设置-添加", notes="banner设置-添加") | |||
| @PostMapping(value = "/add") | |||
| public Result<String> add(@RequestBody WebBanner webBanner) { | |||
| webBannerService.save(webBanner); | |||
| return Result.OK("添加成功!"); | |||
| } | |||
| /** | |||
| * 编辑 | |||
| * | |||
| * @param webBanner | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "banner设置-编辑") | |||
| @ApiOperation(value="banner设置-编辑", notes="banner设置-编辑") | |||
| @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |||
| public Result<String> edit(@RequestBody WebBanner webBanner) { | |||
| webBannerService.updateById(webBanner); | |||
| return Result.OK("编辑成功!"); | |||
| } | |||
| /** | |||
| * 通过id删除 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "banner设置-通过id删除") | |||
| @ApiOperation(value="banner设置-通过id删除", notes="banner设置-通过id删除") | |||
| @DeleteMapping(value = "/delete") | |||
| public Result<String> delete(@RequestParam(name="id",required=true) String id) { | |||
| webBannerService.removeById(id); | |||
| return Result.OK("删除成功!"); | |||
| } | |||
| /** | |||
| * 批量删除 | |||
| * | |||
| * @param ids | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "banner设置-批量删除") | |||
| @ApiOperation(value="banner设置-批量删除", notes="banner设置-批量删除") | |||
| @DeleteMapping(value = "/deleteBatch") | |||
| public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | |||
| this.webBannerService.removeByIds(Arrays.asList(ids.split(","))); | |||
| return Result.OK("批量删除成功!"); | |||
| } | |||
| /** | |||
| * 通过id查询 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| //@AutoLog(value = "banner设置-通过id查询") | |||
| @ApiOperation(value="banner设置-通过id查询", notes="banner设置-通过id查询") | |||
| @GetMapping(value = "/queryById") | |||
| public Result<WebBanner> queryById(@RequestParam(name="id",required=true) String id) { | |||
| WebBanner webBanner = webBannerService.getById(id); | |||
| if(webBanner==null) { | |||
| return Result.error("未找到对应数据"); | |||
| } | |||
| return Result.OK(webBanner); | |||
| } | |||
| /** | |||
| * 导出excel | |||
| * | |||
| * @param request | |||
| * @param webBanner | |||
| */ | |||
| @RequestMapping(value = "/exportXls") | |||
| public ModelAndView exportXls(HttpServletRequest request, WebBanner webBanner) { | |||
| return super.exportXls(request, webBanner, WebBanner.class, "banner设置"); | |||
| } | |||
| /** | |||
| * 通过excel导入数据 | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| @RequestMapping(value = "/importExcel", method = RequestMethod.POST) | |||
| public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) { | |||
| return super.importExcel(request, response, WebBanner.class); | |||
| } | |||
| } | |||
| @ -0,0 +1,76 @@ | |||
| package org.jeecg.modules.banner.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: banner设置 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Data | |||
| @TableName("web_banner") | |||
| @Accessors(chain = true) | |||
| @EqualsAndHashCode(callSuper = false) | |||
| @ApiModel(value="web_banner对象", description="banner设置") | |||
| public class WebBanner implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /**id*/ | |||
| @TableId(type = IdType.ASSIGN_ID) | |||
| @ApiModelProperty(value = "id") | |||
| private String id; | |||
| /**图片*/ | |||
| @Excel(name = "图片", width = 15) | |||
| @ApiModelProperty(value = "图片") | |||
| private String image; | |||
| /**跳转地址*/ | |||
| @Excel(name = "跳转地址", width = 15) | |||
| @ApiModelProperty(value = "跳转地址") | |||
| private String toUrl; | |||
| /**排序*/ | |||
| @Excel(name = "排序", width = 15) | |||
| @ApiModelProperty(value = "排序") | |||
| private Integer sort; | |||
| /**0 首页上方banner轮播 1 首页第二处 2首页第三处*/ | |||
| @Excel(name = "0 首页上方banner轮播 1 首页第二处 2首页第三处", width = 15, dicCode = "bannerType") | |||
| @Dict(dicCode = "bannerType") | |||
| @ApiModelProperty(value = "0 首页上方banner轮播 1 首页第二处 2首页第三处") | |||
| private Integer type; | |||
| /**是否删除 0否 1是*/ | |||
| @Excel(name = "是否删除 0否 1是", width = 15, dicCode = "is_disable") | |||
| @Dict(dicCode = "is_disable") | |||
| @ApiModelProperty(value = "是否删除 0否 1是") | |||
| private Integer isDisable; | |||
| /**创建时间*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "创建时间") | |||
| private Date createTime; | |||
| /**修改时间*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "修改时间") | |||
| private Date updateTime; | |||
| /**更新人*/ | |||
| @ApiModelProperty(value = "更新人") | |||
| private String updateBy; | |||
| /**所属部门*/ | |||
| @ApiModelProperty(value = "所属部门") | |||
| private String sysOrgCode; | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.banner.mapper; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||
| /** | |||
| * @Description: banner设置 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface WebBannerMapper extends BaseMapper<WebBanner> { | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
| <mapper namespace="org.jeecg.modules.banner.mapper.WebBannerMapper"> | |||
| </mapper> | |||
| @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.banner.service; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import com.baomidou.mybatisplus.extension.service.IService; | |||
| /** | |||
| * @Description: banner设置 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface IWebBannerService extends IService<WebBanner> { | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| package org.jeecg.modules.banner.service.impl; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import org.jeecg.modules.banner.mapper.WebBannerMapper; | |||
| import org.jeecg.modules.banner.service.IWebBannerService; | |||
| import org.springframework.stereotype.Service; | |||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||
| /** | |||
| * @Description: banner设置 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Service | |||
| public class WebBannerServiceImpl extends ServiceImpl<WebBannerMapper, WebBanner> implements IWebBannerService { | |||
| } | |||
| @ -0,0 +1,197 @@ | |||
| <template> | |||
| <a-card :bordered="false"> | |||
| <!-- 查询区域 --> | |||
| <div class="table-page-search-wrapper"> | |||
| <a-form layout="inline" @keyup.enter.native="searchQuery"> | |||
| <a-row :gutter="24"> | |||
| </a-row> | |||
| </a-form> | |||
| </div> | |||
| <!-- 查询区域-END --> | |||
| <!-- 操作按钮区域 --> | |||
| <div class="table-operator"> | |||
| <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button> | |||
| <a-button type="primary" icon="download" @click="handleExportXls('banner设置')">导出</a-button> | |||
| <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel"> | |||
| <a-button type="primary" icon="import">导入</a-button> | |||
| </a-upload> | |||
| <!-- 高级查询区域 --> | |||
| <j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query> | |||
| <a-dropdown v-if="selectedRowKeys.length > 0"> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item> | |||
| </a-menu> | |||
| <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button> | |||
| </a-dropdown> | |||
| </div> | |||
| <!-- table区域-begin --> | |||
| <div> | |||
| <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;"> | |||
| <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项 | |||
| <a style="margin-left: 24px" @click="onClearSelected">清空</a> | |||
| </div> | |||
| <a-table | |||
| ref="table" | |||
| size="middle" | |||
| :scroll="{x:true}" | |||
| bordered | |||
| rowKey="id" | |||
| :columns="columns" | |||
| :dataSource="dataSource" | |||
| :pagination="ipagination" | |||
| :loading="loading" | |||
| :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" | |||
| class="j-table-force-nowrap" | |||
| @change="handleTableChange"> | |||
| <template slot="htmlSlot" slot-scope="text"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template slot="imgSlot" slot-scope="text,record"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span> | |||
| <img v-else :src="getImgView(text)" :preview="record.id" height="25px" alt="" style="max-width:80px;font-size: 12px;font-style: italic;"/> | |||
| </template> | |||
| <template slot="fileSlot" slot-scope="text"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button | |||
| v-else | |||
| :ghost="true" | |||
| type="primary" | |||
| icon="download" | |||
| size="small" | |||
| @click="downloadFile(text)"> | |||
| 下载 | |||
| </a-button> | |||
| </template> | |||
| <span slot="action" slot-scope="text, record"> | |||
| <a @click="handleEdit(record)">编辑</a> | |||
| <a-divider type="vertical" /> | |||
| <a-dropdown> | |||
| <a class="ant-dropdown-link">更多 <a-icon type="down" /></a> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item> | |||
| <a @click="handleDetail(record)">详情</a> | |||
| </a-menu-item> | |||
| <a-menu-item> | |||
| <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)"> | |||
| <a>删除</a> | |||
| </a-popconfirm> | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </a-dropdown> | |||
| </span> | |||
| </a-table> | |||
| </div> | |||
| <web-banner-modal ref="modalForm" @ok="modalFormOk"></web-banner-modal> | |||
| </a-card> | |||
| </template> | |||
| <script> | |||
| import '@/assets/less/TableExpand.less' | |||
| import { mixinDevice } from '@/utils/mixin' | |||
| import { JeecgListMixin } from '@/mixins/JeecgListMixin' | |||
| import WebBannerModal from './modules/WebBannerModal' | |||
| import {filterMultiDictText} from '@/components/dict/JDictSelectUtil' | |||
| export default { | |||
| name: 'WebBannerList', | |||
| mixins:[JeecgListMixin, mixinDevice], | |||
| components: { | |||
| WebBannerModal | |||
| }, | |||
| data () { | |||
| return { | |||
| description: 'banner设置管理页面', | |||
| // 表头 | |||
| columns: [ | |||
| { | |||
| title: '#', | |||
| dataIndex: '', | |||
| key:'rowIndex', | |||
| width:60, | |||
| align:"center", | |||
| customRender:function (t,r,index) { | |||
| return parseInt(index)+1; | |||
| } | |||
| }, | |||
| { | |||
| title:'图片', | |||
| align:"center", | |||
| dataIndex: 'image', | |||
| scopedSlots: {customRender: 'imgSlot'} | |||
| }, | |||
| { | |||
| title:'跳转地址', | |||
| align:"center", | |||
| dataIndex: 'toUrl' | |||
| }, | |||
| { | |||
| title:'排序', | |||
| align:"center", | |||
| dataIndex: 'sort' | |||
| }, | |||
| { | |||
| title:'0 首页上方banner轮播 1 首页第二处 2首页第三处', | |||
| align:"center", | |||
| dataIndex: 'type_dictText' | |||
| }, | |||
| { | |||
| title:'是否删除 0否 1是', | |||
| align:"center", | |||
| dataIndex: 'isDisable_dictText' | |||
| }, | |||
| { | |||
| title: '操作', | |||
| dataIndex: 'action', | |||
| align:"center", | |||
| fixed:"right", | |||
| width:147, | |||
| scopedSlots: { customRender: 'action' } | |||
| } | |||
| ], | |||
| url: { | |||
| list: "/banner/webBanner/list", | |||
| delete: "/banner/webBanner/delete", | |||
| deleteBatch: "/banner/webBanner/deleteBatch", | |||
| exportXlsUrl: "/banner/webBanner/exportXls", | |||
| importExcelUrl: "banner/webBanner/importExcel", | |||
| }, | |||
| dictOptions:{}, | |||
| superFieldList:[], | |||
| } | |||
| }, | |||
| created() { | |||
| this.getSuperFieldList(); | |||
| }, | |||
| computed: { | |||
| importExcelUrl: function(){ | |||
| return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`; | |||
| }, | |||
| }, | |||
| methods: { | |||
| initDictConfig(){ | |||
| }, | |||
| getSuperFieldList(){ | |||
| let fieldList=[]; | |||
| fieldList.push({type:'string',value:'image',text:'图片',dictCode:''}) | |||
| fieldList.push({type:'string',value:'toUrl',text:'跳转地址',dictCode:''}) | |||
| fieldList.push({type:'popup',value:'sort',text:'排序', popup:{code:'',field:'',orgFields:'',destFields:''}}) | |||
| fieldList.push({type:'int',value:'type',text:'0 首页上方banner轮播 1 首页第二处 2首页第三处',dictCode:'bannerType'}) | |||
| fieldList.push({type:'int',value:'isDisable',text:'是否删除 0否 1是',dictCode:'is_disable'}) | |||
| this.superFieldList = fieldList | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| @import '~@assets/less/common.less'; | |||
| </style> | |||
| @ -0,0 +1,141 @@ | |||
| <template> | |||
| <a-spin :spinning="confirmLoading"> | |||
| <j-form-container :disabled="formDisabled"> | |||
| <a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail"> | |||
| <a-row> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="image"> | |||
| <j-image-upload isMultiple v-model="model.image" ></j-image-upload> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="跳转地址" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="toUrl"> | |||
| <a-input v-model="model.toUrl" placeholder="请输入跳转地址" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="sort"> | |||
| <j-popup | |||
| v-model="model.sort" | |||
| field="sort" | |||
| org-fields="" | |||
| dest-fields="" | |||
| code="" | |||
| :multi="true" | |||
| @input="popupCallback" | |||
| /> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="0 首页上方banner轮播 1 首页第二处 2首页第三处" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="type"> | |||
| <j-dict-select-tag type="list" v-model="model.type" dictCode="bannerType" placeholder="请选择0 首页上方banner轮播 1 首页第二处 2首页第三处" /> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="是否删除 0否 1是" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="isDisable"> | |||
| <j-dict-select-tag type="list" v-model="model.isDisable" dictCode="is_disable" placeholder="请选择是否删除 0否 1是" /> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| </a-row> | |||
| </a-form-model> | |||
| </j-form-container> | |||
| </a-spin> | |||
| </template> | |||
| <script> | |||
| import { httpAction, getAction } from '@/api/manage' | |||
| import { validateDuplicateValue } from '@/utils/util' | |||
| export default { | |||
| name: 'WebBannerForm', | |||
| components: { | |||
| }, | |||
| props: { | |||
| //表单禁用 | |||
| disabled: { | |||
| type: Boolean, | |||
| default: false, | |||
| required: false | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| model:{ | |||
| }, | |||
| labelCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 5 }, | |||
| }, | |||
| wrapperCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 16 }, | |||
| }, | |||
| confirmLoading: false, | |||
| validatorRules: { | |||
| sort: [ | |||
| { required: true, message: '请输入排序!'}, | |||
| ], | |||
| isDisable: [ | |||
| { required: true, message: '请输入是否删除 0否 1是!'}, | |||
| ], | |||
| }, | |||
| url: { | |||
| add: "/banner/webBanner/add", | |||
| edit: "/banner/webBanner/edit", | |||
| queryById: "/banner/webBanner/queryById" | |||
| } | |||
| } | |||
| }, | |||
| computed: { | |||
| formDisabled(){ | |||
| return this.disabled | |||
| }, | |||
| }, | |||
| created () { | |||
| //备份model原始值 | |||
| this.modelDefault = JSON.parse(JSON.stringify(this.model)); | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.edit(this.modelDefault); | |||
| }, | |||
| edit (record) { | |||
| this.model = Object.assign({}, record); | |||
| this.visible = true; | |||
| }, | |||
| submitForm () { | |||
| const that = this; | |||
| // 触发表单验证 | |||
| this.$refs.form.validate(valid => { | |||
| if (valid) { | |||
| that.confirmLoading = true; | |||
| let httpurl = ''; | |||
| let method = ''; | |||
| if(!this.model.id){ | |||
| httpurl+=this.url.add; | |||
| method = 'post'; | |||
| }else{ | |||
| httpurl+=this.url.edit; | |||
| method = 'put'; | |||
| } | |||
| httpAction(httpurl,this.model,method).then((res)=>{ | |||
| if(res.success){ | |||
| that.$message.success(res.message); | |||
| that.$emit('ok'); | |||
| }else{ | |||
| that.$message.warning(res.message); | |||
| } | |||
| }).finally(() => { | |||
| that.confirmLoading = false; | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| popupCallback(value,row){ | |||
| this.model = Object.assign(this.model, row); | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,84 @@ | |||
| <template> | |||
| <a-drawer | |||
| :title="title" | |||
| :width="width" | |||
| placement="right" | |||
| :closable="false" | |||
| @close="close" | |||
| destroyOnClose | |||
| :visible="visible"> | |||
| <web-banner-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit" normal></web-banner-form> | |||
| <div class="drawer-footer"> | |||
| <a-button @click="handleCancel" style="margin-bottom: 0;">关闭</a-button> | |||
| <a-button v-if="!disableSubmit" @click="handleOk" type="primary" style="margin-bottom: 0;">提交</a-button> | |||
| </div> | |||
| </a-drawer> | |||
| </template> | |||
| <script> | |||
| import WebBannerForm from './WebBannerForm' | |||
| export default { | |||
| name: 'WebBannerModal', | |||
| components: { | |||
| WebBannerForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:"操作", | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }); | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| /** Button按钮间距 */ | |||
| .ant-btn { | |||
| margin-left: 30px; | |||
| margin-bottom: 30px; | |||
| float: right; | |||
| } | |||
| .drawer-footer{ | |||
| position: absolute; | |||
| bottom: -8px; | |||
| width: 100%; | |||
| border-top: 1px solid #e8e8e8; | |||
| padding: 10px 16px; | |||
| text-align: right; | |||
| left: 0; | |||
| background: #fff; | |||
| border-radius: 0 0 2px 2px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,60 @@ | |||
| <template> | |||
| <j-modal | |||
| :title="title" | |||
| :width="width" | |||
| :visible="visible" | |||
| switchFullscreen | |||
| @ok="handleOk" | |||
| :okButtonProps="{ class:{'jee-hidden': disableSubmit} }" | |||
| @cancel="handleCancel" | |||
| cancelText="关闭"> | |||
| <web-banner-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></web-banner-form> | |||
| </j-modal> | |||
| </template> | |||
| <script> | |||
| import WebBannerForm from './WebBannerForm' | |||
| export default { | |||
| name: 'WebBannerModal', | |||
| components: { | |||
| WebBannerForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:'', | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }) | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,61 @@ | |||
| import {defHttp} from '/@/utils/http/axios'; | |||
| import {Modal} from 'ant-design-vue'; | |||
| enum Api { | |||
| list = '/banner/webBanner/list', | |||
| save='/banner/webBanner/add', | |||
| edit='/banner/webBanner/edit', | |||
| deleteOne = '/banner/webBanner/delete', | |||
| deleteBatch = '/banner/webBanner/deleteBatch', | |||
| importExcel = '/banner/webBanner/importExcel', | |||
| exportXls = '/banner/webBanner/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}); | |||
| } | |||
| @ -0,0 +1,91 @@ | |||
| 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: 'image', | |||
| customRender:render.renderAvatar, | |||
| }, | |||
| { | |||
| title: '跳转地址', | |||
| align:"center", | |||
| dataIndex: 'toUrl' | |||
| }, | |||
| { | |||
| title: '排序', | |||
| align:"center", | |||
| dataIndex: 'sort' | |||
| }, | |||
| { | |||
| title: '0 首页上方banner轮播 1 首页第二处 2首页第三处', | |||
| align:"center", | |||
| dataIndex: 'type_dictText' | |||
| }, | |||
| { | |||
| title: '是否删除 0否 1是', | |||
| align:"center", | |||
| dataIndex: 'isDisable_dictText' | |||
| }, | |||
| ]; | |||
| //查询数据 | |||
| export const searchFormSchema: FormSchema[] = [ | |||
| ]; | |||
| //表单数据 | |||
| export const formSchema: FormSchema[] = [ | |||
| { | |||
| label: '图片', | |||
| field: 'image', | |||
| component: 'JImageUpload', | |||
| componentProps:{ | |||
| }, | |||
| }, | |||
| { | |||
| label: '跳转地址', | |||
| field: 'toUrl', | |||
| component: 'Input', | |||
| }, | |||
| { | |||
| label: '排序', | |||
| field: 'sort', | |||
| component: 'JPopup', | |||
| componentProps: ({ formActionType }) => { | |||
| const {setFieldsValue} = formActionType; | |||
| return{ | |||
| setFieldsValue:setFieldsValue, | |||
| code:"", | |||
| fieldConfig:, | |||
| multi:true, | |||
| } | |||
| }, | |||
| dynamicRules: ({model,schema}) => { | |||
| return [ | |||
| { required: true, message: '请输入排序!'}, | |||
| ]; | |||
| }, | |||
| }, | |||
| { | |||
| label: '0 首页上方banner轮播 1 首页第二处 2首页第三处', | |||
| field: 'type', | |||
| component: 'JDictSelectTag', | |||
| componentProps:{ | |||
| dictCode:"bannerType" | |||
| }, | |||
| }, | |||
| { | |||
| label: '是否删除 0否 1是', | |||
| field: 'isDisable', | |||
| component: 'JDictSelectTag', | |||
| componentProps:{ | |||
| dictCode:"is_disable" | |||
| }, | |||
| dynamicRules: ({model,schema}) => { | |||
| return [ | |||
| { required: true, message: '请输入是否删除 0否 1是!'}, | |||
| ]; | |||
| }, | |||
| }, | |||
| ]; | |||
| @ -0,0 +1,162 @@ | |||
| <template> | |||
| <div> | |||
| <!--引用表格--> | |||
| <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |||
| <!--插槽:table标题--> | |||
| <template #tableTitle> | |||
| <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |||
| <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |||
| <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |||
| <a-dropdown v-if="checkedKeys.length > 0"> | |||
| <template #overlay> | |||
| <a-menu> | |||
| <a-menu-item key="1" @click="batchHandleDelete"> | |||
| <Icon icon="ant-design:delete-outlined"></Icon> | |||
| 删除 | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </template> | |||
| <a-button>批量操作 | |||
| <Icon icon="mdi:chevron-down"></Icon> | |||
| </a-button> | |||
| </a-dropdown> | |||
| </template> | |||
| <!--操作栏--> | |||
| <template #action="{ record }"> | |||
| <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |||
| </template> | |||
| <!--字段回显插槽--> | |||
| <template #htmlSlot="{text}"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template #fileSlot="{text}"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |||
| </template> | |||
| </BasicTable> | |||
| <!-- 表单区域 --> | |||
| <WebBannerModal @register="registerModal" @success="handleSuccess"></WebBannerModal> | |||
| </div> | |||
| </template> | |||
| <script lang="ts" name="banner-webBanner" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |||
| import {useModal} from '/@/components/Modal'; | |||
| import { useListPage } from '/@/hooks/system/useListPage' | |||
| import WebBannerModal from './components/WebBannerModal.vue' | |||
| import {columns, searchFormSchema} from './webBanner.data'; | |||
| import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './webBanner.api'; | |||
| const checkedKeys = ref<Array<string | number>>([]); | |||
| //注册model | |||
| const [registerModal, {openModal}] = useModal(); | |||
| //注册table数据 | |||
| const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |||
| tableProps:{ | |||
| title: 'banner设置', | |||
| api: list, | |||
| columns, | |||
| canResize:false, | |||
| formConfig: { | |||
| labelWidth: 120, | |||
| schemas: searchFormSchema, | |||
| autoSubmitOnEnter:true, | |||
| showAdvancedButton:true, | |||
| fieldMapToTime: [ | |||
| ], | |||
| }, | |||
| actionColumn: { | |||
| width: 120, | |||
| }, | |||
| }, | |||
| exportConfig: { | |||
| name:"banner设置", | |||
| url: getExportUrl, | |||
| }, | |||
| importConfig: { | |||
| url: getImportUrl | |||
| }, | |||
| }) | |||
| const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |||
| /** | |||
| * 新增事件 | |||
| */ | |||
| function handleAdd() { | |||
| openModal(true, { | |||
| isUpdate: false, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 编辑事件 | |||
| */ | |||
| function handleEdit(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 详情 | |||
| */ | |||
| function handleDetail(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: false, | |||
| }); | |||
| } | |||
| /** | |||
| * 删除事件 | |||
| */ | |||
| async function handleDelete(record) { | |||
| await deleteOne({id: record.id}, reload); | |||
| } | |||
| /** | |||
| * 批量删除事件 | |||
| */ | |||
| async function batchHandleDelete() { | |||
| await batchDelete({ids: checkedKeys.value}, reload); | |||
| } | |||
| /** | |||
| * 成功回调 | |||
| */ | |||
| function handleSuccess() { | |||
| reload(); | |||
| } | |||
| /** | |||
| * 操作栏 | |||
| */ | |||
| function getTableAction(record){ | |||
| return [ | |||
| { | |||
| label: '编辑', | |||
| onClick: handleEdit.bind(null, record), | |||
| } | |||
| ] | |||
| } | |||
| /** | |||
| * 下拉操作栏 | |||
| */ | |||
| function getDropDownAction(record){ | |||
| return [ | |||
| { | |||
| label: '详情', | |||
| onClick: handleDetail.bind(null, record), | |||
| }, { | |||
| label: '删除', | |||
| popConfirm: { | |||
| title: '是否确认删除', | |||
| confirm: handleDelete.bind(null, record), | |||
| } | |||
| } | |||
| ] | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| </style> | |||
| @ -0,0 +1,58 @@ | |||
| <template> | |||
| <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |||
| <BasicForm @register="registerForm"/> | |||
| </BasicModal> | |||
| </template> | |||
| <script lang="ts" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicModal, useModalInner} from '/@/components/Modal'; | |||
| import {BasicForm, useForm} from '/@/components/Form/index'; | |||
| import {formSchema} from '../webBanner.data'; | |||
| import {saveOrUpdate} from '../webBanner.api'; | |||
| // Emits声明 | |||
| const emit = defineEmits(['register','success']); | |||
| const isUpdate = ref(true); | |||
| //表单配置 | |||
| const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |||
| labelWidth: 150, | |||
| schemas: formSchema, | |||
| showActionButtonGroup: false, | |||
| }); | |||
| //表单赋值 | |||
| const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |||
| //重置表单 | |||
| await resetFields(); | |||
| setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |||
| isUpdate.value = !!data?.isUpdate; | |||
| if (unref(isUpdate)) { | |||
| //表单赋值 | |||
| await setFieldsValue({ | |||
| ...data.record, | |||
| }); | |||
| } | |||
| // 隐藏底部时禁用整个表单 | |||
| setProps({ disabled: !data?.showFooter }) | |||
| }); | |||
| //设置标题 | |||
| const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |||
| //表单提交事件 | |||
| async function handleSubmit(v) { | |||
| try { | |||
| let values = await validate(); | |||
| setModalProps({confirmLoading: true}); | |||
| //提交表单 | |||
| await saveOrUpdate(values, isUpdate.value); | |||
| //关闭弹窗 | |||
| closeModal(); | |||
| //刷新列表 | |||
| emit('success'); | |||
| } finally { | |||
| setModalProps({confirmLoading: false}); | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| </style> | |||
| @ -1,18 +0,0 @@ | |||
| package org.jeecg.modules.service; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.modules.bean.LoginReq; | |||
| public interface ApiLoginService { | |||
| /** | |||
| * 公众号授权登录 | |||
| * @param loginReq | |||
| * @return | |||
| */ | |||
| Result<?> officialLogin(LoginReq loginReq); | |||
| } | |||
| @ -1,163 +0,0 @@ | |||
| package org.jeecg.modules.service.impl; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.xkcoding.http.config.HttpConfig; | |||
| import lombok.Value; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.commons.lang.StringUtils; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.common.constant.CommonConstant; | |||
| import org.jeecg.common.exception.JeecgBootException; | |||
| import org.jeecg.common.system.util.JwtUtil; | |||
| import org.jeecg.common.util.PasswordUtil; | |||
| import org.jeecg.common.util.RedisUtil; | |||
| import org.jeecg.modules.bean.ConvertUtils; | |||
| import org.jeecg.modules.bean.HttpConf; | |||
| import org.jeecg.modules.bean.LoginReq; | |||
| import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; | |||
| import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService; | |||
| import org.jeecg.modules.service.ApiLoginService; | |||
| import org.springframework.stereotype.Service; | |||
| import javax.annotation.Resource; | |||
| import javax.transaction.Transactional; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.math.BigDecimal; | |||
| import java.util.Date; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| @Slf4j | |||
| @Service | |||
| public class ApiLoginServiceImpl implements ApiLoginService { | |||
| //公共用户表 | |||
| @Resource | |||
| private IHanHaiMemberService hanHaiMemberService; | |||
| //公共缓存类 | |||
| @Resource | |||
| private RedisUtil redisUtil; | |||
| @Resource | |||
| private HttpConf httpConf; | |||
| /** | |||
| * 微信公众号-appid | |||
| */ | |||
| private String mpAppId = "wx15be4225a7e41a1e"; | |||
| /** | |||
| * 微信公众号-appSecret | |||
| */ | |||
| private String mpAppSecret = "0fdb77429ffdf206c151af76a663041c"; | |||
| /** | |||
| * 公众号授权登录注册 | |||
| * @param loginReq | |||
| * @return | |||
| */ | |||
| @Override | |||
| @Transactional | |||
| public Result<?> officialLogin(LoginReq loginReq){ | |||
| Map<Object, Object> loginMap = new HashMap<>(); | |||
| if (StringUtils.isBlank(loginReq.getCode())) { | |||
| throw new JeecgBootException("code为空"); | |||
| } | |||
| String loginUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +mpAppId + "&secret=" + mpAppSecret + "&code=" + loginReq.getCode() + "&grant_type=authorization_code"; | |||
| //使用工具类 | |||
| JSONObject json_test = httpConf.getJSONObject(loginUrl); | |||
| log.info("{} {} -- {}", mpAppId, mpAppSecret, json_test); | |||
| String wxOpenid = json_test.getString("openid"); | |||
| String wxUnionId = json_test.getString("unionid"); | |||
| String access_token = json_test.getString("access_token"); | |||
| if (StringUtils.isBlank(wxOpenid)) { | |||
| throw new JeecgBootException("未获取到openid"); | |||
| } | |||
| HanHaiMember member = hanHaiMemberService.lambdaQuery().eq(HanHaiMember::getOfficialOpenid,wxOpenid).one(); | |||
| if(member!=null){ | |||
| // if (StringUtils.isBlank(member.getVid())){ | |||
| // member.setVid(loginReq.getVid()); | |||
| // member.setVtime(new Date()); | |||
| // hanHaiMemberService.updateById(member); | |||
| // } | |||
| //开始获取用户信息 | |||
| String memberUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+wxOpenid+"&lang=zh_CN"; | |||
| //使用工具类 | |||
| JSONObject json_member = httpConf.getJSONObject(memberUrl); | |||
| String nickname = json_member.getString("nickname"); | |||
| String headimgurl = json_member.getString("headimgurl"); | |||
| try { | |||
| nickname = new String(nickname.getBytes("ISO-8859-1"),"UTF-8"); | |||
| } catch (UnsupportedEncodingException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| member.setNickName(nickname); | |||
| member.setHeadImage(headimgurl); | |||
| member.setWxUnionid(wxUnionId); | |||
| String token = JwtUtil.sign(member.getAccount(), member.getAccount()); | |||
| member.setToken(token); | |||
| member.setUpdateTime(new Date()); | |||
| hanHaiMemberService.updateById(member); | |||
| // 生成token返回 | |||
| redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); | |||
| // 设置超时时间 | |||
| redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100); | |||
| loginMap.put("token",token); | |||
| loginMap.put("userInfo",member); | |||
| return Result.OK("登录成功",loginMap); | |||
| } | |||
| //开始获取用户信息 | |||
| String memberUrl = "https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+wxOpenid+"&lang=zh_CN"; | |||
| //使用工具类 | |||
| JSONObject json_member = httpConf.getJSONObject(memberUrl); | |||
| String nickname = json_member.getString("nickname"); | |||
| String headimgurl = json_member.getString("headimgurl"); | |||
| try { | |||
| nickname = new String(nickname.getBytes("ISO-8859-1"),"UTF-8"); | |||
| } catch (UnsupportedEncodingException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| HanHaiMember save = new HanHaiMember(); | |||
| save.setAccount(wxOpenid); | |||
| save.setVid(loginReq.getVid()); | |||
| save.setVtime(new Date()); | |||
| save.setNickName(nickname); | |||
| save.setHeadImage(headimgurl); | |||
| save.setWxUnionid(wxUnionId); | |||
| //销售邀请者标识 | |||
| save.setShareId(loginReq.getShareId()); | |||
| save.setOfficialOpenid(wxOpenid); | |||
| save.setCreateTime(new Date()); | |||
| //密码加密 | |||
| String salt = ConvertUtils.randomGen(8); | |||
| String encrypt = PasswordUtil.encrypt(wxOpenid,"123456" , salt); | |||
| save.setPassword(encrypt); | |||
| save.setPasswordSalt(salt); | |||
| save.setDeleteFlag("N"); | |||
| save.setRole("0"); | |||
| // 生成token返回 | |||
| String token = JwtUtil.sign(wxOpenid, wxOpenid); | |||
| save.setToken(token); | |||
| hanHaiMemberService.save(save); | |||
| redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); | |||
| // 设置超时时间 | |||
| redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100); | |||
| loginMap.put("token",token); | |||
| loginMap.put("userInfo",save); | |||
| return Result.OK("登录成功",loginMap); | |||
| } | |||
| } | |||
| @ -0,0 +1,157 @@ | |||
| package org.jeecg.modules.tbConf.controller; | |||
| import java.util.Arrays; | |||
| 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.modules.tbConf.entity.TbConf; | |||
| import org.jeecg.modules.tbConf.service.ITbConfService; | |||
| 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.jeecg.common.system.base.controller.JeecgController; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.servlet.ModelAndView; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.jeecg.common.aspect.annotation.AutoLog; | |||
| /** | |||
| * @Description: tb_conf | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Api(tags="tb_conf") | |||
| @RestController | |||
| @RequestMapping("/tbConf/tbConf") | |||
| @Slf4j | |||
| public class TbConfController extends JeecgController<TbConf, ITbConfService> { | |||
| @Autowired | |||
| private ITbConfService tbConfService; | |||
| /** | |||
| * 分页列表查询 | |||
| * | |||
| * @param tbConf | |||
| * @param pageNo | |||
| * @param pageSize | |||
| * @param req | |||
| * @return | |||
| */ | |||
| //@AutoLog(value = "tb_conf-分页列表查询") | |||
| @ApiOperation(value="tb_conf-分页列表查询", notes="tb_conf-分页列表查询") | |||
| @GetMapping(value = "/list") | |||
| public Result<IPage<TbConf>> queryPageList(TbConf tbConf, | |||
| @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, | |||
| @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, | |||
| HttpServletRequest req) { | |||
| QueryWrapper<TbConf> queryWrapper = QueryGenerator.initQueryWrapper(tbConf, req.getParameterMap()); | |||
| Page<TbConf> page = new Page<TbConf>(pageNo, pageSize); | |||
| queryWrapper.eq("dict_group","sys_word"); | |||
| IPage<TbConf> pageList = tbConfService.page(page, queryWrapper); | |||
| return Result.OK(pageList); | |||
| } | |||
| /** | |||
| * 添加 | |||
| * | |||
| * @param tbConf | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "tb_conf-添加") | |||
| @ApiOperation(value="tb_conf-添加", notes="tb_conf-添加") | |||
| @PostMapping(value = "/add") | |||
| public Result<String> add(@RequestBody TbConf tbConf) { | |||
| tbConfService.save(tbConf); | |||
| return Result.OK("添加成功!"); | |||
| } | |||
| /** | |||
| * 编辑 | |||
| * | |||
| * @param tbConf | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "tb_conf-编辑") | |||
| @ApiOperation(value="tb_conf-编辑", notes="tb_conf-编辑") | |||
| @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |||
| public Result<String> edit(@RequestBody TbConf tbConf) { | |||
| tbConfService.updateById(tbConf); | |||
| return Result.OK("编辑成功!"); | |||
| } | |||
| /** | |||
| * 通过id删除 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "tb_conf-通过id删除") | |||
| @ApiOperation(value="tb_conf-通过id删除", notes="tb_conf-通过id删除") | |||
| @DeleteMapping(value = "/delete") | |||
| public Result<String> delete(@RequestParam(name="id",required=true) String id) { | |||
| tbConfService.removeById(id); | |||
| return Result.OK("删除成功!"); | |||
| } | |||
| /** | |||
| * 批量删除 | |||
| * | |||
| * @param ids | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "tb_conf-批量删除") | |||
| @ApiOperation(value="tb_conf-批量删除", notes="tb_conf-批量删除") | |||
| @DeleteMapping(value = "/deleteBatch") | |||
| public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | |||
| this.tbConfService.removeByIds(Arrays.asList(ids.split(","))); | |||
| return Result.OK("批量删除成功!"); | |||
| } | |||
| /** | |||
| * 通过id查询 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| //@AutoLog(value = "tb_conf-通过id查询") | |||
| @ApiOperation(value="tb_conf-通过id查询", notes="tb_conf-通过id查询") | |||
| @GetMapping(value = "/queryById") | |||
| public Result<TbConf> queryById(@RequestParam(name="id",required=true) String id) { | |||
| TbConf tbConf = tbConfService.getById(id); | |||
| if(tbConf==null) { | |||
| return Result.error("未找到对应数据"); | |||
| } | |||
| return Result.OK(tbConf); | |||
| } | |||
| /** | |||
| * 导出excel | |||
| * | |||
| * @param request | |||
| * @param tbConf | |||
| */ | |||
| @RequestMapping(value = "/exportXls") | |||
| public ModelAndView exportXls(HttpServletRequest request, TbConf tbConf) { | |||
| return super.exportXls(request, tbConf, TbConf.class, "tb_conf"); | |||
| } | |||
| /** | |||
| * 通过excel导入数据 | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| @RequestMapping(value = "/importExcel", method = RequestMethod.POST) | |||
| public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) { | |||
| return super.importExcel(request, response, TbConf.class); | |||
| } | |||
| } | |||
| @ -0,0 +1,77 @@ | |||
| package org.jeecg.modules.tbConf.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: tb_conf | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Data | |||
| @TableName("tb_conf") | |||
| @Accessors(chain = true) | |||
| @EqualsAndHashCode(callSuper = false) | |||
| @ApiModel(value="tb_conf对象", description="tb_conf") | |||
| public class TbConf implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /**id*/ | |||
| @TableId(type = IdType.ASSIGN_ID) | |||
| @ApiModelProperty(value = "id") | |||
| private Integer id; | |||
| /**key*/ | |||
| @Excel(name = "key", width = 15) | |||
| @ApiModelProperty(value = "key") | |||
| private String name; | |||
| /**配置值*/ | |||
| @Excel(name = "配置值", width = 15) | |||
| @ApiModelProperty(value = "配置值") | |||
| private String value; | |||
| /**配置项*/ | |||
| @Excel(name = "配置项", width = 15) | |||
| @ApiModelProperty(value = "配置项") | |||
| private String info; | |||
| /**分组*/ | |||
| @Excel(name = "分组", width = 15) | |||
| @ApiModelProperty(value = "分组") | |||
| private String dictGroup; | |||
| /**分组说明*/ | |||
| @Excel(name = "分组说明", width = 15) | |||
| @ApiModelProperty(value = "分组说明") | |||
| private String dictGroupInfo; | |||
| /**创建时间*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "创建时间") | |||
| private Date createTime; | |||
| /**修改时间*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "修改时间") | |||
| private Date updateTime; | |||
| /**更新人*/ | |||
| @ApiModelProperty(value = "更新人") | |||
| private String updateBy; | |||
| /**创建人*/ | |||
| @ApiModelProperty(value = "创建人") | |||
| private String createBy; | |||
| /**所属部门*/ | |||
| @ApiModelProperty(value = "所属部门") | |||
| private String sysOrgCode; | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.tbConf.mapper; | |||
| import org.jeecg.modules.tbConf.entity.TbConf; | |||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||
| /** | |||
| * @Description: tb_conf | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface TbConfMapper extends BaseMapper<TbConf> { | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
| <mapper namespace="org.jeecg.modules.tbConf.mapper.TbConfMapper"> | |||
| </mapper> | |||
| @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.tbConf.service; | |||
| import org.jeecg.modules.tbConf.entity.TbConf; | |||
| import com.baomidou.mybatisplus.extension.service.IService; | |||
| /** | |||
| * @Description: tb_conf | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface ITbConfService extends IService<TbConf> { | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| package org.jeecg.modules.tbConf.service.impl; | |||
| import org.jeecg.modules.tbConf.entity.TbConf; | |||
| import org.jeecg.modules.tbConf.mapper.TbConfMapper; | |||
| import org.jeecg.modules.tbConf.service.ITbConfService; | |||
| import org.springframework.stereotype.Service; | |||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||
| /** | |||
| * @Description: tb_conf | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-28 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Service | |||
| public class TbConfServiceImpl extends ServiceImpl<TbConfMapper, TbConf> implements ITbConfService { | |||
| } | |||
| @ -0,0 +1,177 @@ | |||
| <template> | |||
| <a-card :bordered="false"> | |||
| <!-- 查询区域 --> | |||
| <div class="table-page-search-wrapper"> | |||
| <a-form layout="inline" @keyup.enter.native="searchQuery"> | |||
| <a-row :gutter="24"> | |||
| </a-row> | |||
| </a-form> | |||
| </div> | |||
| <!-- 查询区域-END --> | |||
| <!-- 操作按钮区域 --> | |||
| <div class="table-operator"> | |||
| <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button> | |||
| <a-button type="primary" icon="download" @click="handleExportXls('tb_conf')">导出</a-button> | |||
| <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel"> | |||
| <a-button type="primary" icon="import">导入</a-button> | |||
| </a-upload> | |||
| <!-- 高级查询区域 --> | |||
| <j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query> | |||
| <a-dropdown v-if="selectedRowKeys.length > 0"> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item> | |||
| </a-menu> | |||
| <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button> | |||
| </a-dropdown> | |||
| </div> | |||
| <!-- table区域-begin --> | |||
| <div> | |||
| <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;"> | |||
| <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项 | |||
| <a style="margin-left: 24px" @click="onClearSelected">清空</a> | |||
| </div> | |||
| <a-table | |||
| ref="table" | |||
| size="middle" | |||
| :scroll="{x:true}" | |||
| bordered | |||
| rowKey="id" | |||
| :columns="columns" | |||
| :dataSource="dataSource" | |||
| :pagination="ipagination" | |||
| :loading="loading" | |||
| :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" | |||
| class="j-table-force-nowrap" | |||
| @change="handleTableChange"> | |||
| <template slot="htmlSlot" slot-scope="text"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template slot="imgSlot" slot-scope="text,record"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span> | |||
| <img v-else :src="getImgView(text)" :preview="record.id" height="25px" alt="" style="max-width:80px;font-size: 12px;font-style: italic;"/> | |||
| </template> | |||
| <template slot="fileSlot" slot-scope="text"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button | |||
| v-else | |||
| :ghost="true" | |||
| type="primary" | |||
| icon="download" | |||
| size="small" | |||
| @click="downloadFile(text)"> | |||
| 下载 | |||
| </a-button> | |||
| </template> | |||
| <span slot="action" slot-scope="text, record"> | |||
| <a @click="handleEdit(record)">编辑</a> | |||
| <a-divider type="vertical" /> | |||
| <a-dropdown> | |||
| <a class="ant-dropdown-link">更多 <a-icon type="down" /></a> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item> | |||
| <a @click="handleDetail(record)">详情</a> | |||
| </a-menu-item> | |||
| <a-menu-item> | |||
| <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)"> | |||
| <a>删除</a> | |||
| </a-popconfirm> | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </a-dropdown> | |||
| </span> | |||
| </a-table> | |||
| </div> | |||
| <tb-conf-modal ref="modalForm" @ok="modalFormOk"></tb-conf-modal> | |||
| </a-card> | |||
| </template> | |||
| <script> | |||
| import '@/assets/less/TableExpand.less' | |||
| import { mixinDevice } from '@/utils/mixin' | |||
| import { JeecgListMixin } from '@/mixins/JeecgListMixin' | |||
| import TbConfModal from './modules/TbConfModal' | |||
| export default { | |||
| name: 'TbConfList', | |||
| mixins:[JeecgListMixin, mixinDevice], | |||
| components: { | |||
| TbConfModal | |||
| }, | |||
| data () { | |||
| return { | |||
| description: 'tb_conf管理页面', | |||
| // 表头 | |||
| columns: [ | |||
| { | |||
| title: '#', | |||
| dataIndex: '', | |||
| key:'rowIndex', | |||
| width:60, | |||
| align:"center", | |||
| customRender:function (t,r,index) { | |||
| return parseInt(index)+1; | |||
| } | |||
| }, | |||
| { | |||
| title:'配置值', | |||
| align:"center", | |||
| dataIndex: 'value' | |||
| }, | |||
| { | |||
| title:'配置项', | |||
| align:"center", | |||
| dataIndex: 'info' | |||
| }, | |||
| { | |||
| title: '操作', | |||
| dataIndex: 'action', | |||
| align:"center", | |||
| fixed:"right", | |||
| width:147, | |||
| scopedSlots: { customRender: 'action' } | |||
| } | |||
| ], | |||
| url: { | |||
| list: "/tbConf/tbConf/list", | |||
| delete: "/tbConf/tbConf/delete", | |||
| deleteBatch: "/tbConf/tbConf/deleteBatch", | |||
| exportXlsUrl: "/tbConf/tbConf/exportXls", | |||
| importExcelUrl: "tbConf/tbConf/importExcel", | |||
| }, | |||
| dictOptions:{}, | |||
| superFieldList:[], | |||
| } | |||
| }, | |||
| created() { | |||
| this.getSuperFieldList(); | |||
| }, | |||
| computed: { | |||
| importExcelUrl: function(){ | |||
| return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`; | |||
| }, | |||
| }, | |||
| methods: { | |||
| initDictConfig(){ | |||
| }, | |||
| getSuperFieldList(){ | |||
| let fieldList=[]; | |||
| fieldList.push({type:'Text',value:'value',text:'配置值',dictCode:''}) | |||
| fieldList.push({type:'string',value:'info',text:'配置项',dictCode:''}) | |||
| this.superFieldList = fieldList | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| @import '~@assets/less/common.less'; | |||
| </style> | |||
| @ -0,0 +1,109 @@ | |||
| <template> | |||
| <a-spin :spinning="confirmLoading"> | |||
| <j-form-container :disabled="formDisabled"> | |||
| <a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail"> | |||
| <a-row> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="配置值" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="value"> | |||
| <a-input v-model="model.value" placeholder="请输入配置值" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="配置项" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="info"> | |||
| <a-input v-model="model.info" placeholder="请输入配置项" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| </a-row> | |||
| </a-form-model> | |||
| </j-form-container> | |||
| </a-spin> | |||
| </template> | |||
| <script> | |||
| import { httpAction, getAction } from '@/api/manage' | |||
| import { validateDuplicateValue } from '@/utils/util' | |||
| export default { | |||
| name: 'TbConfForm', | |||
| components: { | |||
| }, | |||
| props: { | |||
| //表单禁用 | |||
| disabled: { | |||
| type: Boolean, | |||
| default: false, | |||
| required: false | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| model:{ | |||
| }, | |||
| labelCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 5 }, | |||
| }, | |||
| wrapperCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 16 }, | |||
| }, | |||
| confirmLoading: false, | |||
| validatorRules: { | |||
| }, | |||
| url: { | |||
| add: "/tbConf/tbConf/add", | |||
| edit: "/tbConf/tbConf/edit", | |||
| queryById: "/tbConf/tbConf/queryById" | |||
| } | |||
| } | |||
| }, | |||
| computed: { | |||
| formDisabled(){ | |||
| return this.disabled | |||
| }, | |||
| }, | |||
| created () { | |||
| //备份model原始值 | |||
| this.modelDefault = JSON.parse(JSON.stringify(this.model)); | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.edit(this.modelDefault); | |||
| }, | |||
| edit (record) { | |||
| this.model = Object.assign({}, record); | |||
| this.visible = true; | |||
| }, | |||
| submitForm () { | |||
| const that = this; | |||
| // 触发表单验证 | |||
| this.$refs.form.validate(valid => { | |||
| if (valid) { | |||
| that.confirmLoading = true; | |||
| let httpurl = ''; | |||
| let method = ''; | |||
| if(!this.model.id){ | |||
| httpurl+=this.url.add; | |||
| method = 'post'; | |||
| }else{ | |||
| httpurl+=this.url.edit; | |||
| method = 'put'; | |||
| } | |||
| httpAction(httpurl,this.model,method).then((res)=>{ | |||
| if(res.success){ | |||
| that.$message.success(res.message); | |||
| that.$emit('ok'); | |||
| }else{ | |||
| that.$message.warning(res.message); | |||
| } | |||
| }).finally(() => { | |||
| that.confirmLoading = false; | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,84 @@ | |||
| <template> | |||
| <a-drawer | |||
| :title="title" | |||
| :width="width" | |||
| placement="right" | |||
| :closable="false" | |||
| @close="close" | |||
| destroyOnClose | |||
| :visible="visible"> | |||
| <tb-conf-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit" normal></tb-conf-form> | |||
| <div class="drawer-footer"> | |||
| <a-button @click="handleCancel" style="margin-bottom: 0;">关闭</a-button> | |||
| <a-button v-if="!disableSubmit" @click="handleOk" type="primary" style="margin-bottom: 0;">提交</a-button> | |||
| </div> | |||
| </a-drawer> | |||
| </template> | |||
| <script> | |||
| import TbConfForm from './TbConfForm' | |||
| export default { | |||
| name: 'TbConfModal', | |||
| components: { | |||
| TbConfForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:"操作", | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }); | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| /** Button按钮间距 */ | |||
| .ant-btn { | |||
| margin-left: 30px; | |||
| margin-bottom: 30px; | |||
| float: right; | |||
| } | |||
| .drawer-footer{ | |||
| position: absolute; | |||
| bottom: -8px; | |||
| width: 100%; | |||
| border-top: 1px solid #e8e8e8; | |||
| padding: 10px 16px; | |||
| text-align: right; | |||
| left: 0; | |||
| background: #fff; | |||
| border-radius: 0 0 2px 2px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,60 @@ | |||
| <template> | |||
| <j-modal | |||
| :title="title" | |||
| :width="width" | |||
| :visible="visible" | |||
| switchFullscreen | |||
| @ok="handleOk" | |||
| :okButtonProps="{ class:{'jee-hidden': disableSubmit} }" | |||
| @cancel="handleCancel" | |||
| cancelText="关闭"> | |||
| <tb-conf-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></tb-conf-form> | |||
| </j-modal> | |||
| </template> | |||
| <script> | |||
| import TbConfForm from './TbConfForm' | |||
| export default { | |||
| name: 'TbConfModal', | |||
| components: { | |||
| TbConfForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:'', | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }) | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,61 @@ | |||
| import {defHttp} from '/@/utils/http/axios'; | |||
| import {Modal} from 'ant-design-vue'; | |||
| enum Api { | |||
| list = '/tbConf/tbConf/list', | |||
| save='/tbConf/tbConf/add', | |||
| edit='/tbConf/tbConf/edit', | |||
| deleteOne = '/tbConf/tbConf/delete', | |||
| deleteBatch = '/tbConf/tbConf/deleteBatch', | |||
| importExcel = '/tbConf/tbConf/importExcel', | |||
| exportXls = '/tbConf/tbConf/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}); | |||
| } | |||
| @ -0,0 +1,33 @@ | |||
| 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: 'value' | |||
| }, | |||
| { | |||
| title: '配置项', | |||
| align:"center", | |||
| dataIndex: 'info' | |||
| }, | |||
| ]; | |||
| //查询数据 | |||
| export const searchFormSchema: FormSchema[] = [ | |||
| ]; | |||
| //表单数据 | |||
| export const formSchema: FormSchema[] = [ | |||
| { | |||
| label: '配置值', | |||
| field: 'value', | |||
| component: 'Input', | |||
| }, | |||
| { | |||
| label: '配置项', | |||
| field: 'info', | |||
| component: 'Input', | |||
| }, | |||
| ]; | |||
| @ -0,0 +1,162 @@ | |||
| <template> | |||
| <div> | |||
| <!--引用表格--> | |||
| <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |||
| <!--插槽:table标题--> | |||
| <template #tableTitle> | |||
| <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |||
| <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |||
| <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |||
| <a-dropdown v-if="checkedKeys.length > 0"> | |||
| <template #overlay> | |||
| <a-menu> | |||
| <a-menu-item key="1" @click="batchHandleDelete"> | |||
| <Icon icon="ant-design:delete-outlined"></Icon> | |||
| 删除 | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </template> | |||
| <a-button>批量操作 | |||
| <Icon icon="mdi:chevron-down"></Icon> | |||
| </a-button> | |||
| </a-dropdown> | |||
| </template> | |||
| <!--操作栏--> | |||
| <template #action="{ record }"> | |||
| <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |||
| </template> | |||
| <!--字段回显插槽--> | |||
| <template #htmlSlot="{text}"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template #fileSlot="{text}"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |||
| </template> | |||
| </BasicTable> | |||
| <!-- 表单区域 --> | |||
| <TbConfModal @register="registerModal" @success="handleSuccess"></TbConfModal> | |||
| </div> | |||
| </template> | |||
| <script lang="ts" name="tbConf-tbConf" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |||
| import {useModal} from '/@/components/Modal'; | |||
| import { useListPage } from '/@/hooks/system/useListPage' | |||
| import TbConfModal from './components/TbConfModal.vue' | |||
| import {columns, searchFormSchema} from './tbConf.data'; | |||
| import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './tbConf.api'; | |||
| const checkedKeys = ref<Array<string | number>>([]); | |||
| //注册model | |||
| const [registerModal, {openModal}] = useModal(); | |||
| //注册table数据 | |||
| const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |||
| tableProps:{ | |||
| title: 'tb_conf', | |||
| api: list, | |||
| columns, | |||
| canResize:false, | |||
| formConfig: { | |||
| labelWidth: 120, | |||
| schemas: searchFormSchema, | |||
| autoSubmitOnEnter:true, | |||
| showAdvancedButton:true, | |||
| fieldMapToTime: [ | |||
| ], | |||
| }, | |||
| actionColumn: { | |||
| width: 120, | |||
| }, | |||
| }, | |||
| exportConfig: { | |||
| name:"tb_conf", | |||
| url: getExportUrl, | |||
| }, | |||
| importConfig: { | |||
| url: getImportUrl | |||
| }, | |||
| }) | |||
| const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |||
| /** | |||
| * 新增事件 | |||
| */ | |||
| function handleAdd() { | |||
| openModal(true, { | |||
| isUpdate: false, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 编辑事件 | |||
| */ | |||
| function handleEdit(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 详情 | |||
| */ | |||
| function handleDetail(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: false, | |||
| }); | |||
| } | |||
| /** | |||
| * 删除事件 | |||
| */ | |||
| async function handleDelete(record) { | |||
| await deleteOne({id: record.id}, reload); | |||
| } | |||
| /** | |||
| * 批量删除事件 | |||
| */ | |||
| async function batchHandleDelete() { | |||
| await batchDelete({ids: checkedKeys.value}, reload); | |||
| } | |||
| /** | |||
| * 成功回调 | |||
| */ | |||
| function handleSuccess() { | |||
| reload(); | |||
| } | |||
| /** | |||
| * 操作栏 | |||
| */ | |||
| function getTableAction(record){ | |||
| return [ | |||
| { | |||
| label: '编辑', | |||
| onClick: handleEdit.bind(null, record), | |||
| } | |||
| ] | |||
| } | |||
| /** | |||
| * 下拉操作栏 | |||
| */ | |||
| function getDropDownAction(record){ | |||
| return [ | |||
| { | |||
| label: '详情', | |||
| onClick: handleDetail.bind(null, record), | |||
| }, { | |||
| label: '删除', | |||
| popConfirm: { | |||
| title: '是否确认删除', | |||
| confirm: handleDelete.bind(null, record), | |||
| } | |||
| } | |||
| ] | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| </style> | |||
| @ -0,0 +1,58 @@ | |||
| <template> | |||
| <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |||
| <BasicForm @register="registerForm"/> | |||
| </BasicModal> | |||
| </template> | |||
| <script lang="ts" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicModal, useModalInner} from '/@/components/Modal'; | |||
| import {BasicForm, useForm} from '/@/components/Form/index'; | |||
| import {formSchema} from '../tbConf.data'; | |||
| import {saveOrUpdate} from '../tbConf.api'; | |||
| // Emits声明 | |||
| const emit = defineEmits(['register','success']); | |||
| const isUpdate = ref(true); | |||
| //表单配置 | |||
| const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |||
| labelWidth: 150, | |||
| schemas: formSchema, | |||
| showActionButtonGroup: false, | |||
| }); | |||
| //表单赋值 | |||
| const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |||
| //重置表单 | |||
| await resetFields(); | |||
| setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |||
| isUpdate.value = !!data?.isUpdate; | |||
| if (unref(isUpdate)) { | |||
| //表单赋值 | |||
| await setFieldsValue({ | |||
| ...data.record, | |||
| }); | |||
| } | |||
| // 隐藏底部时禁用整个表单 | |||
| setProps({ disabled: !data?.showFooter }) | |||
| }); | |||
| //设置标题 | |||
| const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |||
| //表单提交事件 | |||
| async function handleSubmit(v) { | |||
| try { | |||
| let values = await validate(); | |||
| setModalProps({confirmLoading: true}); | |||
| //提交表单 | |||
| await saveOrUpdate(values, isUpdate.value); | |||
| //关闭弹窗 | |||
| closeModal(); | |||
| //刷新列表 | |||
| emit('success'); | |||
| } finally { | |||
| setModalProps({confirmLoading: false}); | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| </style> | |||
| @ -0,0 +1,156 @@ | |||
| package org.jeecg.modules.tbSuggest.controller; | |||
| import java.util.Arrays; | |||
| 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.modules.tbSuggest.entity.TbSuggest; | |||
| import org.jeecg.modules.tbSuggest.service.ITbSuggestService; | |||
| 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.jeecg.common.system.base.controller.JeecgController; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.servlet.ModelAndView; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.jeecg.common.aspect.annotation.AutoLog; | |||
| /** | |||
| * @Description: 帮助与反馈 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Api(tags="帮助与反馈") | |||
| @RestController | |||
| @RequestMapping("/tbSuggest/tbSuggest") | |||
| @Slf4j | |||
| public class TbSuggestController extends JeecgController<TbSuggest, ITbSuggestService> { | |||
| @Autowired | |||
| private ITbSuggestService tbSuggestService; | |||
| /** | |||
| * 分页列表查询 | |||
| * | |||
| * @param tbSuggest | |||
| * @param pageNo | |||
| * @param pageSize | |||
| * @param req | |||
| * @return | |||
| */ | |||
| //@AutoLog(value = "帮助与反馈-分页列表查询") | |||
| @ApiOperation(value="帮助与反馈-分页列表查询", notes="帮助与反馈-分页列表查询") | |||
| @GetMapping(value = "/list") | |||
| public Result<IPage<TbSuggest>> queryPageList(TbSuggest tbSuggest, | |||
| @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, | |||
| @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, | |||
| HttpServletRequest req) { | |||
| QueryWrapper<TbSuggest> queryWrapper = QueryGenerator.initQueryWrapper(tbSuggest, req.getParameterMap()); | |||
| Page<TbSuggest> page = new Page<TbSuggest>(pageNo, pageSize); | |||
| IPage<TbSuggest> pageList = tbSuggestService.page(page, queryWrapper); | |||
| return Result.OK(pageList); | |||
| } | |||
| /** | |||
| * 添加 | |||
| * | |||
| * @param tbSuggest | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "帮助与反馈-添加") | |||
| @ApiOperation(value="帮助与反馈-添加", notes="帮助与反馈-添加") | |||
| @PostMapping(value = "/add") | |||
| public Result<String> add(@RequestBody TbSuggest tbSuggest) { | |||
| tbSuggestService.save(tbSuggest); | |||
| return Result.OK("添加成功!"); | |||
| } | |||
| /** | |||
| * 编辑 | |||
| * | |||
| * @param tbSuggest | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "帮助与反馈-编辑") | |||
| @ApiOperation(value="帮助与反馈-编辑", notes="帮助与反馈-编辑") | |||
| @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |||
| public Result<String> edit(@RequestBody TbSuggest tbSuggest) { | |||
| tbSuggestService.updateById(tbSuggest); | |||
| return Result.OK("编辑成功!"); | |||
| } | |||
| /** | |||
| * 通过id删除 | |||
| * | |||
| * @param id | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "帮助与反馈-通过id删除") | |||
| @ApiOperation(value="帮助与反馈-通过id删除", notes="帮助与反馈-通过id删除") | |||
| @DeleteMapping(value = "/delete") | |||
| public Result<String> delete(@RequestParam(name="id",required=true) String id) { | |||
| tbSuggestService.removeById(id); | |||
| return Result.OK("删除成功!"); | |||
| } | |||
| /** | |||
| * 批量删除 | |||
| * | |||
| * @param ids | |||
| * @return | |||
| */ | |||
| @AutoLog(value = "帮助与反馈-批量删除") | |||
| @ApiOperation(value="帮助与反馈-批量删除", notes="帮助与反馈-批量删除") | |||
| @DeleteMapping(value = "/deleteBatch") | |||
| public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | |||
| this.tbSuggestService.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<TbSuggest> queryById(@RequestParam(name="id",required=true) String id) { | |||
| TbSuggest tbSuggest = tbSuggestService.getById(id); | |||
| if(tbSuggest==null) { | |||
| return Result.error("未找到对应数据"); | |||
| } | |||
| return Result.OK(tbSuggest); | |||
| } | |||
| /** | |||
| * 导出excel | |||
| * | |||
| * @param request | |||
| * @param tbSuggest | |||
| */ | |||
| @RequestMapping(value = "/exportXls") | |||
| public ModelAndView exportXls(HttpServletRequest request, TbSuggest tbSuggest) { | |||
| return super.exportXls(request, tbSuggest, TbSuggest.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, TbSuggest.class); | |||
| } | |||
| } | |||
| @ -0,0 +1,101 @@ | |||
| package org.jeecg.modules.tbSuggest.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: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Data | |||
| @TableName("tb_suggest") | |||
| @Accessors(chain = true) | |||
| @EqualsAndHashCode(callSuper = false) | |||
| @ApiModel(value="tb_suggest对象", description="帮助与反馈") | |||
| public class TbSuggest implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /**主键编号*/ | |||
| @TableId(type = IdType.ASSIGN_ID) | |||
| @ApiModelProperty(value = "主键编号") | |||
| private String id; | |||
| /**用户id*/ | |||
| @Excel(name = "用户id", width = 15) | |||
| @ApiModelProperty(value = "用户id") | |||
| private String userId; | |||
| /**用户名*/ | |||
| @Excel(name = "用户名", width = 15) | |||
| @ApiModelProperty(value = "用户名") | |||
| private String userName; | |||
| /**用户手机号*/ | |||
| @Excel(name = "用户手机号", width = 15) | |||
| @ApiModelProperty(value = "用户手机号") | |||
| private String userPhone; | |||
| /**问题描述*/ | |||
| @Excel(name = "问题描述", width = 15) | |||
| @ApiModelProperty(value = "问题描述") | |||
| private String content; | |||
| /**问题截图*/ | |||
| @Excel(name = "问题截图", width = 15) | |||
| @ApiModelProperty(value = "问题截图") | |||
| private String proofImg; | |||
| /**提交时间*/ | |||
| @Excel(name = "提交时间", width = 15, format = "yyyy-MM-dd") | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "提交时间") | |||
| private Date submitTime; | |||
| /**是否回复(0:未回复 1:已回复)*/ | |||
| @Excel(name = "是否回复(0:未回复 1:已回复)", width = 15) | |||
| @ApiModelProperty(value = "是否回复(0:未回复 1:已回复)") | |||
| private Integer isReply; | |||
| /**回复结果*/ | |||
| @Excel(name = "回复结果", width = 15) | |||
| @ApiModelProperty(value = "回复结果") | |||
| private String replyMsg; | |||
| /**回复时间*/ | |||
| @Excel(name = "回复时间", width = 15, format = "yyyy-MM-dd") | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "回复时间") | |||
| private Date replyTime; | |||
| /**回复人*/ | |||
| @Excel(name = "回复人", width = 15) | |||
| @ApiModelProperty(value = "回复人") | |||
| private String replyId; | |||
| /**创建人*/ | |||
| @ApiModelProperty(value = "创建人") | |||
| private String createBy; | |||
| /**创建日期*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "创建日期") | |||
| private Date createTime; | |||
| /**更新人*/ | |||
| @ApiModelProperty(value = "更新人") | |||
| private String updateBy; | |||
| /**更新日期*/ | |||
| @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd") | |||
| @DateTimeFormat(pattern="yyyy-MM-dd") | |||
| @ApiModelProperty(value = "更新日期") | |||
| private Date updateTime; | |||
| /**所属部门*/ | |||
| @ApiModelProperty(value = "所属部门") | |||
| private String sysOrgCode; | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.tbSuggest.mapper; | |||
| import org.jeecg.modules.tbSuggest.entity.TbSuggest; | |||
| import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||
| /** | |||
| * @Description: 帮助与反馈 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface TbSuggestMapper extends BaseMapper<TbSuggest> { | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
| <mapper namespace="org.jeecg.modules.tbSuggest.mapper.TbSuggestMapper"> | |||
| </mapper> | |||
| @ -0,0 +1,16 @@ | |||
| package org.jeecg.modules.tbSuggest.service; | |||
| import org.jeecg.modules.tbSuggest.entity.TbSuggest; | |||
| import com.baomidou.mybatisplus.extension.service.IService; | |||
| import org.springframework.stereotype.Service; | |||
| /** | |||
| * @Description: 帮助与反馈 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| public interface ITbSuggestService extends IService<TbSuggest> { | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| package org.jeecg.modules.tbSuggest.service.impl; | |||
| import org.jeecg.modules.tbSuggest.entity.TbSuggest; | |||
| import org.jeecg.modules.tbSuggest.mapper.TbSuggestMapper; | |||
| import org.jeecg.modules.tbSuggest.service.ITbSuggestService; | |||
| import org.springframework.stereotype.Service; | |||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |||
| /** | |||
| * @Description: 帮助与反馈 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Service | |||
| public class TbSuggestServiceImpl extends ServiceImpl<TbSuggestMapper, TbSuggest> implements ITbSuggestService { | |||
| } | |||
| @ -0,0 +1,219 @@ | |||
| <template> | |||
| <a-card :bordered="false"> | |||
| <!-- 查询区域 --> | |||
| <div class="table-page-search-wrapper"> | |||
| <a-form layout="inline" @keyup.enter.native="searchQuery"> | |||
| <a-row :gutter="24"> | |||
| <a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
| <a-form-item label="用户名"> | |||
| <a-input placeholder="请输入用户名" v-model="queryParam.userName"></a-input> | |||
| </a-form-item> | |||
| </a-col> | |||
| <a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
| <a-form-item label="用户手机号"> | |||
| <a-input placeholder="请输入用户手机号" v-model="queryParam.userPhone"></a-input> | |||
| </a-form-item> | |||
| </a-col> | |||
| <a-col :xl="6" :lg="7" :md="8" :sm="24"> | |||
| <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons"> | |||
| <a-button type="primary" @click="searchQuery" icon="search">查询</a-button> | |||
| <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button> | |||
| <a @click="handleToggleSearch" style="margin-left: 8px"> | |||
| {{ toggleSearchStatus ? '收起' : '展开' }} | |||
| <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/> | |||
| </a> | |||
| </span> | |||
| </a-col> | |||
| </a-row> | |||
| </a-form> | |||
| </div> | |||
| <!-- 查询区域-END --> | |||
| <!-- 操作按钮区域 --> | |||
| <div class="table-operator"> | |||
| <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button> | |||
| <a-button type="primary" icon="download" @click="handleExportXls('帮助与反馈')">导出</a-button> | |||
| <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel"> | |||
| <a-button type="primary" icon="import">导入</a-button> | |||
| </a-upload> | |||
| <!-- 高级查询区域 --> | |||
| <j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query> | |||
| <a-dropdown v-if="selectedRowKeys.length > 0"> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item> | |||
| </a-menu> | |||
| <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button> | |||
| </a-dropdown> | |||
| </div> | |||
| <!-- table区域-begin --> | |||
| <div> | |||
| <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;"> | |||
| <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项 | |||
| <a style="margin-left: 24px" @click="onClearSelected">清空</a> | |||
| </div> | |||
| <a-table | |||
| ref="table" | |||
| size="middle" | |||
| :scroll="{x:true}" | |||
| bordered | |||
| rowKey="id" | |||
| :columns="columns" | |||
| :dataSource="dataSource" | |||
| :pagination="ipagination" | |||
| :loading="loading" | |||
| :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}" | |||
| class="j-table-force-nowrap" | |||
| @change="handleTableChange"> | |||
| <template slot="htmlSlot" slot-scope="text"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template slot="imgSlot" slot-scope="text,record"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span> | |||
| <img v-else :src="getImgView(text)" :preview="record.id" height="25px" alt="" style="max-width:80px;font-size: 12px;font-style: italic;"/> | |||
| </template> | |||
| <template slot="fileSlot" slot-scope="text"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button | |||
| v-else | |||
| :ghost="true" | |||
| type="primary" | |||
| icon="download" | |||
| size="small" | |||
| @click="downloadFile(text)"> | |||
| 下载 | |||
| </a-button> | |||
| </template> | |||
| <span slot="action" slot-scope="text, record"> | |||
| <a @click="handleEdit(record)">编辑</a> | |||
| <a-divider type="vertical" /> | |||
| <a-dropdown> | |||
| <a class="ant-dropdown-link">更多 <a-icon type="down" /></a> | |||
| <a-menu slot="overlay"> | |||
| <a-menu-item> | |||
| <a @click="handleDetail(record)">详情</a> | |||
| </a-menu-item> | |||
| <a-menu-item> | |||
| <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)"> | |||
| <a>删除</a> | |||
| </a-popconfirm> | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </a-dropdown> | |||
| </span> | |||
| </a-table> | |||
| </div> | |||
| <tb-suggest-modal ref="modalForm" @ok="modalFormOk"></tb-suggest-modal> | |||
| </a-card> | |||
| </template> | |||
| <script> | |||
| import '@/assets/less/TableExpand.less' | |||
| import { mixinDevice } from '@/utils/mixin' | |||
| import { JeecgListMixin } from '@/mixins/JeecgListMixin' | |||
| import TbSuggestModal from './modules/TbSuggestModal' | |||
| export default { | |||
| name: 'TbSuggestList', | |||
| mixins:[JeecgListMixin, mixinDevice], | |||
| components: { | |||
| TbSuggestModal | |||
| }, | |||
| data () { | |||
| return { | |||
| description: '帮助与反馈管理页面', | |||
| // 表头 | |||
| columns: [ | |||
| { | |||
| title: '#', | |||
| dataIndex: '', | |||
| key:'rowIndex', | |||
| width:60, | |||
| align:"center", | |||
| customRender:function (t,r,index) { | |||
| return parseInt(index)+1; | |||
| } | |||
| }, | |||
| { | |||
| title:'用户名', | |||
| align:"center", | |||
| dataIndex: 'userName' | |||
| }, | |||
| { | |||
| title:'用户手机号', | |||
| align:"center", | |||
| dataIndex: 'userPhone' | |||
| }, | |||
| { | |||
| title:'问题描述', | |||
| align:"center", | |||
| dataIndex: 'content' | |||
| }, | |||
| { | |||
| title:'问题截图', | |||
| align:"center", | |||
| dataIndex: 'proofImg', | |||
| scopedSlots: {customRender: 'imgSlot'} | |||
| }, | |||
| { | |||
| title:'提交时间', | |||
| align:"center", | |||
| dataIndex: 'submitTime', | |||
| customRender:function (text) { | |||
| return !text?"":(text.length>10?text.substr(0,10):text) | |||
| } | |||
| }, | |||
| { | |||
| title: '操作', | |||
| dataIndex: 'action', | |||
| align:"center", | |||
| fixed:"right", | |||
| width:147, | |||
| scopedSlots: { customRender: 'action' } | |||
| } | |||
| ], | |||
| url: { | |||
| list: "/tbSuggest/tbSuggest/list", | |||
| delete: "/tbSuggest/tbSuggest/delete", | |||
| deleteBatch: "/tbSuggest/tbSuggest/deleteBatch", | |||
| exportXlsUrl: "/tbSuggest/tbSuggest/exportXls", | |||
| importExcelUrl: "tbSuggest/tbSuggest/importExcel", | |||
| }, | |||
| dictOptions:{}, | |||
| superFieldList:[], | |||
| } | |||
| }, | |||
| created() { | |||
| this.getSuperFieldList(); | |||
| }, | |||
| computed: { | |||
| importExcelUrl: function(){ | |||
| return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`; | |||
| }, | |||
| }, | |||
| methods: { | |||
| initDictConfig(){ | |||
| }, | |||
| getSuperFieldList(){ | |||
| let fieldList=[]; | |||
| fieldList.push({type:'string',value:'userName',text:'用户名',dictCode:''}) | |||
| fieldList.push({type:'string',value:'userPhone',text:'用户手机号',dictCode:''}) | |||
| fieldList.push({type:'Text',value:'content',text:'问题描述',dictCode:''}) | |||
| fieldList.push({type:'Text',value:'proofImg',text:'问题截图',dictCode:''}) | |||
| fieldList.push({type:'date',value:'submitTime',text:'提交时间'}) | |||
| this.superFieldList = fieldList | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| @import '~@assets/less/common.less'; | |||
| </style> | |||
| @ -0,0 +1,124 @@ | |||
| <template> | |||
| <a-spin :spinning="confirmLoading"> | |||
| <j-form-container :disabled="formDisabled"> | |||
| <a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail"> | |||
| <a-row> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="用户名" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userName"> | |||
| <a-input v-model="model.userName" placeholder="请输入用户名" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="用户手机号" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="userPhone"> | |||
| <a-input v-model="model.userPhone" placeholder="请输入用户手机号" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="问题描述" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="content"> | |||
| <a-input v-model="model.content" placeholder="请输入问题描述" ></a-input> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="问题截图" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="proofImg"> | |||
| <j-image-upload isMultiple v-model="model.proofImg" ></j-image-upload> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| <a-col :span="24"> | |||
| <a-form-model-item label="提交时间" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="submitTime"> | |||
| <j-date placeholder="请选择提交时间" v-model="model.submitTime" style="width: 100%" /> | |||
| </a-form-model-item> | |||
| </a-col> | |||
| </a-row> | |||
| </a-form-model> | |||
| </j-form-container> | |||
| </a-spin> | |||
| </template> | |||
| <script> | |||
| import { httpAction, getAction } from '@/api/manage' | |||
| import { validateDuplicateValue } from '@/utils/util' | |||
| export default { | |||
| name: 'TbSuggestForm', | |||
| components: { | |||
| }, | |||
| props: { | |||
| //表单禁用 | |||
| disabled: { | |||
| type: Boolean, | |||
| default: false, | |||
| required: false | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| model:{ | |||
| }, | |||
| labelCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 5 }, | |||
| }, | |||
| wrapperCol: { | |||
| xs: { span: 24 }, | |||
| sm: { span: 16 }, | |||
| }, | |||
| confirmLoading: false, | |||
| validatorRules: { | |||
| }, | |||
| url: { | |||
| add: "/tbSuggest/tbSuggest/add", | |||
| edit: "/tbSuggest/tbSuggest/edit", | |||
| queryById: "/tbSuggest/tbSuggest/queryById" | |||
| } | |||
| } | |||
| }, | |||
| computed: { | |||
| formDisabled(){ | |||
| return this.disabled | |||
| }, | |||
| }, | |||
| created () { | |||
| //备份model原始值 | |||
| this.modelDefault = JSON.parse(JSON.stringify(this.model)); | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.edit(this.modelDefault); | |||
| }, | |||
| edit (record) { | |||
| this.model = Object.assign({}, record); | |||
| this.visible = true; | |||
| }, | |||
| submitForm () { | |||
| const that = this; | |||
| // 触发表单验证 | |||
| this.$refs.form.validate(valid => { | |||
| if (valid) { | |||
| that.confirmLoading = true; | |||
| let httpurl = ''; | |||
| let method = ''; | |||
| if(!this.model.id){ | |||
| httpurl+=this.url.add; | |||
| method = 'post'; | |||
| }else{ | |||
| httpurl+=this.url.edit; | |||
| method = 'put'; | |||
| } | |||
| httpAction(httpurl,this.model,method).then((res)=>{ | |||
| if(res.success){ | |||
| that.$message.success(res.message); | |||
| that.$emit('ok'); | |||
| }else{ | |||
| that.$message.warning(res.message); | |||
| } | |||
| }).finally(() => { | |||
| that.confirmLoading = false; | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,84 @@ | |||
| <template> | |||
| <a-drawer | |||
| :title="title" | |||
| :width="width" | |||
| placement="right" | |||
| :closable="false" | |||
| @close="close" | |||
| destroyOnClose | |||
| :visible="visible"> | |||
| <tb-suggest-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit" normal></tb-suggest-form> | |||
| <div class="drawer-footer"> | |||
| <a-button @click="handleCancel" style="margin-bottom: 0;">关闭</a-button> | |||
| <a-button v-if="!disableSubmit" @click="handleOk" type="primary" style="margin-bottom: 0;">提交</a-button> | |||
| </div> | |||
| </a-drawer> | |||
| </template> | |||
| <script> | |||
| import TbSuggestForm from './TbSuggestForm' | |||
| export default { | |||
| name: 'TbSuggestModal', | |||
| components: { | |||
| TbSuggestForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:"操作", | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }); | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| /** Button按钮间距 */ | |||
| .ant-btn { | |||
| margin-left: 30px; | |||
| margin-bottom: 30px; | |||
| float: right; | |||
| } | |||
| .drawer-footer{ | |||
| position: absolute; | |||
| bottom: -8px; | |||
| width: 100%; | |||
| border-top: 1px solid #e8e8e8; | |||
| padding: 10px 16px; | |||
| text-align: right; | |||
| left: 0; | |||
| background: #fff; | |||
| border-radius: 0 0 2px 2px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,60 @@ | |||
| <template> | |||
| <j-modal | |||
| :title="title" | |||
| :width="width" | |||
| :visible="visible" | |||
| switchFullscreen | |||
| @ok="handleOk" | |||
| :okButtonProps="{ class:{'jee-hidden': disableSubmit} }" | |||
| @cancel="handleCancel" | |||
| cancelText="关闭"> | |||
| <tb-suggest-form ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></tb-suggest-form> | |||
| </j-modal> | |||
| </template> | |||
| <script> | |||
| import TbSuggestForm from './TbSuggestForm' | |||
| export default { | |||
| name: 'TbSuggestModal', | |||
| components: { | |||
| TbSuggestForm | |||
| }, | |||
| data () { | |||
| return { | |||
| title:'', | |||
| width:800, | |||
| visible: false, | |||
| disableSubmit: false | |||
| } | |||
| }, | |||
| methods: { | |||
| add () { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.add(); | |||
| }) | |||
| }, | |||
| edit (record) { | |||
| this.visible=true | |||
| this.$nextTick(()=>{ | |||
| this.$refs.realForm.edit(record); | |||
| }) | |||
| }, | |||
| close () { | |||
| this.$emit('close'); | |||
| this.visible = false; | |||
| }, | |||
| handleOk () { | |||
| this.$refs.realForm.submitForm(); | |||
| }, | |||
| submitCallback(){ | |||
| this.$emit('ok'); | |||
| this.visible = false; | |||
| }, | |||
| handleCancel () { | |||
| this.close() | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,61 @@ | |||
| import {defHttp} from '/@/utils/http/axios'; | |||
| import {Modal} from 'ant-design-vue'; | |||
| enum Api { | |||
| list = '/tbSuggest/tbSuggest/list', | |||
| save='/tbSuggest/tbSuggest/add', | |||
| edit='/tbSuggest/tbSuggest/edit', | |||
| deleteOne = '/tbSuggest/tbSuggest/delete', | |||
| deleteBatch = '/tbSuggest/tbSuggest/deleteBatch', | |||
| importExcel = '/tbSuggest/tbSuggest/importExcel', | |||
| exportXls = '/tbSuggest/tbSuggest/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}); | |||
| } | |||
| @ -0,0 +1,81 @@ | |||
| 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: 'userName' | |||
| }, | |||
| { | |||
| title: '用户手机号', | |||
| align:"center", | |||
| dataIndex: 'userPhone' | |||
| }, | |||
| { | |||
| title: '问题描述', | |||
| align:"center", | |||
| dataIndex: 'content' | |||
| }, | |||
| { | |||
| title: '问题截图', | |||
| align:"center", | |||
| dataIndex: 'proofImg', | |||
| customRender:render.renderAvatar, | |||
| }, | |||
| { | |||
| title: '提交时间', | |||
| align:"center", | |||
| dataIndex: 'submitTime', | |||
| customRender:({text}) =>{ | |||
| return !text?"":(text.length>10?text.substr(0,10):text) | |||
| }, | |||
| }, | |||
| ]; | |||
| //查询数据 | |||
| export const searchFormSchema: FormSchema[] = [ | |||
| { | |||
| label: "用户名", | |||
| field: "userName", | |||
| component: 'Input', | |||
| colProps: {span: 6}, | |||
| }, | |||
| { | |||
| label: "用户手机号", | |||
| field: "userPhone", | |||
| component: 'Input', | |||
| colProps: {span: 6}, | |||
| }, | |||
| ]; | |||
| //表单数据 | |||
| export const formSchema: FormSchema[] = [ | |||
| { | |||
| label: '用户名', | |||
| field: 'userName', | |||
| component: 'Input', | |||
| }, | |||
| { | |||
| label: '用户手机号', | |||
| field: 'userPhone', | |||
| component: 'Input', | |||
| }, | |||
| { | |||
| label: '问题描述', | |||
| field: 'content', | |||
| component: 'Input', | |||
| }, | |||
| { | |||
| label: '问题截图', | |||
| field: 'proofImg', | |||
| component: 'JImageUpload', | |||
| componentProps:{ | |||
| }, | |||
| }, | |||
| { | |||
| label: '提交时间', | |||
| field: 'submitTime', | |||
| component: 'DatePicker', | |||
| }, | |||
| ]; | |||
| @ -0,0 +1,162 @@ | |||
| <template> | |||
| <div> | |||
| <!--引用表格--> | |||
| <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |||
| <!--插槽:table标题--> | |||
| <template #tableTitle> | |||
| <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |||
| <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |||
| <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |||
| <a-dropdown v-if="checkedKeys.length > 0"> | |||
| <template #overlay> | |||
| <a-menu> | |||
| <a-menu-item key="1" @click="batchHandleDelete"> | |||
| <Icon icon="ant-design:delete-outlined"></Icon> | |||
| 删除 | |||
| </a-menu-item> | |||
| </a-menu> | |||
| </template> | |||
| <a-button>批量操作 | |||
| <Icon icon="mdi:chevron-down"></Icon> | |||
| </a-button> | |||
| </a-dropdown> | |||
| </template> | |||
| <!--操作栏--> | |||
| <template #action="{ record }"> | |||
| <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |||
| </template> | |||
| <!--字段回显插槽--> | |||
| <template #htmlSlot="{text}"> | |||
| <div v-html="text"></div> | |||
| </template> | |||
| <template #fileSlot="{text}"> | |||
| <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |||
| <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |||
| </template> | |||
| </BasicTable> | |||
| <!-- 表单区域 --> | |||
| <TbSuggestModal @register="registerModal" @success="handleSuccess"></TbSuggestModal> | |||
| </div> | |||
| </template> | |||
| <script lang="ts" name="tbSuggest-tbSuggest" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |||
| import {useModal} from '/@/components/Modal'; | |||
| import { useListPage } from '/@/hooks/system/useListPage' | |||
| import TbSuggestModal from './components/TbSuggestModal.vue' | |||
| import {columns, searchFormSchema} from './tbSuggest.data'; | |||
| import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './tbSuggest.api'; | |||
| const checkedKeys = ref<Array<string | number>>([]); | |||
| //注册model | |||
| const [registerModal, {openModal}] = useModal(); | |||
| //注册table数据 | |||
| const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |||
| tableProps:{ | |||
| title: '帮助与反馈', | |||
| api: list, | |||
| columns, | |||
| canResize:false, | |||
| formConfig: { | |||
| labelWidth: 120, | |||
| schemas: searchFormSchema, | |||
| autoSubmitOnEnter:true, | |||
| showAdvancedButton:true, | |||
| fieldMapToTime: [ | |||
| ], | |||
| }, | |||
| actionColumn: { | |||
| width: 120, | |||
| }, | |||
| }, | |||
| exportConfig: { | |||
| name:"帮助与反馈", | |||
| url: getExportUrl, | |||
| }, | |||
| importConfig: { | |||
| url: getImportUrl | |||
| }, | |||
| }) | |||
| const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |||
| /** | |||
| * 新增事件 | |||
| */ | |||
| function handleAdd() { | |||
| openModal(true, { | |||
| isUpdate: false, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 编辑事件 | |||
| */ | |||
| function handleEdit(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: true, | |||
| }); | |||
| } | |||
| /** | |||
| * 详情 | |||
| */ | |||
| function handleDetail(record: Recordable) { | |||
| openModal(true, { | |||
| record, | |||
| isUpdate: true, | |||
| showFooter: false, | |||
| }); | |||
| } | |||
| /** | |||
| * 删除事件 | |||
| */ | |||
| async function handleDelete(record) { | |||
| await deleteOne({id: record.id}, reload); | |||
| } | |||
| /** | |||
| * 批量删除事件 | |||
| */ | |||
| async function batchHandleDelete() { | |||
| await batchDelete({ids: checkedKeys.value}, reload); | |||
| } | |||
| /** | |||
| * 成功回调 | |||
| */ | |||
| function handleSuccess() { | |||
| reload(); | |||
| } | |||
| /** | |||
| * 操作栏 | |||
| */ | |||
| function getTableAction(record){ | |||
| return [ | |||
| { | |||
| label: '编辑', | |||
| onClick: handleEdit.bind(null, record), | |||
| } | |||
| ] | |||
| } | |||
| /** | |||
| * 下拉操作栏 | |||
| */ | |||
| function getDropDownAction(record){ | |||
| return [ | |||
| { | |||
| label: '详情', | |||
| onClick: handleDetail.bind(null, record), | |||
| }, { | |||
| label: '删除', | |||
| popConfirm: { | |||
| title: '是否确认删除', | |||
| confirm: handleDelete.bind(null, record), | |||
| } | |||
| } | |||
| ] | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| </style> | |||
| @ -0,0 +1,58 @@ | |||
| <template> | |||
| <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |||
| <BasicForm @register="registerForm"/> | |||
| </BasicModal> | |||
| </template> | |||
| <script lang="ts" setup> | |||
| import {ref, computed, unref} from 'vue'; | |||
| import {BasicModal, useModalInner} from '/@/components/Modal'; | |||
| import {BasicForm, useForm} from '/@/components/Form/index'; | |||
| import {formSchema} from '../tbSuggest.data'; | |||
| import {saveOrUpdate} from '../tbSuggest.api'; | |||
| // Emits声明 | |||
| const emit = defineEmits(['register','success']); | |||
| const isUpdate = ref(true); | |||
| //表单配置 | |||
| const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |||
| labelWidth: 150, | |||
| schemas: formSchema, | |||
| showActionButtonGroup: false, | |||
| }); | |||
| //表单赋值 | |||
| const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |||
| //重置表单 | |||
| await resetFields(); | |||
| setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |||
| isUpdate.value = !!data?.isUpdate; | |||
| if (unref(isUpdate)) { | |||
| //表单赋值 | |||
| await setFieldsValue({ | |||
| ...data.record, | |||
| }); | |||
| } | |||
| // 隐藏底部时禁用整个表单 | |||
| setProps({ disabled: !data?.showFooter }) | |||
| }); | |||
| //设置标题 | |||
| const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |||
| //表单提交事件 | |||
| async function handleSubmit(v) { | |||
| try { | |||
| let values = await validate(); | |||
| setModalProps({confirmLoading: true}); | |||
| //提交表单 | |||
| await saveOrUpdate(values, isUpdate.value); | |||
| //关闭弹窗 | |||
| closeModal(); | |||
| //刷新列表 | |||
| emit('success'); | |||
| } finally { | |||
| setModalProps({confirmLoading: false}); | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="less" scoped> | |||
| </style> | |||
| @ -0,0 +1,44 @@ | |||
| package org.jeecg.modules.postBean; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import lombok.EqualsAndHashCode; | |||
| import lombok.experimental.Accessors; | |||
| import org.jeecgframework.poi.excel.annotation.Excel; | |||
| import java.io.Serializable; | |||
| /** | |||
| * @Description: 帮助与反馈 | |||
| * @Author: jeecg-boot | |||
| * @Date: 2024-10-19 | |||
| * @Version: V1.0 | |||
| */ | |||
| @Data | |||
| @Accessors(chain = true) | |||
| @EqualsAndHashCode(callSuper = false) | |||
| @ApiModel(value="问题反馈", description="帮助与反馈") | |||
| public class SuggestReq implements Serializable { | |||
| private static final long serialVersionUID = 1L; | |||
| /**用户名*/ | |||
| @Excel(name = "用户名", width = 15) | |||
| @ApiModelProperty(value = "用户名") | |||
| private String userName; | |||
| /**用户手机号*/ | |||
| @Excel(name = "用户手机号", width = 15) | |||
| @ApiModelProperty(value = "用户手机号") | |||
| private String userPhone; | |||
| /**问题描述*/ | |||
| @Excel(name = "问题描述", width = 15) | |||
| @ApiModelProperty(value = "问题描述") | |||
| private String content; | |||
| /**问题截图*/ | |||
| @Excel(name = "问题截图", width = 15) | |||
| @ApiModelProperty(value = "问题截图") | |||
| private String proofImg; | |||
| } | |||
| @ -1,39 +0,0 @@ | |||
| package org.jeecg.modules.user; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.jeecg.common.api.dto.message.MessageDTO; | |||
| import org.jeecg.modules.system.service.ISysUserService; | |||
| import org.jeecg.modules.system.service.impl.SysBaseApiImpl; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| /** | |||
| * 服务化 system模块 对外接口请求类 | |||
| * @author: jeecg-boot | |||
| */ | |||
| @Slf4j | |||
| @RestController | |||
| @RequestMapping("/user/") | |||
| public class UserController { | |||
| @Autowired | |||
| private SysBaseApiImpl sysBaseApi; | |||
| @Autowired | |||
| private ISysUserService sysUserService; | |||
| /** | |||
| * 发送系统消息 | |||
| * @param message 使用构造器赋值参数 如果不设置category(消息类型)则默认为2 发送系统消息 | |||
| */ | |||
| @PostMapping("/sendSysAnnouncement") | |||
| public void sendSysAnnouncement(@RequestBody MessageDTO message){ | |||
| sysBaseApi.sendSysAnnouncement(message); | |||
| } | |||
| } | |||
| @ -0,0 +1,79 @@ | |||
| package org.jeecg.modules.user.controller; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.xkcoding.http.HttpUtil; | |||
| 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.common.constant.CommonConstant; | |||
| import org.jeecg.common.util.RedisUtil; | |||
| import org.jeecg.config.shiro.ShiroRealm; | |||
| import org.jeecg.modules.user.service.IndexService; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; | |||
| import org.jeecg.modules.postBean.SuggestReq; | |||
| import org.jeecg.modules.tbSuggest.entity.TbSuggest; | |||
| import org.jeecg.modules.tbSuggest.service.ITbSuggestService; | |||
| import org.jeecg.modules.utils.ValidateTool; | |||
| import org.springframework.beans.BeanUtils; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import javax.annotation.Resource; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.stream.Collectors; | |||
| /** | |||
| * @Author scott | |||
| * @since 2018-12-17 | |||
| */ | |||
| @RestController | |||
| @RequestMapping("/index") | |||
| @Api(tags = "首页等展示接口") | |||
| @Slf4j | |||
| public class IndexController { | |||
| @Resource | |||
| private ITbSuggestService tbSuggestService; | |||
| @Resource | |||
| private IndexService indexService; | |||
| @Resource | |||
| private ShiroRealm shiroRealm; | |||
| @Resource | |||
| private RedisUtil redisUtil; | |||
| @ApiOperation(value = "我的头像昵称,平台客户电话等信息") | |||
| @RequestMapping(value = "/index", method = RequestMethod.POST) | |||
| public Result index(@RequestHeader("X-Access-Token") String token) { | |||
| Result<?> indexInfo = indexService.getIndexInfo(token); | |||
| return indexInfo; | |||
| } | |||
| @ApiOperation(value = "获取banner列表") | |||
| @RequestMapping(value = "/bannerList", method = RequestMethod.POST) | |||
| public Result<Map<Integer, List<WebBanner>>> bannerList(@RequestHeader("X-Access-Token") String token) { | |||
| return indexService.bannerList(); | |||
| } | |||
| @ApiOperation(value = "帮助与反馈", notes = "帮助与反馈") | |||
| @PostMapping(value = "/addSuggest") | |||
| public Result<String> addSuggest(@RequestBody SuggestReq tbSuggest, @RequestHeader("X-Access-Token") String token) { | |||
| HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token); | |||
| TbSuggest tbSuggest1 = new TbSuggest(); | |||
| BeanUtils.copyProperties(tbSuggest, tbSuggest1); | |||
| tbSuggest1.setUserId(hanHaiMember.getId()); | |||
| tbSuggestService.save(tbSuggest1); | |||
| return Result.OK("添加成功!"); | |||
| } | |||
| } | |||
| @ -0,0 +1,35 @@ | |||
| package org.jeecg.modules.user.controller; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.modules.bean.LoginReq; | |||
| import org.jeecg.modules.user.service.AppletLoginService; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import javax.annotation.Resource; | |||
| /** | |||
| * 服务化 system模块 对外接口请求类 | |||
| * @author: jeecg-boot | |||
| */ | |||
| @Slf4j | |||
| @RestController | |||
| @RequestMapping("/user/") | |||
| public class UserController { | |||
| @Resource | |||
| private AppletLoginService appletLoginService; | |||
| //小程序授权登录 | |||
| @ApiOperation(value="小程序-登录接口", notes="小程序-登录接口") | |||
| @GetMapping("/login") | |||
| public Result<?> login(LoginReq loginReq){ | |||
| return appletLoginService.appletLogin(loginReq); | |||
| } | |||
| } | |||
| @ -0,0 +1,15 @@ | |||
| package org.jeecg.modules.user.service; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.modules.bean.LoginReq; | |||
| public interface AppletLoginService { | |||
| /** | |||
| * 微信小程序登录接口 | |||
| * @param loginReq | |||
| * @return | |||
| */ | |||
| Result<Object> appletLogin(LoginReq loginReq); | |||
| } | |||
| @ -0,0 +1,18 @@ | |||
| package org.jeecg.modules.user.service; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import org.springframework.stereotype.Service; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| @Service | |||
| public interface IndexService { | |||
| //获取首页基础信息 | |||
| Result<?> getIndexInfo(String token); | |||
| Result<Map<Integer, List<WebBanner>>> bannerList(); | |||
| } | |||
| @ -0,0 +1,238 @@ | |||
| package org.jeecg.modules.user.service.impl; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.common.constant.CommonConstant; | |||
| import org.jeecg.common.exception.JeecgBootException; | |||
| import org.jeecg.common.system.util.JwtUtil; | |||
| import org.jeecg.common.util.RedisUtil; | |||
| import org.jeecg.modules.bean.HttpConf; | |||
| import org.jeecg.modules.bean.LoginReq; | |||
| import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; | |||
| import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService; | |||
| import org.jeecg.modules.user.service.AppletLoginService; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.transaction.annotation.Transactional; | |||
| import javax.annotation.Resource; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| @Service | |||
| public class AppletLoginServiceImpl implements AppletLoginService { | |||
| @Value("${wechat.mpAppId}") | |||
| private String mpAppId; | |||
| @Value("${wechat.mpAppSecret}") | |||
| private String mpAppSecret; | |||
| @Resource | |||
| private IHanHaiMemberService memberService; | |||
| @Resource | |||
| private RedisUtil redisUtil; | |||
| @Resource | |||
| private HttpConf httpConf; | |||
| /** | |||
| * 微信小程序登录接口 | |||
| * @param loginReq | |||
| * @return | |||
| */ | |||
| @Transactional(rollbackFor = {Exception.class}) | |||
| public Result<Object> appletLogin(LoginReq loginReq) { | |||
| Result<Object> result = new Result<>(); | |||
| Map<String, Object> map = new HashMap<>(); | |||
| if (StringUtils.isBlank(loginReq.getCode())) { | |||
| throw new JeecgBootException("小程序code为空"); | |||
| } | |||
| String loginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + mpAppId + "&secret=" + mpAppSecret+ "&js_code=" + loginReq.getCode() + "&grant_type=authorization_code"; | |||
| //使用工具类 | |||
| JSONObject json_test = httpConf.getJSONObject(loginUrl); | |||
| String wxOpenid = json_test.getString("openid"); | |||
| String sessionKey = json_test.getString("session_key"); | |||
| if (StringUtils.isBlank(wxOpenid)) { | |||
| throw new JeecgBootException("未获取到openid"); | |||
| } | |||
| HanHaiMember member = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid,wxOpenid).one(); | |||
| if (member == null) { | |||
| //如果user等于null说明该用户第一次登录,数据库没有该用户信息。 | |||
| loginReq.setOpenid(wxOpenid); | |||
| loginReq.setSession_key(sessionKey); | |||
| member = new HanHaiMember(); | |||
| // member.setSesssionKey(sessionKey); | |||
| member.setAppletOpenid(wxOpenid); | |||
| member.setNickName(loginReq.getNickName()); | |||
| member.setHeadImage(loginReq.getHeadimgurl()); | |||
| // 生成token返回给小程序端 | |||
| String token = JwtUtil.sign(member.getAppletOpenid(), wxOpenid); | |||
| memberService.save(member); | |||
| redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); | |||
| // 设置超时时间 | |||
| redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100); | |||
| map.put("userInfo", member); | |||
| map.put("token", token); | |||
| result.setCode(200); | |||
| result.setResult(map); | |||
| return result; | |||
| } else { | |||
| // member.setHeadImage(loginReq.getHeadimgurl()); | |||
| // member.setSessionKey(sessionKey); | |||
| // memberService.saveOrUpdate(member); | |||
| // 生成token返回给小程序端 | |||
| String token = JwtUtil.sign(member.getAppletOpenid(), wxOpenid); | |||
| redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); | |||
| // 设置超时时间 | |||
| redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 100); | |||
| map.put("userInfo", member); | |||
| map.put("token", token); | |||
| //用户id做im账号 | |||
| result.setResult(map); | |||
| result.setCode(200); | |||
| // result.setMessage(member.getNickName()+"已于"+member.getCreateTime()+"注册成功!请勿重复注册!"); | |||
| // // 未绑定手机号,跳转授权绑定手机号 | |||
| // if (StringUtils.isBlank(member.getPhone())) { | |||
| // result.setMessage("该微信用户尚未绑定手机号,请授权手机进行绑定"); | |||
| // result.setCode(905); | |||
| // result.setResult(map); | |||
| // return result; | |||
| // } | |||
| } | |||
| return result; | |||
| } | |||
| // /** | |||
| // * 微信小程序登录绑定手机号码接口 | |||
| // * @param loginReq | |||
| // * @return | |||
| // */ | |||
| // @Transactional(rollbackFor = Exception.class) | |||
| // @Override | |||
| // public Result<Object> bindPhone(LoginReq loginReq) { | |||
| // Result<Object> result = new Result<>(); | |||
| // if (StringUtils.isEmpty(loginReq.getEncryptedData())) { | |||
| // result.setCode(500); | |||
| // result.setMessage("请授权手机号"); | |||
| // return result; | |||
| // } | |||
| // String loginUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + mpAppId + "&secret=" + mpAppSecret+ "&js_code=" + loginReq.getCode() + "&grant_type=authorization_code"; | |||
| // CloseableHttpClient client = null; | |||
| // CloseableHttpResponse response = null; | |||
| // try { | |||
| // // 创建http GET请求 | |||
| // HttpGet httpGet = new HttpGet(loginUrl); | |||
| // client = HttpClients.createDefault(); | |||
| // // 执行请求 | |||
| // response = client.execute(httpGet); | |||
| // HttpEntity entity = response.getEntity();//得到返回数据 | |||
| // String resultStr = EntityUtils.toString(entity); | |||
| // JSONObject json_test = JSONObject.parseObject(resultStr); | |||
| // String wxOpenid = json_test.getString("openid"); | |||
| // if (StringUtils.isEmpty(wxOpenid)) { | |||
| // return result.error500("未获取到openid"); | |||
| // } | |||
| // String sessionKey = json_test.getString("session_key"); | |||
| // // 保存sessionKey,用于解析手机号码 | |||
| // loginReq.setOpenid(wxOpenid); | |||
| // loginReq.setSession_key(sessionKey); | |||
| // String userPhone = getPhoneNumber(loginReq); | |||
| // HanHaiMember one = memberService.lambdaQuery().eq(HanHaiMember::getAppletOpenid, wxOpenid).one(); | |||
| // if(one!=null){ | |||
| // return result.OK("请不要重复注册"); | |||
| // } | |||
| // HanHaiMember member = new HanHaiMember(); | |||
| // member.setSessionKey(sessionKey); | |||
| // member.setAppletOpenid(wxOpenid); | |||
| // member.setNickName(loginReq.getNickName()); | |||
| // member.setHeadImage(loginReq.getHeadimgurl()); | |||
| // member.setPhone(userPhone); | |||
| // | |||
| // | |||
| // //判断用户是否存在 | |||
| // HanHaiMember boolOne = memberService.lambdaQuery().eq(HanHaiMember::getAccount, loginReq.geta()).one(); | |||
| // boolean bool = false; | |||
| // if(one != null){ | |||
| // bool = true; | |||
| // } | |||
| // | |||
| // if(!bool){ | |||
| // member.setId(boolOne.getId()); | |||
| // memberService.updateById(member); | |||
| // }else{ | |||
| // memberService.save(member); | |||
| // } | |||
| // | |||
| // | |||
| // | |||
| // return result.OK("注册成功",member); | |||
| // }catch(Exception e) { | |||
| // e.printStackTrace(); | |||
| // return Result.error("操作失败,请联系系统管理员!"); | |||
| // } | |||
| // | |||
| // } | |||
| // | |||
| // | |||
| // | |||
| // /** | |||
| // * 解析电话号码 | |||
| // * @param loginReq | |||
| // * @return | |||
| // */ | |||
| // public String getPhoneNumber(LoginReq loginReq) { | |||
| // String encryptedData = loginReq.getEncryptedData(); | |||
| // String session_key = loginReq.getSession_key(); | |||
| // String iv = loginReq.getIv(); | |||
| // // 被加密的数据 | |||
| // byte[] dataByte = Base64.decodeBase64(encryptedData); | |||
| // // 加密秘钥 | |||
| // byte[] keyByte = Base64.decodeBase64(session_key); | |||
| // // 偏移量 | |||
| // byte[] ivByte = Base64.decodeBase64(iv); | |||
| // try { | |||
| // // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 | |||
| // int base = 16; | |||
| // if (keyByte.length % base != 0) { | |||
| // int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); | |||
| // byte[] temp = new byte[groups * base]; | |||
| // Arrays.fill(temp, (byte) 0); | |||
| // System.arraycopy(keyByte, 0, temp, 0, keyByte.length); | |||
| // keyByte = temp; | |||
| // } | |||
| // // 初始化 | |||
| // Security.addProvider(new BouncyCastleProvider()); | |||
| // Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC"); | |||
| // SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); | |||
| // AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); | |||
| // parameters.init(new IvParameterSpec(ivByte)); | |||
| // cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化 | |||
| // byte[] resultByte = cipher.doFinal(dataByte); | |||
| // if (null != resultByte && resultByte.length > 0) { | |||
| // String result = new String(resultByte, "UTF-8"); | |||
| // JSONObject userPhoneObj = JSONObject.parseObject(result); | |||
| // Map<String, Object> userMap = new HashMap<>(); | |||
| // for (Map.Entry<String, Object> entry : userPhoneObj.entrySet()) { | |||
| // userMap.put(entry.getKey(), entry.getValue()); | |||
| // } | |||
| // // 获取phoneNumber 带区号 | |||
| // String userPhone = (String) userMap.get("phoneNumber"); | |||
| // return userPhone; | |||
| // } | |||
| // } catch (Exception e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // return null; | |||
| // } | |||
| } | |||
| @ -0,0 +1,83 @@ | |||
| package org.jeecg.modules.user.service.impl; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |||
| import org.jeecg.common.api.vo.Result; | |||
| import org.jeecg.common.util.RedisUtil; | |||
| import org.jeecg.config.shiro.ShiroRealm; | |||
| import org.jeecg.modules.banner.entity.WebBanner; | |||
| import org.jeecg.modules.banner.service.IWebBannerService; | |||
| import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; | |||
| import org.jeecg.modules.tbConf.entity.TbConf; | |||
| import org.jeecg.modules.tbConf.service.ITbConfService; | |||
| import org.jeecg.modules.user.service.IndexService; | |||
| import org.jeecg.modules.utils.ValidateTool; | |||
| import org.springframework.stereotype.Service; | |||
| import javax.annotation.Resource; | |||
| import java.util.Comparator; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.stream.Collectors; | |||
| @Service | |||
| public class IndexServiceImpl implements IndexService { | |||
| @Resource | |||
| private IWebBannerService webBannerService; | |||
| @Resource | |||
| private ITbConfService tbConfService; | |||
| @Resource | |||
| private ShiroRealm shiroRealm; | |||
| // @Resource | |||
| // private ITbUserRoleService tbUserRoleService; | |||
| @Resource | |||
| private RedisUtil redisUtil; | |||
| @Override | |||
| public Result<?> getIndexInfo(String token) { | |||
| HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(token); | |||
| hanHaiMember.setPasswordSalt(null); | |||
| JSONObject jsonObject = new JSONObject(); | |||
| QueryWrapper<TbConf> objectQueryWrapper = new QueryWrapper<>(); | |||
| objectQueryWrapper.eq("name", "sys_phone"); | |||
| TbConf one = tbConfService.getOne(objectQueryWrapper); | |||
| //平台客户电话号码 | |||
| jsonObject.put("phone", ValidateTool.isNull(one) ? "19198239116" : one.getValue()); | |||
| jsonObject.put("my", hanHaiMember); | |||
| //清关背景图 | |||
| QueryWrapper<TbConf> queryWrapper = new QueryWrapper<>(); | |||
| queryWrapper.eq("name", "sys_pic_qg"); | |||
| TbConf pic = tbConfService.getOne(queryWrapper); | |||
| jsonObject.put("pic", ValidateTool.isNull(pic) ? "https://dianpin-img.xzaiyp.top/temp/组478612x_1730704228537.png" : pic.getValue()); | |||
| // LambdaQueryWrapper<TbUserRole> objectLambdaQueryWrapper = new LambdaQueryWrapper<>(); | |||
| // objectLambdaQueryWrapper.eq(TbUserRole::getUserId, hanHaiMember.getId()). | |||
| // eq(TbUserRole::getRole, 0).eq(TbUserRole::getAuditStatus, 1); | |||
| // TbUserRole cg = tbUserRoleService.getOne(objectLambdaQueryWrapper); | |||
| // LambdaQueryWrapper<TbUserRole> queryWrapper1 = new LambdaQueryWrapper<>(); | |||
| // queryWrapper1.eq(TbUserRole::getUserId, hanHaiMember.getId()). | |||
| // eq(TbUserRole::getRole, 1).eq(TbUserRole::getAuditStatus, 1); | |||
| // TbUserRole shop = tbUserRoleService.getOne(queryWrapper1); | |||
| //// 返回采购商身份信息 | |||
| // jsonObject.put("buy", cg); | |||
| //// 返回供应商身份信息 | |||
| // jsonObject.put("shop", shop); | |||
| return Result.OK(jsonObject); | |||
| } | |||
| @Override | |||
| public Result<Map<Integer, List<WebBanner>>> bannerList() { | |||
| //获取banner | |||
| QueryWrapper<WebBanner> objectQueryWrapper = new QueryWrapper<>(); | |||
| objectQueryWrapper.eq("is_disable", 0).orderByDesc("sort"); | |||
| List<WebBanner> bannerList = webBannerService.list(objectQueryWrapper); | |||
| //分组排序返回 | |||
| Map<Integer, List<WebBanner>> collect = bannerList.stream().sorted(Comparator.comparing(WebBanner::getSort).reversed()).collect(Collectors.groupingBy(WebBanner::getType)); | |||
| return Result.ok(collect); | |||
| } | |||
| } | |||
| @ -0,0 +1,381 @@ | |||
| package org.jeecg.modules.utils; | |||
| import org.jeecg.common.exception.JeecgBootException; | |||
| import java.text.MessageFormat; | |||
| import java.util.Collection; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| public class ValidateTool { | |||
| public static boolean isEmpty(Collection coll) { | |||
| return coll == null || coll.isEmpty(); | |||
| } | |||
| public static boolean isEmpty(CharSequence cs) { | |||
| return cs == null || cs.length() == 0; | |||
| } | |||
| public static boolean isNotEmpty(Collection coll) { | |||
| return !isEmpty(coll); | |||
| } | |||
| public static boolean isNotEmpty(CharSequence cs) { | |||
| return !isEmpty(cs); | |||
| } | |||
| /** | |||
| * 是否为空白字符串 字符串仅为空格、回车、换行、制表符、空字符串...时 返回false | |||
| * @param cs | |||
| * @return | |||
| */ | |||
| public static boolean isBlank(CharSequence cs) { | |||
| int strLen = length(cs); | |||
| if (strLen == 0) { | |||
| return true; | |||
| } else { | |||
| for(int i = 0; i < strLen; ++i) { | |||
| if (!Character.isWhitespace(cs.charAt(i))) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| public static boolean isNotBlank(CharSequence cs) { | |||
| return !isBlank(cs); | |||
| } | |||
| public static int length(CharSequence cs) { | |||
| return cs == null ? 0 : cs.length(); | |||
| } | |||
| /** | |||
| * 验证参数是否为空 | |||
| * | |||
| * @param obj | |||
| * @return 不为�?:true,为空false | |||
| * @throws | |||
| */ | |||
| public static boolean checkIsNull(Object obj) { | |||
| if (obj == null) { | |||
| return false; | |||
| } | |||
| if (obj instanceof String) { | |||
| if (((String) obj).trim().equals("")) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| public static boolean isNull(Object obj) { | |||
| if (obj == null) { | |||
| return true; | |||
| } | |||
| if (obj instanceof String) { | |||
| if (((String) obj).trim().equals("")) { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| public static boolean isNotNull(Object obj) { | |||
| if (obj == null) { | |||
| return false; | |||
| } | |||
| if (obj instanceof String) { | |||
| if (((String) obj).trim().equals("")) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| // String regName = "^[A-Za-z0-9]{6,40}$"; | |||
| // if (!userCustomerModel.getUsername().matches(regName)) { | |||
| // throw new JeecgBootException(MessageUtil.getMessage("COMMON_CHEECKNAME_ERROR_CODE"), MessageUtil.getMessage("COMMON_CHEECKNAME_ERROR")); | |||
| // } | |||
| public static boolean checkIsWX(String str){ | |||
| //微信号码 | |||
| // 微信号规则:微信账号仅支持6-20个字母、数字、下划线或减号,以字母开头。解释一下,只要是字母开头,可以是纯字母(hjqzHJQZhongjiqiezi),或字母数字混合 | |||
| String pattern = "^[a-zA-Z]{1}[-_a-zA-Z0-9]{5,19}+$"; | |||
| boolean isMatch = Pattern.matches(pattern, str); | |||
| if (isMatch==false) { | |||
| throw new JeecgBootException("微信号不合法"); | |||
| } | |||
| return true; | |||
| }; | |||
| public static boolean checkIsQQ(String str){ | |||
| //数字范围5-14个之间 | |||
| String pattern = "[1-9][0-9]{4,14}"; | |||
| boolean isMatch = Pattern.matches(pattern, str); | |||
| if (isMatch==false) { | |||
| throw new JeecgBootException("QQ号不合法"); | |||
| } | |||
| return true; | |||
| } | |||
| // | |||
| //^[a-zA-Z][a-zA-Z0-9_]{4,15}$ | |||
| public static boolean checkIsName(String str){ | |||
| Pattern p = Pattern.compile("[\\u4e00-\\u9fa5]"); | |||
| Matcher m = p.matcher(str); | |||
| if (m.matches()) { | |||
| return true; | |||
| } else { | |||
| throw new JeecgBootException("用户名不合法"); | |||
| } | |||
| } | |||
| /** | |||
| * 验证参数长度 | |||
| * | |||
| * @param code 参数名称 | |||
| * @param obj | |||
| * @param begin | |||
| * @param end | |||
| * @return boolean | |||
| * @throws | |||
| */ | |||
| public static boolean checkParamLength(String code, Object obj, int begin, int end) { | |||
| if (!checkIsNull(obj)) { | |||
| throw new JeecgBootException(format("{0}不能为空,请确认", code)); | |||
| } | |||
| if (obj instanceof String) { | |||
| if (!checkLength((String) obj, begin, end)) { | |||
| throw new JeecgBootException(format("验证码错误", code)); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * @description 验证参数是否为空以及参数长度是否符合要求 | |||
| * @param code, obj, begin, end | |||
| * @return boolean | |||
| * @date 2019/6/24/024 | |||
| */ | |||
| public static boolean checkParam(String code, Object obj, int begin, int end) { | |||
| if (!checkIsNull(obj)) { | |||
| throw new JeecgBootException(format("{0}不能为空,请确认", code)); | |||
| } | |||
| if (obj instanceof String) { | |||
| if (!checkLength((String) obj, begin, end)) { | |||
| throw new JeecgBootException(format("{0}长度不符合格式", code)); | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| public static String format(String message, Object... arg) { | |||
| MessageFormat formatter = new MessageFormat(message); | |||
| String output = formatter.format(arg); | |||
| return output; | |||
| } | |||
| public static int totalLength(String content) { | |||
| String regex = "[\u4e00-\u9fa5]"; | |||
| int length = content.length(); | |||
| int chineseLength = content.length() - content.replaceAll(regex, "").length(); | |||
| return length+chineseLength; | |||
| } | |||
| /** | |||
| * @description 判断字符串是不是汉字 | |||
| * @param: con | |||
| * @param: ignore 是否忽略 · 这个符号 | |||
| * @return boolean | |||
| * @date 2019/9/20/020 | |||
| */ | |||
| public static boolean isChinese(String con,boolean ignore) { | |||
| for (int i = 0; i < con.length(); i = i + 1) { | |||
| if (ignore){ | |||
| if (!Pattern.compile("[\u4e00-\u9fa5]").matcher( | |||
| String.valueOf(con.charAt(i))).find() && !"·".equals(String.valueOf(con.charAt(i)))) { | |||
| return false; | |||
| } | |||
| }else { | |||
| if (!Pattern.compile("[\u4e00-\u9fa5]").matcher( | |||
| String.valueOf(con.charAt(i))).find()) { | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * @description 判断是不是中文或英文字母 | |||
| * @param: con | |||
| * @return boolean | |||
| * @date 2019/9/20/020 | |||
| */ | |||
| public static boolean conValidate(String con) { | |||
| if (null != con && !"".equals(con)) { | |||
| if ((isChinese(con,true) || con.matches("^[A-Za-z]+$"))) { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * 验证参数长度 | |||
| * | |||
| * @param code 参数名称 | |||
| * @param obj | |||
| * @return boolean | |||
| * @throws | |||
| */ | |||
| public static boolean checkParamIsNull(String code, Object obj) { | |||
| if (!checkIsNull(obj)) { | |||
| throw new JeecgBootException(format("{0}不能为空,请确认", code)); | |||
| } | |||
| return true; | |||
| } | |||
| public static boolean checkLength(String str, int begin, int end) { | |||
| if (str == null) { | |||
| return false; | |||
| } | |||
| if (str.length() <= end && str.length() >= begin) { | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| /** | |||
| * 验证是否为手机号�? | |||
| * | |||
| * @throws JeecgBootException | |||
| */ | |||
| public static boolean checkParamIsMobile(String mobile) { | |||
| if (mobile == null || mobile == "") { | |||
| throw new JeecgBootException( "请填写手机号"); | |||
| } | |||
| if (!isMobileNO(mobile)) { | |||
| throw new JeecgBootException( "手机号错误"); | |||
| } | |||
| return true; | |||
| } | |||
| //验证手机号码格式 | |||
| public static boolean isMobileNO(String mobiles) { | |||
| // if (mobiles == null ) { | |||
| // return false; | |||
| // } | |||
| // else { | |||
| // return true; | |||
| // } | |||
| if (!checkIsNull(mobiles)) { | |||
| return false; | |||
| } | |||
| String pattern = "(0|86)?(13[0-9]|14[0-9]|15[0-9]|16[012345689]|17[2-9]|18[0-9]|19[0-9])[0-9]{8}"; | |||
| //手机号码 | |||
| Pattern p = Pattern.compile(pattern); | |||
| Matcher m = p.matcher(mobiles); | |||
| if (m.matches()) { | |||
| return true; | |||
| } else { | |||
| return false; | |||
| } | |||
| } | |||
| /** | |||
| * 验证输入的邮箱格式是否符合 | |||
| * | |||
| * @param email | |||
| * @return 是否合法 | |||
| */ | |||
| public static boolean emailFormat(String email) { | |||
| boolean tag = true; | |||
| final String pattern1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; | |||
| final Pattern pattern = Pattern.compile(pattern1); | |||
| final Matcher mat = pattern.matcher(email); | |||
| if (!mat.find()) { | |||
| tag = false; | |||
| } | |||
| return tag; | |||
| } | |||
| public static boolean isNum(String code, String value) { | |||
| if (value == null) { | |||
| throw new JeecgBootException(format("{0}不能为空,请确认", code)); | |||
| } | |||
| String pattern = "^[0-9]+$"; | |||
| Pattern p = Pattern.compile(pattern); | |||
| Matcher m = p.matcher(value); | |||
| if (!m.matches()) { | |||
| throw new JeecgBootException(format("{0}数据不符合格式", code)); | |||
| } | |||
| return true; | |||
| } | |||
| public static boolean isBankCard(String value) { | |||
| if (isNull(value)) { | |||
| throw new JeecgBootException("银行卡号不能为空,请确认"); | |||
| } | |||
| String pattern = "^[0-9]+$"; | |||
| Pattern p = Pattern.compile(pattern); | |||
| Matcher m = p.matcher(value); | |||
| if (!m.matches()) { | |||
| throw new JeecgBootException("银行卡号格式错误"); | |||
| } | |||
| if (value.length()<16 || value.length()>19) { | |||
| throw new JeecgBootException("银行卡号格式错误"); | |||
| } | |||
| return true; | |||
| } | |||
| public static boolean isDecimalValid(String code, String str, int start, int end) { | |||
| checkParamIsNull(code, str); | |||
| int s = 0; | |||
| try { | |||
| s = Integer.parseInt(str); | |||
| } catch (Exception e) { | |||
| throw new JeecgBootException(format("{0}数据不符合格式", code)); | |||
| } | |||
| if (end == start) { | |||
| if (end == s) { | |||
| return true; | |||
| } else { | |||
| throw new JeecgBootException(format("{0}数据不符合格式", code)); | |||
| } | |||
| } else { | |||
| if (s <= end && s >= start) { | |||
| return true; | |||
| } | |||
| } | |||
| throw new JeecgBootException(format("{0}数据不符合格式", code)); | |||
| } | |||
| } | |||
| @ -0,0 +1,368 @@ | |||
| server: | |||
| port: 8000 | |||
| tomcat: | |||
| max-swallow-size: -1 | |||
| error: | |||
| include-exception: true | |||
| include-stacktrace: ALWAYS | |||
| include-message: ALWAYS | |||
| servlet: | |||
| context-path: /employ-admin | |||
| compression: | |||
| enabled: true | |||
| min-response-size: 1024 | |||
| mime-types: application/javascript,application/json,application/xml,text/html,text/xml,text/plain,text/css,image/* | |||
| management: | |||
| endpoints: | |||
| web: | |||
| exposure: | |||
| include: metrics,httptrace | |||
| spring: | |||
| servlet: | |||
| multipart: | |||
| max-file-size: 10MB | |||
| max-request-size: 10MB | |||
| mail: | |||
| host: smtp.qq.com | |||
| username: | |||
| password: | |||
| properties: | |||
| mail: | |||
| smtp: | |||
| auth: true | |||
| starttls: | |||
| enable: true | |||
| required: true | |||
| ## quartz定时任务,采用数据库方式 | |||
| quartz: | |||
| job-store-type: jdbc | |||
| initialize-schema: embedded | |||
| #定时任务启动开关,true-开 false-关 | |||
| auto-startup: true | |||
| #启动时更新己存在的Job | |||
| overwrite-existing-jobs: true | |||
| properties: | |||
| org: | |||
| quartz: | |||
| scheduler: | |||
| instanceName: MyScheduler | |||
| instanceId: AUTO | |||
| jobStore: | |||
| class: org.springframework.scheduling.quartz.LocalDataSourceJobStore | |||
| driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate | |||
| tablePrefix: QRTZ_ | |||
| isClustered: true | |||
| misfireThreshold: 60000 | |||
| clusterCheckinInterval: 10000 | |||
| threadPool: | |||
| class: org.quartz.simpl.SimpleThreadPool | |||
| threadCount: 10 | |||
| threadPriority: 5 | |||
| threadsInheritContextClassLoaderOfInitializingThread: true | |||
| #json 时间戳统一转换 | |||
| jackson: | |||
| date-format: yyyy-MM-dd HH:mm:ss | |||
| time-zone: GMT+8 | |||
| jpa: | |||
| open-in-view: false | |||
| activiti: | |||
| check-process-definitions: false | |||
| #启用作业执行器 | |||
| async-executor-activate: false | |||
| #启用异步执行器 | |||
| job-executor-activate: false | |||
| aop: | |||
| proxy-target-class: true | |||
| #配置freemarker | |||
| freemarker: | |||
| # 设置模板后缀名 | |||
| suffix: .ftl | |||
| # 设置文档类型 | |||
| content-type: text/html | |||
| # 设置页面编码格式 | |||
| charset: UTF-8 | |||
| # 设置页面缓存 | |||
| cache: false | |||
| prefer-file-system-access: false | |||
| # 设置ftl文件路径 | |||
| template-loader-path: | |||
| - classpath:/templates | |||
| # 设置静态文件路径,js,css等 | |||
| mvc: | |||
| static-path-pattern: /** | |||
| #Spring Boot 2.6+后映射匹配的默认策略已从AntPathMatcher更改为PathPatternParser,需要手动指定为ant-path-matcher | |||
| pathmatch: | |||
| matching-strategy: ant_path_matcher | |||
| resource: | |||
| static-locations: classpath:/static/,classpath:/public/ | |||
| autoconfigure: | |||
| exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure | |||
| datasource: | |||
| druid: | |||
| stat-view-servlet: | |||
| enabled: true | |||
| loginUsername: admin | |||
| loginPassword: 123456 | |||
| allow: | |||
| web-stat-filter: | |||
| enabled: true | |||
| dynamic: | |||
| druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置) | |||
| # 连接池的配置信息 | |||
| # 初始化大小,最小,最大 | |||
| initial-size: 5 | |||
| min-idle: 5 | |||
| maxActive: 20 | |||
| # 配置获取连接等待超时的时间 | |||
| maxWait: 60000 | |||
| # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | |||
| timeBetweenEvictionRunsMillis: 60000 | |||
| # 配置一个连接在池中最小生存的时间,单位是毫秒 | |||
| minEvictableIdleTimeMillis: 300000 | |||
| validationQuery: SELECT 1 | |||
| testWhileIdle: true | |||
| testOnBorrow: false | |||
| testOnReturn: false | |||
| # 打开PSCache,并且指定每个连接上PSCache的大小 | |||
| poolPreparedStatements: true | |||
| maxPoolPreparedStatementPerConnectionSize: 20 | |||
| # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 | |||
| filters: stat,wall,slf4j | |||
| # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 | |||
| # connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000 | |||
| datasource: | |||
| master: | |||
| url: jdbc:mysql://8.138.162.67:3306/employ2?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&autoReconnect=true&failOverReadOnly=false | |||
| username: root | |||
| password: Fk4q*h@V | |||
| driver-class-name: com.mysql.cj.jdbc.Driver | |||
| # 多数据源配置 | |||
| #multi-datasource1: | |||
| #url: jdbc:mysql://localhost:3306/jeecg-boot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai | |||
| #username: root | |||
| #password: root | |||
| #driver-class-name: com.mysql.cj.jdbc.Driver | |||
| #redis 配置 | |||
| redis: | |||
| database: 4 | |||
| host: 8.138.162.67 | |||
| lettuce: | |||
| pool: | |||
| max-active: -1 #最大连接数据库连接数,设 -1 为没有限制 | |||
| max-idle: 0 #最大等待连接中的数量,设 0 为没有限制 | |||
| max-wait: -1ms #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。 | |||
| min-idle: 0 #最小等待连接中的数量,设 0 为没有限制 | |||
| shutdown-timeout: 1000ms | |||
| password: 'gmmGMM@2024' | |||
| port: 6379 | |||
| #mybatis plus 设置 | |||
| mybatis-plus: | |||
| mapper-locations: classpath*:org/jeecg/**/xml/*Mapper.xml | |||
| global-config: | |||
| # 关闭MP3.0自带的banner | |||
| banner: false | |||
| db-config: | |||
| #主键类型 0:"数据库ID自增",1:"该类型为未设置主键类型", 2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID",5:"字符串全局唯一ID (idWorker 的字符串表示)"; | |||
| id-type: ASSIGN_ID | |||
| # 默认数据库表下划线命名 | |||
| table-underline: true | |||
| configuration: | |||
| # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 | |||
| # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl | |||
| # 返回类型为Map,显示null对应的字段 | |||
| call-setters-on-nulls: true | |||
| #jeecg专用配置 | |||
| minidao : | |||
| base-package: org.jeecg.modules.jmreport.* | |||
| jeecg : | |||
| # 是否启用安全模式 | |||
| safeMode: false | |||
| # 签名密钥串(前后端要一致,正式发布请自行修改) | |||
| signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a | |||
| # 本地:local\Minio:minio\阿里云:alioss | |||
| uploadType: alioss | |||
| path : | |||
| #文件上传根目录 设置 | |||
| upload: /opt/upFiles | |||
| #webapp文件路径 | |||
| webapp: /opt/webapp | |||
| shiro: | |||
| excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**,/category/**,/visual/**,/map/**,/jmreport/bigscreen2/** | |||
| #阿里云oss存储和大鱼短信秘钥配置 | |||
| oss: | |||
| accessKey: LTAI5tPfZo39q2r9Sr5mW84u | |||
| secretKey: XxExGallsV4O9nERHpVsQg2XtPCU7r | |||
| endpoint: oss-cn-guangzhou.aliyuncs.com | |||
| bucketName: augcl | |||
| staticDomain: https://img.augcl.com | |||
| # ElasticSearch 6设置 | |||
| elasticsearch: | |||
| cluster-name: jeecg-ES | |||
| cluster-nodes: 127.0.0.1:9200 | |||
| check-enabled: false | |||
| # 表单设计器配置 | |||
| desform: | |||
| # 主题颜色(仅支持 16进制颜色代码) | |||
| theme-color: "#1890ff" | |||
| # 文件、图片上传方式,可选项:qiniu(七牛云)、system(跟随系统配置) | |||
| upload-type: system | |||
| map: | |||
| # 配置百度地图的AK,申请地址:https://lbs.baidu.com/apiconsole/key?application=key#/home | |||
| baidu: ?? | |||
| # 在线预览文件服务器地址配置 | |||
| file-view-domain: 127.0.0.1:8012 | |||
| # minio文件上传 | |||
| minio: | |||
| minio_url: http://minio.jeecg.com | |||
| minio_name: ?? | |||
| minio_pass: ?? | |||
| bucketName: otatest | |||
| #大屏报表参数设置 | |||
| jmreport: | |||
| mode: dev | |||
| #数据字典是否进行saas数据隔离,自己看自己的字典 | |||
| saas: false | |||
| #是否需要校验token | |||
| is_verify_token: true | |||
| #必须校验方法 | |||
| verify_methods: remove,delete,save,add,update | |||
| #自定义项目前缀 | |||
| customPrePath: | |||
| pageSize: | |||
| - 10 | |||
| - 20 | |||
| - 30 | |||
| - 40 | |||
| #Wps在线文档 | |||
| wps: | |||
| domain: https://wwo.wps.cn/office/ | |||
| appid: ?? | |||
| appsecret: ?? | |||
| #xxl-job配置 | |||
| xxljob: | |||
| enabled: false | |||
| adminAddresses: http://127.0.0.1:9080/xxl-job-admin | |||
| appname: ${spring.application.name} | |||
| accessToken: '' | |||
| address: 127.0.0.1:30007 | |||
| ip: 127.0.0.1 | |||
| port: 30007 | |||
| logPath: logs/jeecg/job/jobhandler/ | |||
| logRetentionDays: 30 | |||
| route: | |||
| config: | |||
| data-id: jeecg-gateway-router | |||
| group: DEFAULT_GROUP | |||
| #自定义路由配置 yml nacos database | |||
| data-type: database | |||
| #分布式锁配置 | |||
| redisson: | |||
| address: 127.0.0.1:6379 | |||
| password: | |||
| type: STANDALONE | |||
| enabled: true | |||
| #cas单点登录 | |||
| cas: | |||
| prefixUrl: http://cas.example.org:8443/cas | |||
| #Mybatis输出sql日志 | |||
| logging: | |||
| level: | |||
| org.jeecg.modules.system.mapper : info | |||
| #swagger | |||
| knife4j: | |||
| #开启增强配置 | |||
| enable: true | |||
| #开启生产环境屏蔽 | |||
| production: false | |||
| basic: | |||
| enable: false | |||
| username: jeecg | |||
| password: jeecg1314 | |||
| #第三方登录 | |||
| justauth: | |||
| enabled: true | |||
| type: | |||
| GITHUB: | |||
| client-id: ?? | |||
| client-secret: ?? | |||
| redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/github/callback | |||
| WECHAT_ENTERPRISE: | |||
| client-id: ?? | |||
| client-secret: ?? | |||
| redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/wechat_enterprise/callback | |||
| agent-id: ?? | |||
| DINGTALK: | |||
| client-id: ?? | |||
| client-secret: ?? | |||
| redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/dingtalk/callback | |||
| WECHAT_OPEN: | |||
| client-id: ?? | |||
| client-secret: ?? | |||
| redirect-uri: http://sso.test.com:8080/jeecg-boot/sys/thirdLogin/wechat_open/callback | |||
| cache: | |||
| type: default | |||
| prefix: 'demo::' | |||
| timeout: 1h | |||
| #第三方APP对接 | |||
| third-app: | |||
| enabled: false | |||
| type: | |||
| #企业微信 | |||
| WECHAT_ENTERPRISE: | |||
| enabled: false | |||
| #CORP_ID | |||
| client-id: ?? | |||
| #SECRET | |||
| client-secret: ?? | |||
| #自建应用id | |||
| agent-id: ?? | |||
| #自建应用秘钥(新版企微需要配置) | |||
| # agent-app-secret: ?? | |||
| #钉钉 | |||
| DINGTALK: | |||
| enabled: false | |||
| # appKey | |||
| client-id: ?? | |||
| # appSecret | |||
| client-secret: ?? | |||
| agent-id: ?? | |||
| #配置微信 | |||
| wechat: | |||
| mpAppId: | |||
| mpAppSecret: | |||
| mchId: | |||
| mchKey: | |||
| keyPath: /usr/local/cert/apiclient_cert.p12 | |||
| notifyUrl: | |||
| page: /pages/loginAgreement/login | |||
| codeImg: /usr/codeImage | |||
| savePath: WxCodeFile | |||
| keyPemPath: apiclient_key.pem | |||
| serialNo: | |||
| apiV3Key: | |||
| baseUrl: https://api.mch.weixin.qq.com/v3 | |||
| wxpay: | |||
| #应用编号 | |||
| appId: | |||
| #商户号 | |||
| mchId: | |||
| # APIv2密钥 | |||
| apiKey: | |||
| # APIv3密钥 | |||
| apiV3Key: | |||
| # 微信支付V3-url前缀 | |||
| baseUrl: https://api.mch.weixin.qq.com/v3 | |||
| # 密钥路径,resources根目录下 | |||
| keyPemPath: apiclient_key.pem | |||
| #商户证书序列号 | |||
| serialNo: | |||
| # 支付通知回调, pjm6m9.natappfree.cc 为内网穿透地址 | |||
| notifyUrl: | |||
| # 退款通知回调, pjm6m9.natappfree.cc 为内网穿透地址 | |||
| refundNotifyUrl: | |||