diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java index 95bcaece..bd28665d 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java @@ -34,6 +34,11 @@ public class SysConfigController extends BaseController @Autowired private ISysConfigService configService; + @GetMapping("/test") + public String list(){ + return "test"; + } + /** * 获取参数配置列表 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java index caebb397..c91943da 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java @@ -47,6 +47,9 @@ public class SysLoginController @Autowired private ISysConfigService configService; + + + /** * 登录方法 * @@ -58,7 +61,7 @@ public class SysLoginController { AjaxResult ajax = AjaxResult.success(); // 生成令牌 - String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getUuid()); ajax.put(Constants.TOKEN, token); return ajax; diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml index bcfad3ea..49718862 100644 --- a/ruoyi-admin/src/main/resources/application-druid.yml +++ b/ruoyi-admin/src/main/resources/application-druid.yml @@ -6,9 +6,9 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: password + url: jdbc:mysql://193.112.94.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: ry-vue + password: yKSYaNzYifKFNHHj # 从库数据源 slave: # 从数据源开关/默认关闭 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index ff21fe0d..a7f7990a 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -7,7 +7,7 @@ ruoyi: # 版权年份 copyrightYear: 2026 # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) - profile: D:/ruoyi/uploadPath + profile: /home/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数字计算 char 字符验证 @@ -68,13 +68,13 @@ spring: # redis 配置 redis: # 地址 - host: localhost + host: 193.112.94.36 # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码 - password: + password: 123456 # 连接超时时间 timeout: 10s lettuce: diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-admin/src/main/resources/logback.xml index d69a5720..54a1f2ed 100644 --- a/ruoyi-admin/src/main/resources/logback.xml +++ b/ruoyi-admin/src/main/resources/logback.xml @@ -1,7 +1,7 @@ - + diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index be8730e8..da919909 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -113,6 +113,13 @@ javax.servlet-api + + + org.projectlombok + lombok + 1.18.24 + + \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index 693461b9..8db1bd2a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -15,6 +15,7 @@ import com.ruoyi.common.core.domain.BaseEntity; * * @author ruoyi */ + public class SysDept extends BaseEntity { private static final long serialVersionUID = 1L; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index a7795f32..4b8bd4b1 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -60,10 +60,10 @@ public class SysLoginService * @param uuid 唯一标识 * @return 结果 */ - public String login(String username, String password, String code, String uuid) + public String login(String username, String password, String uuid) { // 验证码校验 - validateCaptcha(username, code, uuid); +// validateCaptcha(username, code, uuid); // 登录前置校验 loginPreCheck(username, password); // 用户验证 diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java index d64ab08f..b1c7c5fb 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java @@ -189,7 +189,7 @@ public class VelocityUtils } else if (template.contains("mapper.java.vm")) { - fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + fileName = StringUtils.format("{}/mapper/{}mapper.java", javaPath, className); } else if (template.contains("service.java.vm")) { @@ -205,7 +205,7 @@ public class VelocityUtils } else if (template.contains("mapper.xml.vm")) { - fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + fileName = StringUtils.format("{}/{}mapper.xml", mybatisPath, className); } else if (template.contains("sql.vm")) { diff --git a/ruoyi-mall/pom.xml b/ruoyi-mall/pom.xml new file mode 100644 index 00000000..29d41093 --- /dev/null +++ b/ruoyi-mall/pom.xml @@ -0,0 +1,97 @@ + + + + ruoyi + com.ruoyi + 3.9.1 + + 4.0.0 + jar + ruoyi-mall + + + 微店商城服务 + + + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + io.springfox + springfox-boot-starter + + + + + io.swagger + swagger-models + 1.6.2 + + + + + mysql + mysql-connector-java + + + + + com.ruoyi + ruoyi-framework + + + + + com.ruoyi + ruoyi-quartz + + + + + com.ruoyi + ruoyi-generator + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.5.15 + + true + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + ${project.artifactId} + + + + ${project.artifactId} + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/MallApplication.java b/ruoyi-mall/src/main/java/com/ruoyi/MallApplication.java new file mode 100644 index 00000000..45303fce --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/MallApplication.java @@ -0,0 +1,20 @@ +package com.ruoyi; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +/** + * 启动程序 + * + * @author ruoyi + */ +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) +public class MallApplication +{ + public static void main(String[] args) + { + SpringApplication.run(MallApplication.class, args); + System.out.println("商城Mall启动成功"); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/ruoyi-mall/src/main/java/com/ruoyi/RuoYiServletInitializer.java new file mode 100644 index 00000000..d55e335f --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/RuoYiServletInitializer.java @@ -0,0 +1,18 @@ +package com.ruoyi; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author ruoyi + */ +public class RuoYiServletInitializer extends SpringBootServletInitializer +{ + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) + { + return application.sources(MallApplication.class); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/controller/BrandController.java b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/BrandController.java new file mode 100644 index 00000000..b7e0c093 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/BrandController.java @@ -0,0 +1,66 @@ +package com.ruoyi.web.controller; + +import com.ruoyi.common.annotation.Anonymous; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.web.domain.Brand; +import com.ruoyi.web.service.BrandService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/mall/brand") +public class BrandController extends BaseController { + + @Autowired + private BrandService brandService; + + /** + * 获取商品品牌树 + * + * @return + */ + @Anonymous + @GetMapping("/tree") + public AjaxResult getBrandTree() { + return AjaxResult.success(brandService.getBrandTree()); + } + + /** + * 添加商品品牌 + * + * @param brand + * @return + */ + @Anonymous + @Log(title = "商品品牌管理", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult addBrand(@RequestBody Brand brand) { + brand.setCreateBy(getUsername()); + return toAjax(brandService.addBrand(brand)); + } + + /** + * 修改商品品牌 + * + * @param brand + * @return + */ + @Anonymous + @Log(title = "商品品牌管理", businessType = BusinessType.UPDATE) + @PostMapping("/update") + public AjaxResult updateBrand(@RequestBody Brand brand) { + return toAjax(brandService.updateBrand(brand)); + } + + // 删除品牌 + @DeleteMapping("/delete/{id}") + public String deleteBrand(@PathVariable Long id) { + brandService.deleteBrand(id); + return "success"; + } +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/controller/ProductStoreController.java b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/ProductStoreController.java new file mode 100644 index 00000000..f302bb76 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/ProductStoreController.java @@ -0,0 +1,148 @@ +package com.ruoyi.web.controller; + +import com.ruoyi.common.annotation.Anonymous; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.exception.file.InvalidExtensionException; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileUploadUtils; +import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.common.utils.file.MimeTypeUtils; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.web.domain.Product; +import com.ruoyi.web.domain.Store; +import com.ruoyi.web.dto.BatchStoreDTO; +import com.ruoyi.web.service.ProductService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 商品管理 + */ +@RestController +@RequestMapping("/mall/product") +public class ProductStoreController extends BaseController { + @Autowired + private ProductService productService; + + /** + * 获取商品列表 + */ + @PreAuthorize("@ss.hasPermi('product:list')") + @GetMapping("/list") + public AjaxResult list(Product product) { + return AjaxResult.success(productService.selectList(product)); + } + + /** + * 批量删除商品 + */ + @Anonymous + @DeleteMapping("/batchDelete") + public AjaxResult batchDelete(@RequestBody BatchStoreDTO dto) { + return toAjax(productService.batchProductById(dto)); + } + + + /** + * 根据商品id 获取商品详情 + */ + @PreAuthorize("@ss.hasPermi('product:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable Long id) { + return success(productService.selectProductBarCode(id)); + } + + + + /** + * 新增商品 + */ + @PreAuthorize("@ss.hasPermi('product:add')") + @Log(title = "商品管理", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@Validated Product product, + @RequestParam("file") MultipartFile file) throws IOException, InvalidExtensionException { + + if (!productService.checkProductCodeUnique(product)) { + return error("新增商品条码'" + product.getProductBarCode() + "'失败,商品条码已存在"); + } + // TODO: 2026/1/14 这个file 为空的时候 就使用国码里面的图片,不为空代表用户自己选择了图片上传 用自己服务器上的 + //国码后续添加 + if (!file.isEmpty()) { + String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true); + if (StringUtils.isNotEmpty(avatar)) { + product.setMainImage(avatar); + } + } + product.setCreateBy(getUsername()); + return toAjax(productService.insertProductStore(product)); + } + + + /** + * 修改商品信息 + */ +// @PreAuthorize("@ss.hasPermi('product:edit')") + @Anonymous + @Log(title = "商品管理", businessType = BusinessType.UPDATE) + @PostMapping("/update") + public AjaxResult edit(@Validated Product product, + @RequestParam("file") MultipartFile file) throws IOException, InvalidExtensionException { + if (!productService.checkProductCodeUnique(product)) { + return error("修改商品条码'" + product.getProductBarCode() + "'失败,商品条码已存在"); + } + // TODO: 2026/1/14 这个file 为空的时候 就使用国码里面的图片,不为空代表用户自己选择了图片上传 用自己服务器上的 + //然后修改的时候 这个file不为空代表用户又修改了图片需要更新,为空的话之前图片保持不变 + if (!file.isEmpty()) { + String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true); + if (StringUtils.isNotEmpty(avatar)) { + product.setMainImage(avatar); + } + } + + //todo 这里可以国码有的时候使用国码的图片路径 + + + product.setUpdateBy(getUsername()); + return toAjax(productService.updateProduct(product)); + } + + + /** + * 删除商品 + */ + @PreAuthorize("@ss.hasPermi('product:delete')") + @Log(title = "商品管理", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{id}") + public AjaxResult remove(@PathVariable Long id) { + return toAjax(productService.deleteProductById(id)); + } + + + /** + * 商品导入excel + */ + @Log(title = "商品管理", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('product:import')") + @PostMapping("/importData") + public AjaxResult importData(@RequestParam("file") MultipartFile file, + @RequestParam("storeId") Integer storeId) throws Exception { + ExcelUtil util = new ExcelUtil(Product.class); + List productList = util.importExcel(file.getInputStream()); + return AjaxResult.success(productService.importProduct(productList,storeId)); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/controller/StoreController.java b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/StoreController.java new file mode 100644 index 00000000..f5276bb5 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/controller/StoreController.java @@ -0,0 +1,96 @@ +package com.ruoyi.web.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.web.domain.Store; +import com.ruoyi.web.dto.UserStoreAssignDTO; +import com.ruoyi.web.service.StoreService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 门店管理 + */ +@RestController +@RequestMapping("/mall/store") +public class StoreController extends BaseController { + @Autowired + private StoreService storeService; + + /** + * 查询门店管理 + */ + @PreAuthorize("@ss.hasPermi('store:list')") + @GetMapping("/list") + public TableDataInfo list(Store store) { + startPage(); + List list = storeService.selectList(store); + return getDataTable(list); + } + + + /** + * 新增门店 + */ + @PreAuthorize("@ss.hasPermi('store:add')") + @Log(title = "门店管理", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@Validated @RequestBody Store store) { + if (!storeService.checkStoreNameUnique(store)) { + return error("新增门店'" + store.getStoreCode() + "'失败,门店编码已存在"); + } + store.setCreateBy(getUsername()); + return toAjax(storeService.insertStore(store)); + } + + /** + * 删除门店 + */ + @PreAuthorize("@ss.hasPermi('store:delete')") + @Log(title = "门店管理", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{storeId}") + public AjaxResult remove(@PathVariable Long storeId) { + return toAjax(storeService.deleteStoreById(storeId)); + } + + /** + * 修改门店信息 + */ + @PreAuthorize("@ss.hasPermi('store:edit')") + @Log(title = "门店管理", businessType = BusinessType.UPDATE) + @PutMapping("update") + public AjaxResult edit(@Validated @RequestBody Store store) { + if (!storeService.checkStoreNameUnique(store)) { + return error("修改门店编码'" + store.getStoreCode() + "'失败,门店编码已存在"); + } + store.setUpdateBy(getUsername()); + return toAjax(storeService.updateStore(store)); + } + + + /** + * 用户关联门店 包含 修改 删除 + */ + @PreAuthorize("@ss.hasPermi('user:store:edit')") + @Log(title = "用户关联门店", businessType = BusinessType.GRANT) + @PutMapping("/userCorrelationStore") + public AjaxResult userCorrelationStore(@RequestBody UserStoreAssignDTO dto) { + return toAjax(storeService.insertUserStores(dto.getUserId(), dto.getStoreIds())); + } + + /** + * 根据用户id 获取关联的门店 + */ +// @PreAuthorize("@ss.hasPermi('product:query')") + @GetMapping(value = "/getUserStore/{userId}") + public AjaxResult getUserStore(@PathVariable String userId) { + return success(storeService.getUserStore(userId)); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/ruoyi-mall/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java new file mode 100644 index 00000000..ae1c3ecf --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java @@ -0,0 +1,125 @@ +package com.ruoyi.web.core.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.ruoyi.common.config.RuoYiConfig; +import io.swagger.annotations.ApiOperation; +import io.swagger.models.auth.In; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.AuthorizationScope; +import springfox.documentation.service.Contact; +import springfox.documentation.service.SecurityReference; +import springfox.documentation.service.SecurityScheme; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; + +/** + * Swagger2的接口配置 + * + * @author ruoyi + */ +@Configuration +public class SwaggerConfig +{ + /** 系统基础配置 */ + @Autowired + private RuoYiConfig ruoyiConfig; + + /** 是否开启swagger */ + @Value("${swagger.enabled}") + private boolean enabled; + + /** 设置请求的统一前缀 */ + @Value("${swagger.pathMapping}") + private String pathMapping; + + /** + * 创建API + */ + @Bean + public Docket createRestApi() + { + return new Docket(DocumentationType.OAS_30) + // 是否启用Swagger + .enable(enabled) + // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) + .apiInfo(apiInfo()) + // 设置哪些接口暴露给Swagger展示 + .select() + // 扫描所有有注解的api,用这种方式更灵活 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + // 扫描指定包中的swagger注解 + // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger")) + // 扫描所有 .apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()) + .build() + /* 设置安全模式,swagger可以设置访问token */ + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()) + .pathMapping(pathMapping); + } + + /** + * 安全模式,这里指定token通过Authorization头请求头传递 + */ + private List securitySchemes() + { + List apiKeyList = new ArrayList(); + apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); + return apiKeyList; + } + + /** + * 安全上下文 + */ + private List securityContexts() + { + List securityContexts = new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) + .build()); + return securityContexts; + } + + /** + * 默认的安全上引用 + */ + private List defaultAuth() + { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List securityReferences = new ArrayList<>(); + securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); + return securityReferences; + } + + /** + * 添加摘要信息 + */ + private ApiInfo apiInfo() + { + // 用ApiInfoBuilder进行定制 + return new ApiInfoBuilder() + // 设置标题 + .title("标题:若依管理系统_接口文档") + // 描述 + .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") + // 作者信息 + .contact(new Contact(ruoyiConfig.getName(), null, null)) + // 版本 + .version("版本号:" + ruoyiConfig.getVersion()) + .build(); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Brand.java b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Brand.java new file mode 100644 index 00000000..6de2ac79 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Brand.java @@ -0,0 +1,20 @@ +package com.ruoyi.web.domain; + +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import java.util.List; + +/** + * 商品品牌表 mall_brand + */ +@Data +public class Brand extends BaseEntity { + private static final long serialVersionUID = 1L; + + private Long id; + private Long parentId = 0L; // 0表示一级品牌 + private String brandName; // 品牌名称 + private Integer storeId; //门店id + // 非数据库字段:子商品品牌列表 + private List children; +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Product.java b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Product.java new file mode 100644 index 00000000..05946a85 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Product.java @@ -0,0 +1,108 @@ +package com.ruoyi.web.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +/** + * 商品门店库存表 mall_product_store + */ +@Data +public class Product extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + private Long id; + + /** + * 商品编码 + */ + @Excel(name = "商品编码") + private String productCode; + + /** + * 货架码 + */ + @Excel(name = "货架码") + private String shelfCode; + + /** + * 保质期天数 + */ + private Integer shelfLife; + + /** + * 生产日期 + */ + private String productionDate; + + /** + * 临期天数 + */ + private Integer approaching; + + /** + * 商品条码 + */ + @NotBlank(message = "商品条码不能为空") + @Excel(name = "商品条码") + private String productBarCode; + + /** + * 商品名称 + */ + @NotBlank(message = "商品名称不能为空") + @Excel(name = "商品名称") + private String productName; + /** + * 商品描述 + */ + @Excel(name = "商品描述") + private String productDesc; + /** + * 主图 + */ + private String mainImage; + /** + * 门店销售价 + */ + private BigDecimal storePrice; + /** + * 成本价 + */ + private BigDecimal costPrice; + + /** + * 市场价 + */ + private Long originalPrice; + + /** + * 门店ID + */ + private Integer storeId; + + /** + * 库存数量 + */ + @NotNull(message = "库存数量不能为空") + @Excel(name = "库存数量") + private Integer stockQuantity; + /** + * 已售数量 + */ + private Integer soldQuantity; + + /** + * 状态(0上架 1下架) + */ + private String status; + +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Store.java b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Store.java new file mode 100644 index 00000000..43cf7636 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/domain/Store.java @@ -0,0 +1,59 @@ +package com.ruoyi.web.domain; + +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; + + +/** + * 门店表 mall_store + */ +@Data +public class Store extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 门店ID + */ + private Long storeId; + + /** + * 门店名称 + */ + private String storeName; + + /** + * 门店编码 + */ + private String storeCode; + + /** + * 省份 + */ + private String province; + + /** + * 城市 + */ + private String city; + + /** + * 区县 + */ + private String district; + + /** + * 完整地址 + */ + private String fullAddress; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 店长 + */ + private String storeManager; + +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/dto/BatchStoreDTO.java b/ruoyi-mall/src/main/java/com/ruoyi/web/dto/BatchStoreDTO.java new file mode 100644 index 00000000..b7b79ed8 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/dto/BatchStoreDTO.java @@ -0,0 +1,11 @@ +package com.ruoyi.web.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class BatchStoreDTO { + + private List ids; +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/dto/UserStoreAssignDTO.java b/ruoyi-mall/src/main/java/com/ruoyi/web/dto/UserStoreAssignDTO.java new file mode 100644 index 00000000..517b4e65 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/dto/UserStoreAssignDTO.java @@ -0,0 +1,9 @@ +package com.ruoyi.web.dto; + +import lombok.Data; + +@Data +public class UserStoreAssignDTO { + private Long userId; + private Long[] storeIds; +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/BrandMapper.java b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/BrandMapper.java new file mode 100644 index 00000000..7e4d2bcd --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/BrandMapper.java @@ -0,0 +1,56 @@ +package com.ruoyi.web.mapper; + +import com.ruoyi.web.domain.Brand; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +@Mapper +public interface BrandMapper { + + /** + * 查询所有品牌 + */ + List selectAll(); + + /** + * 查询一级品牌(parentId=0) + */ + List selectRootBrands(); + + /** + * 根据父品牌ID查询子品牌 + */ + List selectByParentId(@Param("parentId") Long parentId); + + /** + * 根据ID查询品牌 + */ + Brand selectById(@Param("id") Long id); + + /** + * 新增品牌 + */ + int insert(Brand brand); + + /** + * 更新品牌 + */ + int update(Brand brand); + + /** + * 删除品牌 + */ + int delete(@Param("id") Long id); + + +// /** +// * 检查是否有子品牌 +// */ +// int countChildren(@Param("parentId") Long parentId); +// +// /** +// * 根据品牌名称查询 +// */ +// Brand selectByName(@Param("brandName") String brandName); +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/ProductMapper.java b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/ProductMapper.java new file mode 100644 index 00000000..197b4cb7 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/ProductMapper.java @@ -0,0 +1,29 @@ +package com.ruoyi.web.mapper; + +import com.ruoyi.web.domain.Product; +import com.ruoyi.web.domain.Store; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 商品 数据层 + */ +public interface ProductMapper { + List selectList(Product product); + + Product checkProductCodeUnique(Product product); + + int insertProductStore(Product product); + + Product selectProductBarCode(Long id); + + int deleteProductById(Long id); + + int updateProduct(Product product); + + int updateProductBarCode(Product product); + + + int batchProductById(@Param("ids") List ids); +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/StoreMapper.java b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/StoreMapper.java new file mode 100644 index 00000000..e2cb1dae --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/StoreMapper.java @@ -0,0 +1,32 @@ +package com.ruoyi.web.mapper; + + +import com.ruoyi.web.domain.Store; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 门店 数据层 + * + */ +public interface StoreMapper +{ + List selectList(Store store); + + int insertStore(Store store); + + Store checkStoreNameUnique(@Param("storeCode") String storeCode,@Param("storeId") Long storeId); + + int deleteStoreById(Long storeId); + + int updateStore(Store store); + + void deleteUserStore(Long userId); + + int insertUserStore(@Param("userId") Long userId, @Param("storeIds") Long[] storeIds); + + void deleteStoreUser(Long storeId); + + +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/UserStoreMapper.java b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/UserStoreMapper.java new file mode 100644 index 00000000..f382801e --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/mapper/UserStoreMapper.java @@ -0,0 +1,12 @@ +package com.ruoyi.web.mapper; + + +import com.ruoyi.web.vo.UserStoreVo; + +/** + * 用户关联门店 + */ +public interface UserStoreMapper { + + UserStoreVo getUserStoreWithStores(String userId); +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/BrandService.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/BrandService.java new file mode 100644 index 00000000..920d3018 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/BrandService.java @@ -0,0 +1,20 @@ +package com.ruoyi.web.service; + +import com.ruoyi.web.domain.Brand; + +import java.util.List; + +public interface BrandService { + + // 获取品牌树(一级品牌包含子品牌) + List getBrandTree(); + + // 添加品牌 + int addBrand(Brand brand); + + int updateBrand(Brand brand); + + // 删除品牌 + void deleteBrand(Long id); + +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/ProductService.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/ProductService.java new file mode 100644 index 00000000..d5b8486b --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/ProductService.java @@ -0,0 +1,38 @@ +package com.ruoyi.web.service; + +import com.ruoyi.web.domain.Product; +import com.ruoyi.web.dto.BatchStoreDTO; + +import java.util.List; + +/** + * 商品 服务层 + * + */ +public interface ProductService { + /** + * 分页查询所有商品 + * @param product + * @return + */ + List selectList(Product product); + + /** + * 查询商品编码是否存在 + * @param product + * @return + */ + boolean checkProductCodeUnique(Product product); + + int insertProductStore(Product product); + + int importProduct(List productList,Integer storeId); + + Product selectProductBarCode(Long id); + + int deleteProductById(Long id); + + int updateProduct(Product product); + + int batchProductById(BatchStoreDTO dto); +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/StoreService.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/StoreService.java new file mode 100644 index 00000000..40e2064e --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/StoreService.java @@ -0,0 +1,59 @@ +package com.ruoyi.web.service; + +import com.ruoyi.web.domain.Store; +import com.ruoyi.web.vo.UserStoreVo; + +import java.util.List; + +/** + * 门店 服务层 + * + * @author ruoyi + */ +public interface StoreService { + + /** + * 分页查询门店 + * @param store + * @return + */ + List selectList(Store store); + + /** + * 新增门店信息 + * @param store + * @return + */ + int insertStore(Store store); + + /** + * 查看门店编码是否存在 + * @param store + * @return + */ + boolean checkStoreNameUnique(Store store); + + /** + * 删除门店 + * @param storeId + * @return + */ + int deleteStoreById(Long storeId); + + /** + * 修改部门信息 + * @param store + * @return + */ + int updateStore(Store store); + + /** + * 用户关联门店 + * @param userId + * @param storeIds + * @return + */ + int insertUserStores(Long userId, Long[] storeIds); + + UserStoreVo getUserStore(String userId); +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/BrandServiceImpl.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/BrandServiceImpl.java new file mode 100644 index 00000000..ae6058fa --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/BrandServiceImpl.java @@ -0,0 +1,57 @@ +package com.ruoyi.web.service.impl; + +import com.ruoyi.web.domain.Brand; +import com.ruoyi.web.mapper.BrandMapper; +import com.ruoyi.web.service.BrandService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +public class BrandServiceImpl implements BrandService { + + @Autowired + private BrandMapper brandMapper; + + @Override + public List getBrandTree() { + // 1. 获取所有一级品牌 + List rootBrands = brandMapper.selectRootBrands(); + + // 2. 为每个一级品牌设置子品牌 + for (Brand rootBrand : rootBrands) { + List children = brandMapper.selectByParentId(rootBrand.getId()); + rootBrand.setChildren(children); + } + return rootBrands; + } + + @Override + @Transactional + public int addBrand(Brand brand) { + // 如果是二级品牌,检查父品牌是否存在 + if (brand.getParentId() != null && brand.getParentId() != 0) { + Brand parent = brandMapper.selectById(brand.getParentId()); + if (parent == null || parent.getParentId() != 0) { + throw new RuntimeException("父品牌不存在或不是一级品牌"); + } + } else { + brand.setParentId(0L); // 确保一级品牌parentId=0 + } + return brandMapper.insert(brand); + } + + @Override + @Transactional + public int updateBrand(Brand brand) { + return brandMapper.update(brand); + } + + @Override + public void deleteBrand(Long id) { + + } + +} \ No newline at end of file diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/ProductServiceImpl.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/ProductServiceImpl.java new file mode 100644 index 00000000..39da8c9c --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/ProductServiceImpl.java @@ -0,0 +1,82 @@ +package com.ruoyi.web.service.impl; + + +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.web.domain.Product; +import com.ruoyi.web.dto.BatchStoreDTO; +import com.ruoyi.web.mapper.ProductMapper; +import com.ruoyi.web.service.ProductService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 商品 服务层实现 + */ +@Service +public class ProductServiceImpl implements ProductService { + @Resource + private ProductMapper productMapper; + + + @Override + public List selectList(Product product) { + return productMapper.selectList(product); + } + + @Override + public boolean checkProductCodeUnique(Product product) { + if (product == null || StringUtils.isBlank(product.getProductBarCode())) { + return UserConstants.UNIQUE; + } + + Long id = product.getId() == null ? -1L : product.getId(); + product.setId(id); + Product product1 = productMapper.checkProductCodeUnique(product); + return product1 != null ? UserConstants.NOT_UNIQUE : UserConstants.UNIQUE; + } + + @Override + public int insertProductStore(Product product) { + return productMapper.insertProductStore(product); + } + + @Override + public int importProduct(List productList, Integer storeId) { + for (Product product : productList) { + product.setStoreId(storeId); + //判断同条形码是否存在,区分不同门店 + if (!checkProductCodeUnique(product)) { + productMapper.updateProductBarCode(product); + } else { + productMapper.insertProductStore(product); + } + } + return 1; + } + + @Override + public Product selectProductBarCode(Long id) { + return productMapper.selectProductBarCode(id); + } + + @Override + public int deleteProductById(Long id) { + return productMapper.deleteProductById(id); + } + + @Override + public int updateProduct(Product product) { + return productMapper.updateProduct(product); + } + + @Override + public int batchProductById(BatchStoreDTO dto) { + if (dto.getIds() == null || dto.getIds().isEmpty()) { + return 0; + } + return productMapper.batchProductById(dto.getIds()); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/StoreServiceImpl.java b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/StoreServiceImpl.java new file mode 100644 index 00000000..795c0f5f --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/service/impl/StoreServiceImpl.java @@ -0,0 +1,89 @@ +package com.ruoyi.web.service.impl; + + +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.web.domain.Store; +import com.ruoyi.web.mapper.StoreMapper; +import com.ruoyi.web.mapper.UserStoreMapper; +import com.ruoyi.web.service.StoreService; +import com.ruoyi.web.vo.UserStoreVo; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + + +/** + * 门店 服务层实现 + * + * @author ruoyi + */ +@Service +public class StoreServiceImpl implements StoreService { + + @Resource + private StoreMapper storeMapper; + + @Resource + private UserStoreMapper userStoreMapper; + + @Override + public List selectList(Store store) { + return storeMapper.selectList(store); + } + + @Override + public int insertStore(Store store) { + return storeMapper.insertStore(store); + } + + @Override + public boolean checkStoreNameUnique(Store store) { + if (store == null || StringUtils.isBlank(store.getStoreCode())) { + return UserConstants.UNIQUE; + } + + // 获取当前门店ID(新增时为-1) + Long storeId = store.getStoreId() == null ? -1L : store.getStoreId(); + + // 查询除自身外是否有相同编码的门店 + Store existStore = storeMapper.checkStoreNameUnique( + store.getStoreCode(), + storeId + ); + + // 如果查询到记录,说明编码已被其他门店使用 + return existStore != null ? UserConstants.NOT_UNIQUE : UserConstants.UNIQUE; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteStoreById(Long storeId) { + storeMapper.deleteStoreUser(storeId); + return storeMapper.deleteStoreById(storeId); + } + + @Override + public int updateStore(Store store) { + return storeMapper.updateStore(store); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUserStores(Long userId, Long[] storeIds) { + //先把直接这个用户关联的门店删除掉 + storeMapper.deleteUserStore(userId); + //再新增新的用户关联门店 + if (storeIds != null && storeIds.length > 0) { + return storeMapper.insertUserStore(userId, storeIds); + } + return 1; + } + + @Override + public UserStoreVo getUserStore(String userId) { + return userStoreMapper.getUserStoreWithStores(userId); + } +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/vo/StoreVo.java b/ruoyi-mall/src/main/java/com/ruoyi/web/vo/StoreVo.java new file mode 100644 index 00000000..e14cc291 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/vo/StoreVo.java @@ -0,0 +1,22 @@ +package com.ruoyi.web.vo; + +import lombok.Data; + +@Data +public class StoreVo { + + /** + * 门店ID + */ + private Long storeId; + + /** + * 门店名称 + */ + private String storeName; + + /** + * 门店编码 + */ + private String storeCode; +} diff --git a/ruoyi-mall/src/main/java/com/ruoyi/web/vo/UserStoreVo.java b/ruoyi-mall/src/main/java/com/ruoyi/web/vo/UserStoreVo.java new file mode 100644 index 00000000..54dcba77 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/ruoyi/web/vo/UserStoreVo.java @@ -0,0 +1,12 @@ +package com.ruoyi.web.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class UserStoreVo { + + private Long userId; //用户id + private List stores; // 门店对象列表 +} diff --git a/ruoyi-mall/src/main/resources/META-INF/spring-devtools.properties b/ruoyi-mall/src/main/resources/META-INF/spring-devtools.properties new file mode 100644 index 00000000..37e7b580 --- /dev/null +++ b/ruoyi-mall/src/main/resources/META-INF/spring-devtools.properties @@ -0,0 +1 @@ +restart.include.json=/com.alibaba.fastjson2.*.jar \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/application-druid.yml b/ruoyi-mall/src/main/resources/application-druid.yml new file mode 100644 index 00000000..10bf7d85 --- /dev/null +++ b/ruoyi-mall/src/main/resources/application-druid.yml @@ -0,0 +1,61 @@ +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + # 主库数据源 + master: + url: jdbc:mysql://193.112.94.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: ry-vue + password: yKSYaNzYifKFNHHj + # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + url: + username: + password: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置连接超时时间 + connectTimeout: 30000 + # 配置网络超时时间 + socketTimeout: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: ruoyi + login-password: 123456 + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/application.yml b/ruoyi-mall/src/main/resources/application.yml new file mode 100644 index 00000000..6e3fd810 --- /dev/null +++ b/ruoyi-mall/src/main/resources/application.yml @@ -0,0 +1,136 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: RuoYi + # 版本 + version: 3.9.1 + # 版权年份 + copyrightYear: 2026 + # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) + profile: /home/ruoyi/uploadPath + # 获取ip地址开关 + addressEnabled: false + # 验证码类型 math 数字计算 char 字符验证 + captchaType: math + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8081 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # 连接数满后的排队数,默认为100 + accept-count: 1000 + threads: + # tomcat最大线程数,默认为200 + max: 800 + # Tomcat启动初始化的线程数,默认值10 + min-spare: 100 + +# 日志配置 +logging: + level: + com.ruoyi: debug + org.springframework: warn + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: druid + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + # 服务模块 + devtools: + restart: + # 热部署开关 + enabled: true + # redis 配置 + redis: + # 地址 + host: 193.112.94.36 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 + password: 123456 + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接池中的最大空闲连接 + max-idle: 8 + # 连接池的最大数据库连接数 + max-active: 8 + # #连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + +# token配置 +token: + # 令牌自定义标识 + header: Authorization + # 令牌密钥 + secret: abcdefghijklmnopqrstuvwxyz + # 令牌有效期(默认30分钟) + expireTime: 30 + +# MyBatis配置 +mybatis: + # 搜索指定包别名 + typeAliasesPackage: com.ruoyi.**.domain + # 配置mapper的扫描,找到所有的mapper.xml映射文件 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 加载全局的配置文件 + configLocation: classpath:mybatis/mybatis-config.xml + +# PageHelper分页插件 +pagehelper: + helperDialect: mysql + supportMethodsArguments: true + params: count=countSql + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true + # 请求前缀 + pathMapping: /dev-api + +# 防盗链配置 +referer: + # 防盗链开关 + enabled: false + # 允许的域名列表 + allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* diff --git a/ruoyi-mall/src/main/resources/banner.txt b/ruoyi-mall/src/main/resources/banner.txt new file mode 100644 index 00000000..0931cb84 --- /dev/null +++ b/ruoyi-mall/src/main/resources/banner.txt @@ -0,0 +1,24 @@ +Application Version: ${ruoyi.version} +Spring Boot Version: ${spring-boot.version} +//////////////////////////////////////////////////////////////////// +// _ooOoo_ // +// o8888888o // +// 88" . "88 // +// (| ^_^ |) // +// O\ = /O // +// ____/`---'\____ // +// .' \\| |// `. // +// / \\||| : |||// \ // +// / _||||| -:- |||||- \ // +// | | \\\ - /// | | // +// | \_| ''\---/'' | | // +// \ .-\__ `-` ___/-. / // +// ___`. .' /--.--\ `. . ___ // +// ."" '< `.___\_<|>_/___.' >'"". // +// | | : `- \`.;`\ _ /`;.`/ - ` : | | // +// \ \ `-. \_ __\ /__ _/ .-` / / // +// ========`-.____`-.___\_____/___.-`____.-'======== // +// `=---=' // +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// 佛祖保佑 永不宕机 永无BUG // +//////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/i18n/messages.properties b/ruoyi-mall/src/main/resources/i18n/messages.properties new file mode 100644 index 00000000..93de0055 --- /dev/null +++ b/ruoyi-mall/src/main/resources/i18n/messages.properties @@ -0,0 +1,38 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +login.blocked=很遗憾,访问IP已被列入系统黑名单 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 + +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 + +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/ruoyi-mall/src/main/resources/logback.xml b/ruoyi-mall/src/main/resources/logback.xml new file mode 100644 index 00000000..a8c526ec --- /dev/null +++ b/ruoyi-mall/src/main/resources/logback.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log.path}/sys-user.log + + + ${log.path}/sys-user.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/mapper/commodity/BrandMapper.xml b/ruoyi-mall/src/main/resources/mapper/commodity/BrandMapper.xml new file mode 100644 index 00000000..160324f0 --- /dev/null +++ b/ruoyi-mall/src/main/resources/mapper/commodity/BrandMapper.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into mall_brand ( + parent_id, + brand_name, + create_by, + store_id, + create_time + )values( + #{parentId}, + #{brandName}, + #{createBy}, + #{storeId}, + sysdate() + ) + + + + + UPDATE mall_brand + SET brand_name = #{brandName} + WHERE id = #{id} + + + + + DELETE + FROM brand + WHERE id = #{id} + + + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/mapper/commodity/ProductMapper.xml b/ruoyi-mall/src/main/resources/mapper/commodity/ProductMapper.xml new file mode 100644 index 00000000..8a85ff88 --- /dev/null +++ b/ruoyi-mall/src/main/resources/mapper/commodity/ProductMapper.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, + product_code, + product_name, + product_desc, + main_image, + store_price, + cost_price, + store_id, + stock_quantity, + sold_quantity, + status, + create_by, + create_time, + update_by, + update_time, + remark, + product_bar_code, + shelf_code, + shelf_life, + production_date, + approaching + from mall_product_store + + + + + + + + + + + + insert into mall_product_store ( + product_code, + product_name, + product_desc, + main_image, + store_price, + cost_price, + original_price, + store_id, + stock_quantity, + sold_quantity, + status, + create_by, + remark, + shelf_code, + product_bar_code, + shelf_life, + production_date, + approaching, + create_time + )values( + #{productCode}, + #{productName}, + #{productDesc}, + #{mainImage}, + #{storePrice}, + #{costPrice}, + #{originalPrice}, + #{storeId}, + #{stockQuantity}, + #{soldQuantity}, + #{status}, + #{createBy}, + #{remark}, + #{shelfCode}, + #{productBarCode}, + #{shelfLife}, + #{productionDate}, + #{approaching}, + sysdate() + ) + + + + + update mall_product_store + + product_code = #{productCode}, + product_name = #{productName}, + product_desc = #{productDesc}, + main_image = #{mainImage}, + store_price = #{storePrice}, + cost_price = #{costPrice}, + stock_quantity = #{stockQuantity}, + sold_quantity = #{soldQuantity}, + status = #{status}, + shelf_code = #{shelfCode}, + product_bar_code = #{productBarCode}, + update_by = #{updateBy}, + remark = #{remark}, + shelf_life = #{shelfLife}, + production_date = #{productionDate}, + approaching = #{approaching}, + update_time = sysdate() + + where id = #{id} + + + + update mall_product_store + + product_code = #{productCode}, + product_name = #{productName}, + product_desc = #{productDesc}, + main_image = #{mainImage}, + store_price = #{storePrice}, + cost_price = #{costPrice}, + stock_quantity = #{stockQuantity}, + sold_quantity = #{soldQuantity}, + status = #{status}, + shelf_code = #{shelfCode}, + product_bar_code = #{productBarCode}, + update_by = #{updateBy}, + remark = #{remark}, + shelf_life = #{shelfLife}, + production_date = #{productionDate}, + approaching = #{approaching}, + update_time = sysdate() + + where product_bar_code = #{productBarCode} + + + + delete + from sys_config + where config_id = #{configId} + + + + delete from sys_config where config_id in + + #{configId} + + + + + update mall_product_store + set del_flag = '2' + where id = #{id} + + + + UPDATE mall_product_store + SET del_flag = 2 + WHERE id IN + + #{id} + + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/mapper/commodity/StoreMapper.xml b/ruoyi-mall/src/main/resources/mapper/commodity/StoreMapper.xml new file mode 100644 index 00000000..d26a70e6 --- /dev/null +++ b/ruoyi-mall/src/main/resources/mapper/commodity/StoreMapper.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + select store_id, + store_name, + store_code, + province, + city, + district, + full_address, + contact_phone, + store_manager, + create_by, + create_time, + update_by, + update_time, + remark + from mall_store + + + + + + + + + + insert into mall_store ( + store_name, + store_code, + province, + city, + district, + full_address, + contact_phone, + store_manager, + create_by, + remark, + create_time + )values( + #{storeName}, + #{storeCode}, + #{province}, + #{city}, + #{district}, + #{fullAddress}, + #{contactPhone}, + #{storeManager}, + #{createBy}, + #{remark}, + sysdate() + ) + + + + INSERT INTO mall_user_store(user_id, store_id) + VALUES + + (#{userId}, #{storeId}) + + + + + + update mall_store + + store_name = #{storeName}, + store_code = #{storeCode}, + province = #{province}, + city = #{city}, + district = #{district}, + full_address = #{fullAddress}, + contact_phone = #{contactPhone}, + store_manager = #{storeManager}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where store_id = #{storeId} + + + + update mall_store + set del_flag = '2' + where store_id = #{storeId} + + + + delete + from mall_user_store + where user_id = #{userId} + + + + delete + from mall_user_store + where store_id = #{storeId} + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/mapper/commodity/UserStoreMapper.xml b/ruoyi-mall/src/main/resources/mapper/commodity/UserStoreMapper.xml new file mode 100644 index 00000000..e339f680 --- /dev/null +++ b/ruoyi-mall/src/main/resources/mapper/commodity/UserStoreMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-mall/src/main/resources/mybatis/mybatis-config.xml b/ruoyi-mall/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 00000000..ac47c038 --- /dev/null +++ b/ruoyi-mall/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html index 56fd45b3..fde27bbe 100644 --- a/ruoyi-ui/public/index.html +++ b/ruoyi-ui/public/index.html @@ -14,7 +14,7 @@ #app { height: 100%; margin: 0px; - padding: 0px; + padding: 0px; } .chromeframe { margin: 0.2em 0; diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index a6bfb3b8..2fc5132f 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -1,136 +1,136 @@ -'use strict' -const path = require('path') - -function resolve(dir) { - return path.join(__dirname, dir) -} - -const CompressionPlugin = require('compression-webpack-plugin') - -const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 - -const baseUrl = 'http://localhost:8080' // 后端接口 - -const port = process.env.port || process.env.npm_config_port || 80 // 端口 - -// vue.config.js 配置说明 -//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions -// 这里只列一部分,具体配置参考文档 -module.exports = { - // 部署生产环境和开发环境下的URL。 - // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 - // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 - publicPath: process.env.NODE_ENV === "production" ? "/" : "/", - // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) - outputDir: 'dist', - // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) - assetsDir: 'static', - // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 - productionSourceMap: false, - transpileDependencies: ['quill'], - // webpack-dev-server 相关配置 - devServer: { - host: '0.0.0.0', - port: port, - open: true, - proxy: { - // detail: https://cli.vuejs.org/config/#devserver-proxy - [process.env.VUE_APP_BASE_API]: { - target: baseUrl, - changeOrigin: true, - pathRewrite: { - ['^' + process.env.VUE_APP_BASE_API]: '' - } - }, - // springdoc proxy - '^/v3/api-docs/(.*)': { - target: baseUrl, - changeOrigin: true - } - }, - disableHostCheck: true - }, - css: { - loaderOptions: { - sass: { - sassOptions: { outputStyle: "expanded" } - } - } - }, - configureWebpack: { - name: name, - resolve: { - alias: { - '@': resolve('src') - } - }, - plugins: [ - // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 - new CompressionPlugin({ - cache: false, // 不启用文件缓存 - test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式 - filename: '[path][base].gz[query]', // 压缩后的文件名 - algorithm: 'gzip', // 使用gzip压缩 - minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩 - deleteOriginalAssets: false // 压缩后删除原文件 - }) - ], - }, - chainWebpack(config) { - config.plugins.delete('preload') // TODO: need test - config.plugins.delete('prefetch') // TODO: need test - - // set svg-sprite-loader - config.module - .rule('svg') - .exclude.add(resolve('src/assets/icons')) - .end() - config.module - .rule('icons') - .test(/\.svg$/) - .include.add(resolve('src/assets/icons')) - .end() - .use('svg-sprite-loader') - .loader('svg-sprite-loader') - .options({ - symbolId: 'icon-[name]' - }) - .end() - - config.when(process.env.NODE_ENV !== 'development', config => { - config - .plugin('ScriptExtHtmlWebpackPlugin') - .after('html') - .use('script-ext-html-webpack-plugin', [{ - // `runtime` must same as runtimeChunk name. default is `runtime` - inline: /runtime\..*\.js$/ - }]) - .end() - - config.optimization.splitChunks({ - chunks: 'all', - cacheGroups: { - libs: { - name: 'chunk-libs', - test: /[\\/]node_modules[\\/]/, - priority: 10, - chunks: 'initial' // only package third parties that are initially dependent - }, - elementUI: { - name: 'chunk-elementUI', // split elementUI into a single package - test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm - priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app - }, - commons: { - name: 'chunk-commons', - test: resolve('src/components'), // can customize your rules - minChunks: 3, // minimum common number - priority: 5, - reuseExistingChunk: true - } - } - }) - config.optimization.runtimeChunk('single') - }) - } -} +'use strict' +const path = require('path') + +function resolve(dir) { + return path.join(__dirname, dir) +} + +const CompressionPlugin = require('compression-webpack-plugin') + +const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 + +const baseUrl = 'http://193.112.94.36:8080' // 后端接口 + +const port = process.env.port || process.env.npm_config_port || 80 // 端口 + +// vue.config.js 配置说明 +//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions +// 这里只列一部分,具体配置参考文档 +module.exports = { + // 部署生产环境和开发环境下的URL。 + // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 + // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 + publicPath: process.env.NODE_ENV === "production" ? "/" : "/", + // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) + outputDir: 'dist', + // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) + assetsDir: 'static', + // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 + productionSourceMap: false, + transpileDependencies: ['quill'], + // webpack-dev-server 相关配置 + devServer: { + host: '0.0.0.0', + port: 8087, + open: true, + proxy: { + // detail: https://cli.vuejs.org/config/#devserver-proxy + [process.env.VUE_APP_BASE_API]: { + target: baseUrl, + changeOrigin: true, + pathRewrite: { + ['^' + process.env.VUE_APP_BASE_API]: '' + } + }, + // springdoc proxy + '^/v3/api-docs/(.*)': { + target: baseUrl, + changeOrigin: true + } + }, + disableHostCheck: true + }, + css: { + loaderOptions: { + sass: { + sassOptions: { outputStyle: "expanded" } + } + } + }, + configureWebpack: { + name: name, + resolve: { + alias: { + '@': resolve('src') + } + }, + plugins: [ + // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 + new CompressionPlugin({ + cache: false, // 不启用文件缓存 + test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式 + filename: '[path][base].gz[query]', // 压缩后的文件名 + algorithm: 'gzip', // 使用gzip压缩 + minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩 + deleteOriginalAssets: false // 压缩后删除原文件 + }) + ], + }, + chainWebpack(config) { + config.plugins.delete('preload') // TODO: need test + config.plugins.delete('prefetch') // TODO: need test + + // set svg-sprite-loader + config.module + .rule('svg') + .exclude.add(resolve('src/assets/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/assets/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + .end() + + config.when(process.env.NODE_ENV !== 'development', config => { + config + .plugin('ScriptExtHtmlWebpackPlugin') + .after('html') + .use('script-ext-html-webpack-plugin', [{ + // `runtime` must same as runtimeChunk name. default is `runtime` + inline: /runtime\..*\.js$/ + }]) + .end() + + config.optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial' // only package third parties that are initially dependent + }, + elementUI: { + name: 'chunk-elementUI', // split elementUI into a single package + test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm + priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app + }, + commons: { + name: 'chunk-commons', + test: resolve('src/components'), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }) + config.optimization.runtimeChunk('single') + }) + } +}