[
  {
    "path": ".gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n.DS_Store\n*.DS_Store\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n!**/src/main/**/build/\n!**/src/test/**/build/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "README.md",
    "content": "## SpringBoot + Vue 的物流管理系统\n\n#### 主要框架\n- SpringBoot\n\n- SpringData\n\n- SpringSecurity\n\n- Vue2"
  },
  {
    "path": "api/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n.DS_Store\n*.DS_Store\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n!**/src/main/**/build/\n!**/src/test/**/build/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "api/README.md",
    "content": "## SpringBoot + Vue 的物流管理系统\n\n#### 主要框架\n- SpringBoot\n\n- SpringData\n\n- SpringSecurity\n\n- Vue2"
  },
  {
    "path": "api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.example</groupId>\n    <artifactId>api</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.4.2</version>\n    </parent>\n\n    <properties>\n        <java.version>11</java.version>\n        <jwt.version>0.9.1</jwt.version>\n        <mybatis-plus.version>3.4.2</mybatis-plus.version>\n        <fastjson.version>1.2.73</fastjson.version>\n        <mybatis-enhance-actable.version>1.4.7.RELEASE</mybatis-enhance-actable.version>\n    </properties>\n\n    <dependencies>\n\n        <!--SpringBoot依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!--SpringData依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n\n        <!--SpringSecurity依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n\n        <!--Email邮箱发送依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-mail</artifactId>\n        </dependency>\n\n        <!--jwt依赖-->\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>${jwt.version}</version>\n        </dependency>\n\n        <!--mysql驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--lombok-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <!--json工具-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>${fastjson.version}</version>\n        </dependency>\n\n\n        <!--jdk9以上缺失的jar包-->\n        <dependency>\n            <groupId>javax.xml.bind</groupId>\n            <artifactId>jaxb-api</artifactId>\n            <version>2.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.sun.xml.bind</groupId>\n            <artifactId>jaxb-impl</artifactId>\n            <version>2.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.sun.xml.bind</groupId>\n            <artifactId>jaxb-core</artifactId>\n            <version>2.3.0</version>\n        </dependency>\n        <dependency>\n            <groupId>javax.activation</groupId>\n            <artifactId>activation</artifactId>\n            <version>1.1.1</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <!--更换阿里云maven镜像-->\n    <repositories>\n        <repository>\n            <id>maven-ali</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public//</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n                <updatePolicy>always</updatePolicy>\n                <checksumPolicy>fail</checksumPolicy>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "api/src/main/java/com/example/api/ApiApplication.java",
    "content": "package com.example.api;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ApiApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ApiApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/annotation/DisableBaseResponse.java",
    "content": "package com.example.api.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 加上注解后不统一封装返回\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface DisableBaseResponse {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/AdminController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.dto.LoginDto;\nimport com.example.api.model.entity.Admin;\nimport com.example.api.model.enums.Role;\nimport com.example.api.repository.AdminRepository;\nimport com.example.api.service.AdminService;\nimport com.example.api.utils.JwtTokenUtil;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/api/admin\")\npublic class AdminController {\n\n    @Resource\n    private AdminService adminService;\n\n    @Resource\n    private AdminRepository adminRepository;\n\n    @GetMapping(\"hasInit\")\n    public boolean hasInit() {\n        return adminRepository.existsAdminByRoles(Role.ROLE_SUPER_ADMIN.getValue());\n    }\n\n    @PostMapping(\"/init\")\n    public Admin init(@RequestBody Admin admin) throws Exception {\n        if (adminRepository.existsAdminByRoles(Role.ROLE_SUPER_ADMIN.getValue())) throw new Exception(\"初始化请求错误\");\n        admin.setRoles(Role.ROLE_SUPER_ADMIN.getValue());\n        return adminService.save(admin);\n    }\n\n    @GetMapping(\"\")\n    @PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_ADMIN')\")\n    public List<Admin> findAll() {\n        return adminService.findAll();\n    }\n\n    @DeleteMapping(\"\")\n    @PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_ADMIN')\")\n    public void delete(String id) {\n        adminService.delete(id);\n    }\n\n    @PostMapping(\"\")\n    @PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_ADMIN')\")\n    public Admin save(@RequestBody Admin admin) throws Exception {\n        return adminService.save(admin);\n    }\n\n    @PostMapping(\"/login\")\n    public Map<String, Object> loginByEmail(String type, @RequestBody LoginDto dto) throws Exception {\n        Map<String, Object> map = new HashMap<>();\n        Admin admin = type.equals(\"email\") ? adminService.loginByEmail(dto) : adminService.loginByPassword(dto);\n        String token = adminService.createToken(admin,\n                dto.isRemember() ? JwtTokenUtil.REMEMBER_EXPIRATION_TIME : JwtTokenUtil.EXPIRATION_TIME);\n        map.put(\"admin\", admin);\n        map.put(\"token\", token);\n        return map;\n    }\n\n    @GetMapping(\"/sendEmail\")\n    public void sendEmail(String email) throws Exception {\n        adminService.sendEmail(email);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/CommodityController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Commodity;\nimport com.example.api.service.CommodityService;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/commodity\")\n@PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_COMMODITY')\")\npublic class CommodityController {\n\n    @Resource\n    private CommodityService commodityService;\n\n    @PostMapping(\"\")\n    public Commodity save(@RequestBody Commodity commodity) {\n        return commodityService.save(commodity);\n    }\n\n    @DeleteMapping(\"\")\n    public void delete(String id) {\n        commodityService.delete(id);\n    }\n\n    @PutMapping(\"\")\n    public void update(@RequestBody Commodity commodity) {\n        commodityService.update(commodity);\n    }\n\n    @GetMapping(\"\")\n    public List<Commodity> findAll() {\n        return commodityService.findAll();\n    }\n\n    @GetMapping(\"/search/{name}\")\n    public List<Commodity> findByLikeName(@PathVariable String name) {\n        return commodityService.findAllByLikeName(name);\n    }\n\n    @GetMapping(\"/{id}\")\n    public Commodity findById(@PathVariable String id) {\n        return commodityService.findById(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/DistributionController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Distribution;\nimport com.example.api.repository.DriverRepository;\nimport com.example.api.repository.VehicleRepository;\nimport com.example.api.service.DistributionService;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/api/distribution\")\npublic class DistributionController {\n\n    @Resource\n    private DistributionService distributionService;\n\n    @Resource\n    private DriverRepository driverRepository;\n\n    @Resource\n    private VehicleRepository vehicleRepository;\n\n    @PostMapping(\"\")\n    public Distribution save(@RequestBody Distribution distribution) throws Exception {\n        return distributionService.save(distribution);\n    }\n\n    @GetMapping(\"\")\n    public List<Distribution> findAll() {\n        return distributionService.findAll();\n    }\n\n    @GetMapping(\"can\")\n    public Map<String, Object> can() {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"drivers\", driverRepository.findAll());\n        map.put(\"vehicles\", vehicleRepository.findAll());\n        return map;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/DriverController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Driver;\nimport com.example.api.service.DriverService;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/driver\")\npublic class DriverController {\n\n    @Resource\n    private DriverService driverService;\n\n    @PostMapping(\"\")\n    public Driver save(@RequestBody Driver driver) {\n        return driverService.save(driver);\n    }\n\n    @GetMapping(\"\")\n    public List<Driver> findAll() {\n        return driverService.findAll();\n    }\n\n    @GetMapping(\"/{id}\")\n    public Driver findById(@PathVariable String id) {\n        return driverService.findById(id);\n    }\n\n    @DeleteMapping(\"\")\n    public void delete(String id) {\n        driverService.delete(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/EmailController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.utils.RandomUtil;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.mail.MailException;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\n\n@RestController\n@RequestMapping(\"/api/email\")\npublic class EmailController {\n\n    @Resource\n    private JavaMailSender mailSender;\n\n    @Value(\"${spring.mail.username}\")\n    private String from;\n\n    @GetMapping(\"/send\")\n    public String send() {\n        SimpleMailMessage message = new SimpleMailMessage();\n        //发件人\n        message.setFrom(from);\n        //收件人\n        message.setTo(\"1729677089@qq.com\");\n        message.setSubject(\"验证码\");\n        message.setText(\"你的验证码为:  \" + RandomUtil.next() + \"  十五分钟内有效\");\n        try {\n            mailSender.send(message);\n            return \"发送普通邮件成功\";\n        } catch (MailException e) {\n            e.printStackTrace();\n            return \"邮件方失败\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/EmployeeController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Employee;\nimport com.example.api.service.EmployeeService;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/employee\")\n@PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_EMPLOYEE')\")\npublic class EmployeeController {\n\n    @Resource\n    private EmployeeService employeeService;\n\n    @GetMapping(\"\")\n    public List<Employee> findAll() {\n        return employeeService.findAll();\n    }\n\n    @GetMapping(\"/{id}\")\n    public Employee findById(@PathVariable String id) {\n        return employeeService.findById(id);\n    }\n\n    @PostMapping(\"\")\n    public Employee save(@RequestBody Employee employee) {\n        return employeeService.save(employee);\n    }\n\n    @PutMapping(\"\")\n    public void update(@RequestBody Employee employee) {\n        employeeService.update(employee);\n    }\n\n    @DeleteMapping(\"\")\n    public void delete(String id) {\n        employeeService.delete(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/InventoryController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Inventory;\nimport com.example.api.model.entity.InventoryRecord;\nimport com.example.api.model.vo.CommodityChartVo;\nimport com.example.api.service.InventoryRecordService;\nimport com.example.api.service.InventoryService;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/inventory\")\npublic class InventoryController {\n\n    @Resource\n    private InventoryService inventoryService;\n\n    @Resource\n    private InventoryRecordService recordService;\n\n    @GetMapping(\"\")\n    public List<Inventory> findAll() {\n        return inventoryService.findAll();\n    }\n\n    @GetMapping(\"analyze\")\n    public List<CommodityChartVo> analyze(Integer type) {\n        return recordService.analyzeCommodity(type);\n    }\n\n    //指定仓库id\n    //查询某个仓库的库存情况\n    @GetMapping(\"/warehouse/{id}\")\n    public List<Inventory> findByWarehouse(@PathVariable String id) {\n        return inventoryService.findByWarehouseId(id);\n    }\n\n    //指定商品id\n    //查询某个商品在所有仓库的库存\n    @GetMapping(\"/commodity/{id}\")\n    public List<Inventory> findByCommodity(@PathVariable String id) {\n        return inventoryService.findByCommodityId(id);\n    }\n\n    //指定仓库id\n    //查询某个仓库库内商品的出库入库记录\n    @GetMapping(\"/record/warehouse/{id}\")\n    public List<InventoryRecord> findRecordByWarehouse(@PathVariable String id) {\n        return recordService.findAllByWarehouseId(id);\n    }\n\n    //指定商品id\n    //查询某个商品在所有仓库出库入库记录\n    @GetMapping(\"/record/commodity/{id}\")\n    public List<InventoryRecord> findRecordByCommodity(@PathVariable String id) {\n        return recordService.findAllByCommodityId(id);\n    }\n\n    @PostMapping(\"/in\")\n    public InventoryRecord in(@RequestBody InventoryRecord record) throws Exception {\n        return recordService.in(record);\n    }\n\n    @PostMapping(\"/out\")\n    public InventoryRecord out(@RequestBody InventoryRecord record) throws Exception {\n        return recordService.out(record);\n    }\n\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/RoleController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.enums.Role;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"/api/role\")\npublic class RoleController {\n\n    @GetMapping(\"\")\n    public Role[] list() {\n        return Role.ROLES;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/SaleController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Sale;\nimport com.example.api.service.SaleService;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/sale\")\n@PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_SALE')\")\npublic class SaleController {\n\n    @Resource\n    private SaleService saleService;\n\n    @PostMapping(\"\")\n    public Sale save(@RequestBody Sale sale) {\n        return saleService.save(sale);\n    }\n\n    @GetMapping(\"\")\n    public List<Sale> findAll() {\n        return saleService.findAll();\n    }\n\n    @GetMapping(\"/search/{name}\")\n    public List<Sale> search(@PathVariable String name) {\n        return saleService.searchByCompany(name);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/UserController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.User;\nimport com.example.api.repository.UserRepository;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\n\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private UserRepository userRepository;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/VehicleController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.annotation.DisableBaseResponse;\nimport com.example.api.model.entity.Vehicle;\nimport com.example.api.service.VehicleService;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/vehicle\")\npublic class VehicleController {\n\n    @Resource\n    private VehicleService vehicleService;\n\n    @PostMapping(\"\")\n    public Vehicle save(@RequestBody Vehicle vehicle) {\n        return vehicleService.save(vehicle);\n    }\n\n    @GetMapping(\"\")\n    public List<Vehicle> findAll() {\n        return vehicleService.findAll();\n    }\n\n    @GetMapping(\"/{id}\")\n    public Vehicle findById(@PathVariable String id) {\n        return vehicleService.findById(id);\n    }\n\n    @DeleteMapping(\"\")\n    public void delete(String id) {\n        vehicleService.delete(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/controller/WarehouseController.java",
    "content": "package com.example.api.controller;\n\nimport com.example.api.model.entity.Warehouse;\nimport com.example.api.service.WarehouseService;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/api/warehouse\")\n@PreAuthorize(\"hasAnyRole('ROLE_SUPER_ADMIN' ,'ROLE_WAREHOUSE')\")\npublic class WarehouseController {\n\n    @Resource\n    private WarehouseService warehouseService;\n\n    @PostMapping(\"\")\n    public Warehouse save(@RequestBody Warehouse warehouse) {\n        return warehouseService.save(warehouse);\n    }\n\n    @GetMapping(\"\")\n    public List<Warehouse> findAll() {\n        return warehouseService.findAll();\n    }\n\n    @DeleteMapping(\"\")\n    public void delete(String id) {\n        warehouseService.delete(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/handler/GlobalExceptionHandler.java",
    "content": "package com.example.api.handler;\n\nimport com.example.api.model.support.ResponseResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\n/**\n * 捕获controller异常\n * controller抛出异常执行下边的函数\n * 返回Response写入ApiResult\n */\n@ResponseBody\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    private final Logger logger = LoggerFactory.getLogger(getClass());\n\n    @ExceptionHandler(value = Exception.class)\n    public Object handleException(Exception e) {\n        if (e.getClass().equals(AccessDeniedException.class)) {\n            return new ResponseResult<>(403, \"你没有访问权限\");\n        }\n        logger.warn(e.getMessage());\n        return new ResponseResult<>(400, e.getMessage());\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/handler/GlobalResponseHandler.java",
    "content": "package com.example.api.handler;\n\nimport com.example.api.annotation.DisableBaseResponse;\nimport com.example.api.model.support.ResponseResult;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;\n\n/**\n * 统一拦截Controller中所有方法的返回值\n * 封装后返回ResponseResult<T>\n */\n@ControllerAdvice(value = \"com.example.api.controller\")\npublic class GlobalResponseHandler implements ResponseBodyAdvice<Object> {\n\n\n    @Override\n    public boolean supports(MethodParameter methodParameter, Class c) {\n        return !methodParameter.hasParameterAnnotation(DisableBaseResponse.class);\n    }\n\n    @Override\n    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass,\n                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {\n        return o == null ? new ResponseResult<>() : new ResponseResult<>(o);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/dto/LoginDto.java",
    "content": "package com.example.api.model.dto;\n\nimport lombok.Data;\n\n/**\n * 登录传输数据\n */\n@Data\npublic class LoginDto {\n\n    private String email;\n\n    private String password;\n\n    private String code;\n\n    private boolean remember;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Admin.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 管理员\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Admin {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String email;\n\n    private String password;\n\n    private String roles;\n\n    private String createAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Code.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 验证码\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Code {\n\n    @Id\n    private String email;\n\n    private String value;\n\n    private long exp;\n\n    public Code(String email, String value) {\n        this.email = email;\n        this.value = value;\n        this.exp = System.currentTimeMillis() + 1000 * 60 * 15;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Commodity.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 商品\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Commodity {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String name;\n\n    private double price;\n\n    private String description;\n\n    private int count;\n\n    private String createAt;\n\n    private String updateAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Company.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 往来公司\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Company {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Distribution.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 配送\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Distribution {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    //司机id\n    private String did;\n\n    //车辆id\n    private String vid;\n\n    //司机\n    private String driver;\n\n    //车牌号\n    private String number;\n\n    //客户电话\n    private String phone;\n\n    //客户地址\n    private String address;\n\n    //加急处理\n    private boolean urgent;\n\n    private String care;\n\n    private String time;\n\n    private Integer status;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Driver.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 驾驶员\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Driver {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String name;\n\n    private String gender;\n\n    private String phone;\n\n    //家庭住址\n    private String address;\n\n    //身份证号码\n    private String idCard;\n\n    //驾驶证\n    private String license;\n\n    //驾驶证分数 12分\n    private String score;\n\n    //正在驾驶\n    private boolean driving;\n\n    private String createAt;\n\n    private String updateAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Employee.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 员工\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Employee {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String name;\n\n    private String gender;\n\n    private String phone;\n\n    //家庭住址\n    private String address;\n\n    //身份证号码\n    private String idCard;\n\n    //部门\n    private String department;\n\n    private String createAt;\n\n    private String updateAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Inventory.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 库存\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Inventory {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    //仓库id\n    private String wid;\n\n    //商品信息id\n    private String cid;\n\n    //商品名\n    private String name;\n\n    //所在位置区域\n    private String location;\n\n    //数量\n    private Integer count;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/InventoryRecord.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 库存记录 出库 入库\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class InventoryRecord {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    //商品名\n    private String name;\n\n    //仓库id\n    private String wid;\n\n    //商品信息id\n    private String cid;\n\n    private Integer count;\n\n    //-1:出库 +1:入库\n    private Integer type;\n\n    //描述信息\n    private String description;\n\n    private String createAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Sale.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 销售\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Sale {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String company;\n\n    private String number;\n\n    private String commodity;\n\n    private String count;\n\n    private double price;\n\n    private String phone;\n\n    private String description;\n\n    private boolean pay;\n\n    private String createAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/User.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 用户\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class User {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    private String username;\n\n    private String password;\n\n    private String createAt;\n\n    private String updateAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Vehicle.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 车辆\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Vehicle {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    //车牌号\n    private String number;\n\n    //车辆类型\n    private String type;\n\n    //是否正在运输\n    private boolean driving;\n\n    private String createAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/entity/Warehouse.java",
    "content": "package com.example.api.model.entity;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n/**\n * 仓库\n */\n@Data\n@Entity\n@NoArgsConstructor\npublic class Warehouse {\n\n    @Id\n    @GeneratedValue(generator = \"uuid2\")\n    @GenericGenerator(name = \"uuid2\", strategy = \"org.hibernate.id.UUIDGenerator\")\n    private String id;\n\n    //仓库名称\n    private String name;\n\n    //仓库负责人\n    private String principle;\n\n    private String createAt;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/enums/DistributionStatus.java",
    "content": "package com.example.api.model.enums;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * 配送单状态\n */\npublic enum DistributionStatus {\n\n    //正在审核\n    REVIEWING(0),\n\n    //审核成功\n    REVIEW_SUCCESS(1),\n\n    //订单完成\n    END(2);\n\n    @Getter\n    @Setter\n    private Integer code;\n\n    DistributionStatus(Integer code) {\n        this.code = code;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/enums/Role.java",
    "content": "package com.example.api.model.enums;\n\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport lombok.Getter;\n\n@Getter\n@JsonFormat(shape = JsonFormat.Shape.OBJECT)\npublic enum Role {\n\n    //超级管理员 不对外提供添加此权限的方法\n    ROLE_SUPER_ADMIN(\"ROLE_SUPER_ADMIN\", \"超级管理员\"),\n\n    ROLE_ADMIN(\"ROLE_ADMIN\", \"操作员相关权限\"),\n\n    ROLE_COMMODITY(\"ROLE_COMMODITY\", \"商品相关权限\"),\n\n    ROLE_EMPLOYEE(\"ROLE_EMPLOYEE\", \"员工相关权限\"),\n\n    ROLE_SALE(\"ROLE_SALE\", \"销售相关权限\"),\n\n    ROLE_WAREHOUSE(\"ROLE_WAREHOUSE\", \"仓库相关权限\");\n\n    private final String value;\n\n    private final String description;\n\n    public static final Role[] ROLES = {\n            ROLE_ADMIN,\n            ROLE_COMMODITY,\n            ROLE_EMPLOYEE,\n            ROLE_SALE,\n            ROLE_WAREHOUSE\n    };\n\n    Role(String value, String description) {\n        this.value = value;\n        this.description = description;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/support/ResponseResult.java",
    "content": "package com.example.api.model.support;\n\nimport lombok.Data;\n\n@Data\npublic class ResponseResult<T> {\n\n    private Integer code;\n\n    private boolean status;\n\n    private String msg;\n\n    private T data;\n\n    public ResponseResult() {\n        this.code = 200;\n        this.status = true;\n        this.msg = null;\n        this.data = null;\n    }\n\n    //不附带msg返回数据\n    public ResponseResult(T data) {\n        this.code = 200;\n        this.status = true;\n        this.msg = null;\n        this.data = data;\n    }\n\n    //默认附带msg和data\n    public ResponseResult(String msg, T data) {\n        this.code = 200;\n        this.status = true;\n        this.msg = msg;\n        this.data = data;\n    }\n\n    //默认的错误返回\n    public ResponseResult(Integer code, String msg) {\n        this.code = code;\n        this.status = false;\n        this.msg = msg;\n        this.data = null;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/model/vo/CommodityChartVo.java",
    "content": "package com.example.api.model.vo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\n\n@Data\n@AllArgsConstructor\npublic class CommodityChartVo {\n\n    //商品名\n    private Integer value;\n\n    //数量\n    private String name;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/AdminRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Admin;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface AdminRepository extends JpaRepository<Admin, String> {\n\n    Admin findAdminByEmailAndPassword(String email, String password);\n\n    Admin findAdminByEmail(String email);\n\n    boolean existsAdminByRoles(String roles);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/CodeRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Code;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CodeRepository extends JpaRepository<Code, String> {\n\n    Code findByEmailAndValue(String email, String value);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/CommodityRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Commodity;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface CommodityRepository extends JpaRepository<Commodity, String> {\n\n    Commodity findByName(String name);\n\n    List<Commodity> findByNameLike(String name);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/DistributionRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Distribution;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface DistributionRepository extends JpaRepository<Distribution, String> {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/DriverRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Driver;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Modifying;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\n\n@Repository\npublic interface DriverRepository extends JpaRepository<Driver, String> {\n\n    @Modifying\n    @Transactional\n    @Query(\"update Driver d set d.driving = ?1 where d.id = ?2\")\n    void updateDriving(boolean driving, String id);\n\n    List<Driver> findAllByDriving(boolean driving);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/EmployeeRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Employee;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface EmployeeRepository extends JpaRepository<Employee, String> {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/InventoryRecordRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.InventoryRecord;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface InventoryRecordRepository extends JpaRepository<InventoryRecord, String> {\n\n    List<InventoryRecord> findAllByWid(String wid);\n\n    List<InventoryRecord> findAllByType(Integer type);\n\n    List<InventoryRecord> findAllByCid(String cid);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/InventoryRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Inventory;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface InventoryRepository extends JpaRepository<Inventory, String> {\n\n    Inventory findByWidAndCid(String wid, String cid);\n\n    List<Inventory> findAllByCid(String cid);\n\n    List<Inventory> findAllByWid(String wid);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/SaleRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Sale;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface SaleRepository extends JpaRepository<Sale, String> {\n\n    List<Sale> findAllByCompanyLike(String name);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/UserRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.User;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface UserRepository extends JpaRepository<User, String> {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/VehicleRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Vehicle;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Modifying;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\n\n@Repository\npublic interface VehicleRepository extends JpaRepository<Vehicle, String> {\n\n    @Modifying\n    @Transactional\n    @Query(\"update Vehicle v set v.driving = ?1 where v.id = ?2\")\n    void updateDriving(boolean driving, String id);\n\n    List<Vehicle> findAllByDriving(boolean driving);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/repository/WareHouseRepository.java",
    "content": "package com.example.api.repository;\n\nimport com.example.api.model.entity.Warehouse;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface WareHouseRepository extends JpaRepository<Warehouse, String> {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/security/JwtAuthorizationFilter.java",
    "content": "package com.example.api.security;\n\nimport com.example.api.model.support.ResponseResult;\nimport com.example.api.utils.JwtTokenUtil;\nimport com.example.api.utils.ResponseUtil;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.web.authentication.www.BasicAuthenticationFilter;\n\nimport javax.servlet.FilterChain;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 从Request的Authorization Header 获取Jwt\n * 解析Jwt授权发放token\n */\npublic class JwtAuthorizationFilter extends BasicAuthenticationFilter {\n\n    public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {\n        super(authenticationManager);\n    }\n\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)\n            throws IOException, ServletException {\n\n        //从Request Header 取出Token\n        String token = request.getHeader(JwtTokenUtil.TOKEN_HEADER);\n\n        //Token为空放行\n        //如果接下来进入的URL不是公共的地址SpringSecurity会返回403的错误\n        if (!JwtTokenUtil.checkToken(token)){\n            chain.doFilter(request, response);\n            return;\n        }\n\n        //判断JWT Token是否过期\n        if (JwtTokenUtil.isExpiration(token)) {\n            ResponseUtil.writeJson(response, new ResponseResult<>(403, \"令牌已过期, 请重新登录\"));\n            return;\n        }\n\n        //解析token\n        String username = JwtTokenUtil.getUsername(token);\n        List<String> tokenRoles = JwtTokenUtil.getTokenRoles(token);\n        ArrayList<SimpleGrantedAuthority> roles = new ArrayList<>();\n        for (String role : tokenRoles) {\n            roles.add(new SimpleGrantedAuthority(role));\n        }\n        //向SpringSecurity的Context中加入认证信息\n        SecurityContextHolder.getContext().setAuthentication(\n                new UsernamePasswordAuthenticationToken(username,null, roles));\n\n        super.doFilterInternal(request, response, chain);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/security/SecurityConfiguration.java",
    "content": "package com.example.api.security;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.CorsConfigurationSource;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\n\n@Configuration\n@EnableGlobalMethodSecurity(prePostEnabled = true)\npublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {\n\n    @Bean\n    public BCryptPasswordEncoder bCryptPasswordEncoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    /**\n     * HTTP验证规则\n     *\n     * @param http h\n     * @throws Exception e\n     */\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n\n        //开启跨域\n        http.csrf().disable().cors();\n\n        //禁用session\n        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);\n\n        //添加自定义的jwt过滤器\n        http.addFilter(new JwtAuthorizationFilter(authenticationManagerBean()));\n\n    }\n\n    /**\n     * SpringSecurity有默认的跨域配置 会无法放行RequestHeader带有\"Authorization\"请求\n     * 防止前端请求api报出cors error\n     *\n     * @return *\n     */\n    @Bean\n    CorsConfigurationSource corsConfigurationSource() {\n        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        final CorsConfiguration corsConfiguration = new CorsConfiguration();\n        corsConfiguration.addAllowedHeader(\"*\");\n        corsConfiguration.addAllowedHeader(\"DELETE\");\n        corsConfiguration.addAllowedMethod(\"*\");\n        corsConfiguration.addAllowedOrigin(\"*\");\n        source.registerCorsConfiguration(\"/**\", corsConfiguration);\n        return source;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/AdminService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.dto.LoginDto;\nimport com.example.api.model.entity.Admin;\n\nimport java.util.List;\n\npublic interface AdminService {\n\n    Admin save(Admin admin) throws Exception;\n\n    Admin findById(String id);\n\n    void sendEmail(String email) throws Exception;\n\n    Admin loginByPassword(LoginDto dto) throws Exception;\n\n    Admin loginByEmail(LoginDto dto) throws Exception;\n\n    List<Admin> findAll();\n\n    //生成token\n    String createToken(Admin admin, long exp);\n\n    void delete(String id);\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/CommodityService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Commodity;\n\nimport java.util.List;\n\npublic interface CommodityService {\n\n    Commodity save(Commodity commodity);\n\n    void update(Commodity commodity);\n\n    void delete(String id);\n\n    Commodity findById(String id);\n\n    List<Commodity> findAll();\n\n    List<Commodity> findAllByLikeName(String name);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/DistributionService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Distribution;\n\nimport java.util.List;\n\npublic interface DistributionService {\n\n    Distribution save(Distribution distribution) throws Exception;\n\n    List<Distribution> findAll();\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/DriverService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Driver;\n\nimport java.util.List;\n\npublic interface DriverService {\n\n    Driver save(Driver driver);\n\n    void update(Driver driver);\n\n    void delete(String id);\n\n    Driver findById(String id);\n\n    List<Driver> findAll();\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/EmailService.java",
    "content": "package com.example.api.service;\n\nimport org.springframework.mail.MailException;\n\npublic interface EmailService {\n\n    //发送验证码\n    void sendVerificationCode(String email) throws MailException;\n\n    //检验验证码\n    boolean checkVerificationCode(String email, String code);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/EmployeeService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Employee;\n\nimport java.util.List;\n\npublic interface EmployeeService {\n\n    Employee save(Employee employee);\n\n    void update(Employee employee);\n\n    void delete(String id);\n\n    Employee findById(String id);\n\n    List<Employee> findAll();\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/InventoryRecordService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.InventoryRecord;\nimport com.example.api.model.vo.CommodityChartVo;\n\nimport java.util.List;\n\npublic interface InventoryRecordService {\n\n    //出入库排行统计\n    List<CommodityChartVo> analyzeCommodity(Integer type);\n\n    List<InventoryRecord> findAllByWarehouseId(String wid);\n\n    List<InventoryRecord> findAllByCommodityId(String cid);\n\n    //出库\n    InventoryRecord out(InventoryRecord record) throws Exception;\n\n    //入库\n    InventoryRecord in(InventoryRecord record) throws Exception;\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/InventoryService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Inventory;\n\nimport java.util.List;\n\npublic interface InventoryService {\n\n    Inventory save(Inventory inventory);\n\n    List<Inventory> findAll();\n\n    List<Inventory> findByCommodityId(String cid);\n\n    List<Inventory> findByWarehouseId(String wid);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/SaleService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Sale;\n\nimport java.util.List;\n\npublic interface SaleService {\n\n    Sale save(Sale sale);\n\n    List<Sale> findAll();\n\n    List<Sale> searchByCompany(String name);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/UserService.java",
    "content": "package com.example.api.service;\n\npublic interface UserService {\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/VehicleService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Vehicle;\n\nimport java.util.List;\n\npublic interface VehicleService {\n\n    Vehicle save(Vehicle vehicle);\n\n    void update(Vehicle vehicle);\n\n    void delete(String id);\n\n    Vehicle findById(String id);\n\n    List<Vehicle> findAll();\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/WarehouseService.java",
    "content": "package com.example.api.service;\n\nimport com.example.api.model.entity.Warehouse;\n\nimport java.util.List;\n\npublic interface WarehouseService {\n\n    Warehouse save(Warehouse warehouse);\n\n    List<Warehouse> findAll();\n\n    void delete(String id);\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/AdminServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.dto.LoginDto;\nimport com.example.api.model.entity.Admin;\nimport com.example.api.repository.AdminRepository;\nimport com.example.api.service.AdminService;\nimport com.example.api.service.EmailService;\nimport com.example.api.utils.DataTimeUtil;\nimport com.example.api.utils.JwtTokenUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class AdminServiceImpl implements AdminService {\n\n    @Resource\n    private AdminRepository adminRepository;\n\n    @Resource\n    private EmailService emailService;\n\n    @Override\n    public Admin save(Admin admin) throws Exception {\n        if (admin.getEmail().length() < 8 || admin.getPassword().length() < 5) throw new Exception(\"请求参数异常\");\n        admin.setCreateAt(DataTimeUtil.getNowTimeString());\n        return adminRepository.save(admin);\n    }\n\n    @Override\n    public Admin findById(String id) {\n        return adminRepository.findById(id).orElse(null);\n    }\n\n    @Override\n    public void sendEmail(String email) throws Exception {\n        Admin admin = adminRepository.findAdminByEmail(email);\n        if (admin == null) throw new Exception(\"不存在的邮箱账户\");\n        emailService.sendVerificationCode(email);\n    }\n\n    @Override\n    public Admin loginByPassword(LoginDto dto) throws Exception {\n        Admin one = adminRepository.findAdminByEmailAndPassword(dto.getEmail(), dto.getPassword());\n        if (one == null) throw new Exception(\"用户名或密码错误\");\n        return one;\n    }\n\n    @Override\n    public Admin loginByEmail(LoginDto dto) throws Exception {\n        boolean status = emailService.checkVerificationCode(dto.getEmail(), dto.getCode());\n        if (!status) throw new Exception(\"验证码错误\");\n        return adminRepository.findAdminByEmail(dto.getEmail());\n    }\n\n    @Override\n    public List<Admin> findAll() {\n        return adminRepository.findAll();\n    }\n\n    @Override\n    public String createToken(Admin admin, long exp) {\n        String rolesString = admin.getRoles();\n        String[] roles = rolesString != null ? rolesString.split(\";\") : null;\n        return JwtTokenUtil.createToken(admin.getEmail(), roles, exp);\n    }\n\n    @Override\n    public void delete(String id) {\n        adminRepository.deleteById(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/CommodityServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Commodity;\nimport com.example.api.repository.CommodityRepository;\nimport com.example.api.service.CommodityService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class CommodityServiceImpl implements CommodityService {\n\n    @Resource\n    private CommodityRepository commodityRepository;\n\n    @Override\n    public Commodity save(Commodity commodity) {\n        commodity.setCreateAt(DataTimeUtil.getNowTimeString());\n        return commodityRepository.save(commodity);\n    }\n\n    @Override\n    public void update(Commodity commodity) {\n        commodity.setUpdateAt(DataTimeUtil.getNowTimeString());\n        commodityRepository.save(commodity);\n    }\n\n    @Override\n    public void delete(String id) {\n        commodityRepository.deleteById(id);\n    }\n\n    @Override\n    public Commodity findById(String id) {\n        return commodityRepository.findById(id).orElse(null);\n    }\n\n    @Override\n    public List<Commodity> findAll() {\n        return commodityRepository.findAll();\n    }\n\n    @Override\n    public List<Commodity> findAllByLikeName(String name) {\n        return commodityRepository.findByNameLike(\"%\" + name + \"%\");\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/DistributionServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Distribution;\nimport com.example.api.model.entity.Driver;\nimport com.example.api.model.entity.Vehicle;\nimport com.example.api.repository.DistributionRepository;\nimport com.example.api.repository.DriverRepository;\nimport com.example.api.repository.VehicleRepository;\nimport com.example.api.service.DistributionService;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\nimport java.util.Optional;\n\n@Service\npublic class DistributionServiceImpl implements DistributionService {\n\n    @Resource\n    private DistributionRepository distributionRepository;\n\n    @Resource\n    private DriverRepository driverRepository;\n\n    @Resource\n    private VehicleRepository vehicleRepository;\n\n    @Override\n    public Distribution save(Distribution distribution) throws Exception {\n        if (distributionRepository.findById(distribution.getId()).isEmpty()) {\n            Optional<Driver> driver = driverRepository.findById(distribution.getDid());\n            Optional<Vehicle> vehicle = vehicleRepository.findById(distribution.getVid());\n            if (driver.isEmpty() || vehicle.isEmpty()) throw new Exception(\"请求参数错误\");\n            if (driver.get().isDriving() || vehicle.get().isDriving()) throw new Exception(\"司机或货车状态不可用\");\n            driverRepository.updateDriving(true, distribution.getDid());\n            vehicleRepository.updateDriving(true, distribution.getVid());\n        }\n        return distributionRepository.save(distribution);\n    }\n\n    @Override\n    public List<Distribution> findAll() {\n        return distributionRepository.findAll();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/DriverServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Driver;\nimport com.example.api.repository.DriverRepository;\nimport com.example.api.service.DriverService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class DriverServiceImpl implements DriverService {\n\n    @Resource\n    private DriverRepository driverRepository;\n\n    @Override\n    public Driver save(Driver driver) {\n        driver.setCreateAt(DataTimeUtil.getNowTimeString());\n        return driverRepository.save(driver);\n    }\n\n    @Override\n    public void update(Driver driver) {\n        driver.setUpdateAt(DataTimeUtil.getNowTimeString());\n        driverRepository.save(driver);\n    }\n\n    @Override\n    public void delete(String id) {\n        driverRepository.deleteById(id);\n    }\n\n    @Override\n    public Driver findById(String id) {\n        return driverRepository.findById(id).orElse(null);\n    }\n\n    @Override\n    public List<Driver> findAll() {\n        return driverRepository.findAll();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/EmailServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Code;\nimport com.example.api.repository.CodeRepository;\nimport com.example.api.service.EmailService;\nimport com.example.api.utils.RandomUtil;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.mail.MailException;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\n\n@Service\npublic class EmailServiceImpl implements EmailService {\n\n    @Resource\n    private CodeRepository codeRepository;\n\n    @Resource\n    private JavaMailSender mailSender;\n\n    @Value(\"${spring.mail.username}\")\n    private String from;\n\n    @Override\n    public void sendVerificationCode(String email) throws MailException {\n        SimpleMailMessage message = new SimpleMailMessage();\n        message.setFrom(from);\n        message.setTo(email);\n        message.setSubject(\"验证码\");\n        String value = RandomUtil.next();\n        message.setText(\"你的验证码为:  \" + value + \"  十五分钟内有效\");\n        mailSender.send(message);\n        //保存验证码\n        //同一主键的email为update操作\n        codeRepository.save(new Code(email, value));\n    }\n\n    @Override\n    public boolean checkVerificationCode(String email, String value) {\n        Code code = codeRepository.findByEmailAndValue(email, value);\n        if (code != null && code.getExp() > System.currentTimeMillis()) {\n            //登陆成功删除验证码\n            codeRepository.delete(code);\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/EmployeeServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Employee;\nimport com.example.api.repository.EmployeeRepository;\nimport com.example.api.service.EmployeeService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class EmployeeServiceImpl implements EmployeeService {\n\n    @Resource\n    private EmployeeRepository employeeRepository;\n\n    @Override\n    public Employee save(Employee employee) {\n        employee.setCreateAt(DataTimeUtil.getNowTimeString());\n        return employeeRepository.save(employee);\n    }\n\n    @Override\n    public void update(Employee employee) {\n        employee.setUpdateAt(DataTimeUtil.getNowTimeString());\n        employeeRepository.save(employee);\n    }\n\n    @Override\n    public void delete(String id) {\n        employeeRepository.deleteById(id);\n    }\n\n    @Override\n    public Employee findById(String id) {\n        return employeeRepository.findById(id).orElse(null);\n    }\n\n    @Override\n    public List<Employee> findAll() {\n        return employeeRepository.findAll();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/InventoryRecordServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Commodity;\nimport com.example.api.model.entity.Inventory;\nimport com.example.api.model.entity.InventoryRecord;\nimport com.example.api.model.vo.CommodityChartVo;\nimport com.example.api.repository.CommodityRepository;\nimport com.example.api.repository.InventoryRecordRepository;\nimport com.example.api.repository.InventoryRepository;\nimport com.example.api.service.InventoryRecordService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.*;\n\n@Service\npublic class InventoryRecordServiceImpl implements InventoryRecordService {\n\n    @Resource\n    private InventoryRepository inventoryRepository;\n\n    @Resource\n    private CommodityRepository commodityRepository;\n\n    @Resource\n    private InventoryRecordRepository recordRepository;\n\n    @Override\n    public List<CommodityChartVo> analyzeCommodity(Integer type) {\n        List<CommodityChartVo> result = new ArrayList<>();\n        List<InventoryRecord> all = recordRepository.findAllByType(type);\n        Map<String, Integer> map = new HashMap<>();\n        for (InventoryRecord r : all) {\n            if (map.containsKey(r.getName())) {\n                map.put(r.getName(), map.get(r.getName()) + r.getCount());\n            } else {\n                map.put(r.getName(), r.getCount());\n            }\n        }\n        for (String key : map.keySet()) {\n            result.add(new CommodityChartVo(map.get(key), key));\n        }\n        return result;\n    }\n\n    @Override\n    public List<InventoryRecord> findAllByWarehouseId(String wid) {\n        return recordRepository.findAllByWid(wid);\n    }\n\n    @Override\n    public List<InventoryRecord> findAllByCommodityId(String cid) {\n        return recordRepository.findAllByCid(cid);\n    }\n\n    @Override\n    public InventoryRecord out(InventoryRecord record) throws Exception {\n\n        //查找当前商品在该仓库的库存\n        Inventory inventory = inventoryRepository.findByWidAndCid(record.getWid(), record.getCid());\n        //查询结果为空\n        if (inventory == null) throw new Exception(\"仓库内不存在该商品\");\n        //比较库存\n        if (inventory.getCount() < record.getCount()) throw new Exception(\"出库失败，库存数量不足\");\n\n        Optional<Commodity> optional = commodityRepository.findById(record.getCid());\n        if (optional.isEmpty()) {\n            throw new Exception(\"不存在的商品id\");\n        }\n        Commodity commodity = optional.get();\n        commodity.setCount(commodity.getCount() - record.getCount());\n        commodityRepository.save(optional.get());\n        inventory.setCount(inventory.getCount() - record.getCount());\n\n        inventoryRepository.save(inventory);\n        record.setCreateAt(DataTimeUtil.getNowTimeString());\n        record.setType(-1);\n        return recordRepository.save(record);\n    }\n\n    @Override\n    public InventoryRecord in(InventoryRecord record) throws Exception {\n        Optional<Commodity> optional = commodityRepository.findById(record.getCid());\n        if (optional.isEmpty()) {\n            throw new Exception(\"不存在的商品id\");\n        }\n        Commodity commodity = optional.get();\n        commodity.setCount(commodity.getCount() + record.getCount());\n        commodityRepository.save(optional.get());\n\n        //查找当前商品在该仓库的库存\n        Inventory inventory = inventoryRepository.findByWidAndCid(record.getWid(), record.getCid());\n        //查询结果为空\n        if (inventory == null) {\n            //新建该商品库存信息\n            inventory = new Inventory();\n            inventory.setCid(record.getCid());\n            inventory.setWid(record.getWid());\n            inventory.setCount(0);\n            inventory.setName(record.getName());\n        }\n        inventory.setCount(inventory.getCount() + record.getCount());\n        inventoryRepository.save(inventory);\n        record.setCreateAt(DataTimeUtil.getNowTimeString());\n        record.setType(+1);\n        return recordRepository.save(record);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/InventoryServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Inventory;\nimport com.example.api.repository.InventoryRepository;\nimport com.example.api.service.InventoryService;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class InventoryServiceImpl implements InventoryService {\n\n    @Resource\n    private InventoryRepository inventoryRepository;\n\n    @Override\n    public Inventory save(Inventory inventory) {\n        return inventoryRepository.save(inventory);\n    }\n\n    @Override\n    public List<Inventory> findAll() {\n        return inventoryRepository.findAll();\n    }\n\n    @Override\n    public List<Inventory> findByCommodityId(String cid) {\n        return inventoryRepository.findAllByCid(cid);\n    }\n\n    @Override\n    public List<Inventory> findByWarehouseId(String wid) {\n        return inventoryRepository.findAllByWid(wid);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/SaleServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Sale;\nimport com.example.api.repository.SaleRepository;\nimport com.example.api.service.SaleService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class SaleServiceImpl implements SaleService {\n\n    @Resource\n    private SaleRepository saleRepository;\n\n    @Override\n    public Sale save(Sale sale) {\n        sale.setCreateAt(DataTimeUtil.getNowTimeString());\n        return saleRepository.save(sale);\n    }\n\n    @Override\n    public List<Sale> findAll() {\n        return saleRepository.findAll();\n    }\n\n    @Override\n    public List<Sale> searchByCompany(String name) {\n        return saleRepository.findAllByCompanyLike(name);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/UserServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.service.UserService;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class UserServiceImpl implements UserService {\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/VehicleServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Vehicle;\nimport com.example.api.repository.VehicleRepository;\nimport com.example.api.service.VehicleService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class VehicleServiceImpl implements VehicleService {\n\n    @Resource\n    private VehicleRepository vehicleRepository;\n\n    @Override\n    public Vehicle save(Vehicle vehicle) {\n        vehicle.setCreateAt(DataTimeUtil.getNowTimeString());\n        return vehicleRepository.save(vehicle);\n    }\n\n    @Override\n    public void update(Vehicle vehicle) {\n        vehicleRepository.save(vehicle);\n    }\n\n    @Override\n    public void delete(String id) {\n        vehicleRepository.deleteById(id);\n    }\n\n    @Override\n    public Vehicle findById(String id) {\n        return vehicleRepository.findById(id).orElse(null);\n    }\n\n    @Override\n    public List<Vehicle> findAll() {\n        return vehicleRepository.findAll();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/service/impl/WarehouseServiceImpl.java",
    "content": "package com.example.api.service.impl;\n\nimport com.example.api.model.entity.Warehouse;\nimport com.example.api.repository.WareHouseRepository;\nimport com.example.api.service.WarehouseService;\nimport com.example.api.utils.DataTimeUtil;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\npublic class WarehouseServiceImpl implements WarehouseService {\n\n    @Resource\n    private WareHouseRepository wareHouseRepository;\n\n    @Override\n    public Warehouse save(Warehouse warehouse) {\n        warehouse.setCreateAt(DataTimeUtil.getNowTimeString());\n        return wareHouseRepository.save(warehouse);\n    }\n\n    @Override\n    public List<Warehouse> findAll() {\n        return wareHouseRepository.findAll();\n    }\n\n    @Override\n    public void delete(String id) {\n        wareHouseRepository.deleteById(id);\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/utils/DataTimeUtil.java",
    "content": "package com.example.api.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\n\npublic final class DataTimeUtil {\n\n    public static String getNowTimeString() {\n        SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        return df.format(System.currentTimeMillis());\n    }\n\n    public static long parseTimeStamp(String s) {\n        SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        long t = 0;\n        try {\n            t = df.parse(s).getTime();\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return t;\n    }\n\n    public static boolean isAfterNow(String time) {\n        SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");\n        long t = 0;\n        try {\n            t = df.parse(time).getTime();\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return t > System.currentTimeMillis();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/utils/JwtTokenUtil.java",
    "content": "package com.example.api.utils;\n\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.ExpiredJwtException;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\n\nimport java.util.*;\n\npublic final class JwtTokenUtil {\n\n    //在http header中的名字\n    public final static String TOKEN_HEADER = \"Authorization\";\n\n    //一个星期过期\n    public final static long REMEMBER_EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 7;\n\n    //一天过期\n    public final static long EXPIRATION_TIME = 1000 * 60 * 60 * 24;\n\n    // 应用密钥\n    private static final String APP_SECRET = \"logistics.api\";\n\n    private static final String PREFIX = \"logistics:\";\n\n    // 角色权限声明\n    private static final String ROLE_CLAIMS = \"roles\";\n\n    //检验token是否合法\n    public static boolean checkToken(String token) {\n        if (\"null\".equals(token) || token == null || \"\".equals(token)) return false;\n        return token.startsWith(PREFIX);\n    }\n\n    /**\n     * 生成Token\n     */\n    public static String createToken(String username, String[] roles, long expiration) {\n        Map<String, Object> map = new HashMap<>();\n        map.put(ROLE_CLAIMS, roles);\n        return PREFIX + Jwts.builder()\n                .setSubject(username)\n                .setClaims(map)\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis() + expiration))\n                .signWith(SignatureAlgorithm.HS256, APP_SECRET)\n                .compact();\n    }\n\n    /**\n     * 获取token body\n     */\n    private static Claims getTokenClaims(String token) {\n        token = token.substring(PREFIX.length());\n        Claims claims;\n        try {\n            claims = Jwts.parser()\n                    .setSigningKey(APP_SECRET)\n                    .parseClaimsJws(token)\n                    .getBody();\n        } catch (ExpiredJwtException e) {\n            claims = e.getClaims();\n        }\n        return claims;\n    }\n\n    /**\n     * 从Token中获取username\n     */\n    public static String getUsername(String token) {\n        return getTokenClaims(token).getSubject();\n    }\n\n    /**\n     * 从Token中获取用户角色\n     */\n    public static List<String> getTokenRoles(String token) {\n        List<String> roles = new ArrayList<>();\n        Object object = getTokenClaims(token).get(ROLE_CLAIMS);\n        if (object instanceof ArrayList<?>) {\n            for (Object o : (List<?>) object) {\n                roles.add((String) o);\n            }\n        }\n        return roles;\n    }\n\n    /**\n     * 校验Token是否过期\n     */\n    public static boolean isExpiration(String token) {\n        return getTokenClaims(token).getExpiration().before(new Date());\n    }\n\n}\n\n"
  },
  {
    "path": "api/src/main/java/com/example/api/utils/RandomUtil.java",
    "content": "package com.example.api.utils;\n\nimport java.util.Random;\n\npublic final class RandomUtil {\n\n    public static String next() {\n        StringBuilder builder = new StringBuilder();\n        Random random = new Random();\n        for (int i = 0; i < 6; i++) {\n            builder.append(random.nextInt(10));\n        }\n        return builder.toString();\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/java/com/example/api/utils/ResponseUtil.java",
    "content": "package com.example.api.utils;\n\nimport com.alibaba.fastjson.JSON;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\npublic final class ResponseUtil {\n\n    public static void writeJson(HttpServletResponse response, Object o) {\n        response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n        response.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n        response.setHeader(\"Access-Control-Allow-Methods\", \"POST, GET, PATCH, DELETE, PUT\");\n        response.setHeader(\"Access-Control-Max-Age\", \"3600\");\n        response.setHeader(\"Access-Control-Allow-Headers\", \"Origin, X-Requested-With, Content-Type, Accept\");\n        response.setContentType(\"application/json;charset=utf-8\");\n        response.setStatus(200);\n        try {\n            PrintWriter writer = response.getWriter();\n            writer.write(JSON.toJSONString(o));\n            writer.flush();\n            writer.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "api/src/main/resources/application.yaml",
    "content": "server:\n  port: 8080\nspring:\n  mail:\n    host: smtp.163.com\n    protocol: smtp\n    default-encoding: UTF-8\n    #发件人\n    username: gaoyuanming_1@163.com\n    #授权码\n    password: a123456\n  datasource:\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    url: jdbc:mysql://localhost:3306/logistics?characterEncoding=utf8&serverTimezone=UTC\n    username: root\n    password: abc521521521\n  jpa:\n    hibernate:\n      ddl-auto: update\n    open-in-view: false"
  },
  {
    "path": "web-app/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "web-app/README.md",
    "content": "# Antd Vue Admin 基础模版\n\n### 实现的基本功能\n\n- vuex封装关于User的部分\n\n- vuex + vue-router 的路由卫士\n\n- nprogress每次路由变化的进度条显示\n\n- layout公共布局\n\n- axios简单封装 utils/request.js\n\n### 页面预览\n\n- 首页\n\n![Home](https://gaoyuanming-photo.oss-cn-beijing.aliyuncs.com/simple-antd-vue-admin/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202021-03-25%20%E4%B8%8B%E5%8D%888.07.51.png)\n\n- 登陆页\n\n![Home](https://gaoyuanming-photo.oss-cn-beijing.aliyuncs.com/simple-antd-vue-admin/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202021-03-25%20%E4%B8%8B%E5%8D%888.08.13.png)\n\n### Project setup\n\n```\nnpm install\n```\n\n### Compiles and hot-reloads for development\n\n```\nnpm run serve\n```\n\n### Compiles and minifies for production\n\n```\nnpm run build\n```\n\n### Customize configuration\n\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "web-app/package.json",
    "content": "{\n  \"name\": \"wab-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\"\n  },\n  \"dependencies\": {\n    \"ant-design-vue\": \"^1.7.4\",\n    \"axios\": \"^0.21.1\",\n    \"echarts\": \"^5.0.2\",\n    \"nprogress\": \"^0.2.0\",\n    \"vue\": \"^2.6.11\",\n    \"vue-json-excel\": \"^0.3.0\",\n    \"vue-router\": \"^3.2.0\",\n    \"vuex\": \"^3.4.0\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-router\": \"~4.5.0\",\n    \"@vue/cli-plugin-vuex\": \"~4.5.0\",\n    \"@vue/cli-service\": \"~4.5.0\",\n    \"vue-template-compiler\": \"^2.6.11\"\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\",\n    \"not dead\"\n  ]\n}\n"
  },
  {
    "path": "web-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title>物流管理系统</title>\n</head>\n<body>\n<div id=\"app\"></div>\n</body>\n</html>\n"
  },
  {
    "path": "web-app/src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <router-view/>\n  </div>\n</template>\n\n<style>\n\n/*顶部进度条样式*/\n#nprogress .bar {\n  background: #1890ff !important;\n}\n\nbody {\n  letter-spacing: 1px;\n  background: #f0f2f5 !important;\n}\n\n</style>"
  },
  {
    "path": "web-app/src/api/admin.js",
    "content": "import service from \"../utils/request\";\n\nexport function IsInit() {\n    return service({\n        url: '/admin/hasInit',\n        method: 'get',\n    })\n}\n\nexport function Init(data) {\n    return service({\n        url: '/admin/init',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteAdmin(id) {\n    return service({\n        url: '/admin?id=' + id,\n        method: 'delete',\n    })\n}\n\nexport function FindAllAdmin() {\n    return service({\n        url: '/admin',\n        method: 'get',\n    })\n}\n\nexport function SaveAdmin(data) {\n    return service({\n        url: '/admin',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function AdminSendEmail(email) {\n    return service({\n        url: '/admin/sendEmail?email=' + email,\n        method: 'get'\n    })\n}\n\nexport function AdminLogin(type, data) {\n    return service({\n        url: '/admin/login?type=' + type,\n        method: 'post',\n        data: data\n    })\n}"
  },
  {
    "path": "web-app/src/api/commodity.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllCommodity() {\n    return service({\n        url: '/commodity',\n        method: 'get'\n    })\n}\n\nexport function SearchCommodity(name) {\n    return service({\n        url: '/commodity/search/' + name,\n        method: 'get'\n    })\n}\n\n\nexport function SaveCommodity(data) {\n    return service({\n        url: '/commodity',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteCommodityById(id) {\n    return service({\n        url: '/commodity?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/api/distribution.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllDistribution() {\n    return service({\n        url: '/distribution',\n        method: 'get'\n    })\n}\n\nexport function FindAllCanUse() {\n    return service({\n        url: '/distribution/can',\n        method: 'get'\n    })\n}\n\nexport function SaveDistribution(data) {\n    return service({\n        url: '/distribution',\n        method: 'post',\n        data: data\n    })\n}"
  },
  {
    "path": "web-app/src/api/driver.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllDriver(){\n    return service({\n        url: '/driver',\n        method: 'get'\n    })\n}\n\nexport function SaveDriver(data) {\n    return service({\n        url: '/driver',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteDriverById(id){\n    return service({\n        url: '/driver?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/api/employee.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllEmployee(){\n    return service({\n        url: '/employee',\n        method: 'get'\n    })\n}\n\nexport function SaveEmployee(data) {\n    return service({\n        url: '/employee',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteEmployeeById(id){\n    return service({\n        url: '/employee?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/api/inventory.js",
    "content": "import service from \"../utils/request\";\n\nexport function AnalyzeCommodity(type) {\n    return service({\n        url: '/inventory/analyze?type=' + type,\n        method: 'get'\n    })\n}\n\nexport function FindAllInventory(id) {\n    return service({\n        url: '/inventory/warehouse/' + id,\n        method: 'get'\n    })\n}\n\nexport function InAndOut(type, data) {\n    return service({\n        url: '/inventory/' + type,\n        method: 'post',\n        data: data\n    })\n}\n\nexport function FindRecordByWarehouse(id) {\n    return service({\n        url: '/inventory/record/warehouse/' + id,\n        method: 'get'\n    })\n}\n\nexport function DeleteInventoryById(id) {\n    return service({\n        url: '/inventory?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/api/role.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllRole(){\n    return service({\n        url: '/role',\n        method: 'get'\n    })\n}\n"
  },
  {
    "path": "web-app/src/api/sale.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllSale() {\n    return service({\n        url: '/sale',\n        method: 'get'\n    })\n}\n\nexport function SearchCompany(name) {\n    return service({\n        url: '/sale/search/' + name,\n        method: 'get'\n    })\n}\n\nexport function SaveSale(data) {\n    return service({\n        url: '/sale',\n        method: 'post',\n        data: data\n    })\n}"
  },
  {
    "path": "web-app/src/api/vehicle.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllVehicle(){\n    return service({\n        url: '/vehicle',\n        method: 'get'\n    })\n}\n\nexport function SaveVehicle(data) {\n    return service({\n        url: '/vehicle',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteVehicleById(id){\n    return service({\n        url: '/vehicle?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/api/warehouse.js",
    "content": "import service from \"../utils/request\";\n\nexport function FindAllWarehouse() {\n    return service({\n        url: '/warehouse',\n        method: 'get'\n    })\n}\n\nexport function SaveWarehouse(data) {\n    return service({\n        url: '/warehouse',\n        method: 'post',\n        data: data\n    })\n}\n\nexport function DeleteWarehouseById(id) {\n    return service({\n        url: '/warehouse?id=' + id,\n        method: 'delete'\n    })\n}"
  },
  {
    "path": "web-app/src/components/InventoryRecords.vue",
    "content": "<template>\n  <div>\n    <download-excel\n        class=\"export-excel-wrapper\"\n        :data=\"data\"\n        :fields=\"json_fields\"\n        name=\"出入库记录.xls\">\n      <a-button class=\"btn\" icon=\"download\" type=\"primary\">下载Excel表格</a-button>\n    </download-excel>\n    <a-table :columns=\"columns\" :data-source=\"data\" rowKey=\"id\">\n      <span slot=\"type\" slot-scope=\"type\">\n        <a-tag :color=\"type === -1 ? 'green' : 'cyan'\">{{ type === -1 ? '出库' : '入库' }}</a-tag>\n      </span>\n    </a-table>\n  </div>\n</template>\n\n<script>\nimport {FindRecordByWarehouse} from \"../api/inventory\";\n\nconst columns = [\n  {\n    dataIndex: 'name',\n    key: 'name',\n    title: '商品',\n  },\n  {\n    title: '数量',\n    dataIndex: 'count',\n    key: 'count',\n  },\n  {\n    title: '时间',\n    dataIndex: 'createAt',\n    key: 'createAt',\n  },\n  {\n    title: '类型',\n    key: 'type',\n    dataIndex: 'type',\n    scopedSlots: {customRender: 'type'},\n  },\n  {\n    title: '备注',\n    dataIndex: 'description',\n    key: 'description',\n  },\n];\n\nexport default {\n\n  components: {},\n\n  props: {\n    warehouseId: {type: String, default: ''},\n  },\n\n  data() {\n    return {\n      data: [],\n      columns,\n      json_fields: {\n        \"商品ID\": \"cid\",\n        \"商品名称\": \"name\",\n        \"类型\": {\n          field: 'type',\n          callback: (value) => {\n            console.log(value)\n            return value === -1 ? '出库' : '入库'\n          }\n        },\n        \"数量\": \"count\",\n        \"备注\": \"description\",\n        \"时间\": \"createAt\",\n      },\n    }\n  },\n\n  mounted() {\n    FindRecordByWarehouse(this.warehouseId).then((res) => {\n      this.data = res.data\n      console.log(res.data[0])\n    })\n  },\n\n}\n</script>\n\n<style scoped>\n.btn {\n  margin-bottom: 15px;\n  letter-spacing: 1px;\n}\n</style>"
  },
  {
    "path": "web-app/src/layout/Aside.vue",
    "content": "<template>\n  <a-layout-sider\n      :style=\"{ overflow: 'auto', height: '100vh', position: 'fixed', left: 0 }\"\n      width=\"220\">\n    <div class=\"logo\">\n      <img src=\"../assets/logo.svg\" alt=\"\">\n      物流管理系统\n    </div>\n    <a-menu theme=\"dark\" mode=\"inline\">\n      <a-sub-menu v-for=\"(item, index) in menus\" :key=\"index\">\n        <span slot=\"title\">\n          <a-icon :type=\"item.icon\"/>\n          <span>{{ item.title }}</span>\n        </span>\n        <a-menu-item v-for=\"menu in item.children\" :key=\"menu.title\">\n          <router-link :to=\"menu.path\">\n            {{ menu.title }}\n          </router-link>\n        </a-menu-item>\n      </a-sub-menu>\n    </a-menu>\n  </a-layout-sider>\n</template>\n\n<script>\n\nexport default {\n\n  data() {\n    return {\n      menus: [\n        {\n          title: '基础信息管理',\n          icon: 'home',\n          children: [\n            {title: '商品管理', path: '/commodity'},\n            {title: '来往单位', path: '/company'},\n            {title: '员工管理', path: '/employee'},\n            {title: '仓库管理', path: '/warehouse'},\n          ]\n        },\n        {\n          title: '销售信息管理',\n          icon: 'pay-circle',\n          children: [\n            {title: '销售开票', path: '/sale/create'},\n            {title: '销售记录', path: '/sale/record'},\n          ]\n        },\n        {\n          title: '配送信息管理',\n          icon: 'car',\n          children: [\n            {title: '申请配送', path: '/delivery/create'},\n            {title: '配送列表', path: '/delivery/list'},\n          ]\n        },\n        {\n          title: '运输信息管理',\n          icon: 'rocket',\n          children: [\n            {title: '车辆资料', path: '/vehicle'},\n            {title: '驾驶员资料', path: '/driver'},\n          ]\n        },\n        {\n          title: '系统决策管理',\n          icon: 'line-chart',\n          children: [\n            {title: '入库分析', path: '/analyze/in'},\n            {title: '出库分析', path: '/analyze/out'},\n          ]\n        },\n        {\n          title: '系统信息管理',\n          icon: 'tool',\n          children: [\n            {title: '安全设置', path: '/security'},\n            {title: '操作员管理', path: '/admin'},\n            {title: '权限列表', path: '/role'},\n          ]\n        },\n      ]\n    }\n  },\n\n}\n\n</script>\n\n<style scoped>\n\n#components-layout-demo-fixed-sider .logo {\n  padding: 10px 15px;\n  height: 50px;\n  font-size: 15px;\n  margin: 16px;\n  color: #ffffff;\n  letter-spacing: 2px;\n}\n\n.ant-menu {\n  letter-spacing: 1px;\n}\n\n.logo img {\n  width: 32px;\n  height: 32px;\n  margin-right: 5px;\n}\n\n</style>"
  },
  {
    "path": "web-app/src/layout/Footer.vue",
    "content": "<template>\n  <a-layout-footer :style=\"{ textAlign: 'center', letterSpacing: '1px' }\">\n    物流管理系统 ©2021 Created by 信息工程学院 - 高元明\n  </a-layout-footer>\n</template>\n\n<script>\nexport default {\nname: \"Footer\"\n}\n</script>\n\n<style scoped>\n\n</style>"
  },
  {
    "path": "web-app/src/layout/Header.vue",
    "content": "<template>\n  <a-layout-header class=\"header\" :style=\"{ background: '#fff', padding: 0}\">\n    <a-tooltip placement=\"bottom\">\n      <template slot=\"title\">\n        <span>刷新页面</span>\n      </template>\n      <a-button @click=\"clickReload\" class=\"reload-btn\" icon=\"reload\" type=\"link\">Reload</a-button>\n    </a-tooltip>\n\n    <a-tooltip placement=\"bottom\" class=\"question-btn\">\n      <template slot=\"title\">\n        <span>About</span>\n      </template>\n      <a-button class=\"reload-btn\" icon=\"question-circle\" type=\"link\"/>\n    </a-tooltip>\n\n    <a-dropdown>\n      <a-button class=\"avatar-btn\" type=\"link\">\n        <div class=\"avatar-btn-main\">\n          <a-avatar class=\"avatar\"\n                    :size=\"26\"\n                    src=\"https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png\"/>\n          <div class=\"avatar-btn-username\">{{ details.email }}</div>\n        </div>\n      </a-button>\n      <a-menu slot=\"overlay\">\n        <a-menu-item>\n          <router-link to=\"/security\">\n            <a-icon class=\"icon\" type=\"smile\"/>\n            个人中心\n          </router-link>\n        </a-menu-item>\n        <a-menu-item>\n          <router-link to=\"/role\">\n            <a-icon class=\"icon\" type=\"setting\"/>\n            权限设置\n          </router-link>\n        </a-menu-item>\n        <a-menu-divider/>\n        <a-menu-item @click=\"handleLogout\">\n          <a-icon class=\"icon\" type=\"logout\"/>\n          退出登录\n        </a-menu-item>\n      </a-menu>\n    </a-dropdown>\n\n  </a-layout-header>\n</template>\n\n<script>\nexport default {\n\n  data() {\n    return {\n      details: this.$store.state.user.details ? this.$store.state.user.details : {}\n    }\n  },\n\n  methods: {\n\n    clickReload() {\n      this.$router.go(0)\n    },\n\n    handleLogout() {\n      let that = this\n      this.$confirm({\n        title: '你确定要注销你的登录信息吗?',\n        content: '点击确定将删除你在网站保留的登录信息！',\n        onOk() {\n          that.$router.push('/login')\n          that.$store.commit('user/userLogout')\n        },\n      });\n    }\n\n  }\n\n}\n</script>\n\n<style scoped>\n\n.reload-btn {\n  font-size: 15px;\n  margin-left: 10px;\n  color: rgba(0, 0, 0, 0.65);\n}\n\n.question-btn {\n  float: right;\n  margin: 15px 12px 0 0;\n}\n\n.avatar-btn {\n  float: right;\n  font-size: 15px;\n  color: rgba(0, 0, 0, 0.55);\n  height: 64px;\n}\n\n\n.avatar-btn-main {\n  display: flex;\n}\n\n.avatar-btn-username {\n  line-height: 62px;\n  font-size: 14px;\n}\n\n.avatar {\n  margin-right: 12px;\n  margin-top: 19px;\n}\n\n</style>"
  },
  {
    "path": "web-app/src/layout/Index.vue",
    "content": "<template>\n  <a-layout id=\"components-layout-demo-fixed-sider\">\n    <Aside/>\n    <a-layout :style=\"{ marginLeft: '220px' }\">\n      <Header/>\n      <Main/>\n      <Footer/>\n    </a-layout>\n  </a-layout>\n</template>\n\n<script>\nimport Aside from \"@/layout/Aside\";\nimport Header from \"@/layout/Header\";\nimport Main from \"@/layout/Main\";\nimport Footer from \"@/layout/Footer\";\n\nexport default {\n\n  components: {Aside, Header, Main, Footer},\n\n  mounted() {\n    this.$message.success(\n        '欢迎管理员 ' + this.$store.state.user.details.email,\n        6,\n    );\n  }\n\n}\n</script>\n\n<style scoped>\n#components-layout-demo-fixed-sider .logo {\n  padding: 10px 15px;\n  height: 50px;\n  font-size: 15px;\n  margin: 16px;\n  color: #ffffff;\n  letter-spacing: 2px;\n}\n\n.logo img {\n  width: 32px;\n  height: 32px;\n  margin-right: 5px;\n}\n\n.header {\n  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)\n}\n\n</style>\n"
  },
  {
    "path": "web-app/src/layout/Main.vue",
    "content": "<template>\n  <a-layout-content :style=\"{ margin: '24px', overflow: 'initial' }\">\n    <router-view/>\n  </a-layout-content>\n</template>\n\n<style scoped>\n\n</style>"
  },
  {
    "path": "web-app/src/main.js",
    "content": "import Vue from 'vue'\nimport App from './App.vue'\nimport router from './router'\nimport store from './store'\nimport Antd from 'ant-design-vue'\nimport 'ant-design-vue/dist/antd.css'\nimport JsonExcel from 'vue-json-excel'\n\nVue.component('downloadExcel', JsonExcel)\n\nVue.config.productionTip = false\n\nVue.use(Antd)\n\nnew Vue({\n  router,\n  store,\n  render: function (h) { return h(App) }\n}).$mount('#app')\n"
  },
  {
    "path": "web-app/src/router/index.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport store from '../store'\nimport routes from \"@/router/routes\"\nimport NProgress from 'nprogress'\nimport 'nprogress/nprogress.css'\n\n//顶部进度条样式\nNProgress.configure({\n    showSpinner: false,\n    speed: 800,\n});\n\nVue.use(VueRouter)\n\nconst router = new VueRouter({\n    mode: 'history',\n    base: process.env.BASE_URL,\n    routes\n})\n\n//路由卫士\nrouter.beforeEach((to, from, next) => {\n    NProgress.start()\n    to.meta.auth && !store.state.user.token ? next(\"/login\") : next()\n})\n\nrouter.afterEach(() => {\n    NProgress.done()\n})\n\nexport default router\n"
  },
  {
    "path": "web-app/src/router/routes.js",
    "content": "import Layout from '@/layout/Index'\n\nconst routes = [\n\n    //公共布局下的路由\n    {\n        path: '/',\n        component: Layout,\n        children: [\n            {\n                path: \"\",\n                redirect: \"/commodity\",\n                meta: {auth: true}\n            },\n            {\n                path: 'commodity',\n                component: () => import('@/views/basics/Commodity'),\n                meta: {auth: true}\n            },\n            {\n                path: 'company',\n                component: () => import('@/views/basics/Company'),\n                meta: {auth: true}\n            },\n            {\n                path: 'employee',\n                component: () => import('@/views/basics/Employee'),\n                meta: {auth: true}\n            },\n            {\n                path: 'warehouse',\n                component: () => import('@/views/basics/Warehouse'),\n                meta: {auth: true}\n            },\n            {\n                path: 'warehouse/:id',\n                component: () => import('@/views/basics/Details'),\n                meta: {auth: true}\n            },\n            {\n                path: 'driver',\n                component: () => import('@/views/transport/Driver'),\n                meta: {auth: true}\n            },\n            {\n                path: 'vehicle',\n                component: () => import('@/views/transport/Vehicle'),\n                meta: {auth: true}\n            },\n            {\n                path: 'sale/record',\n                component: () => import('@/views/sale/Record'),\n                meta: {auth: true}\n            },\n            {\n                path: 'sale/create',\n                component: () => import('@/views/sale/Create'),\n                meta: {auth: true}\n            },\n\n            {\n                path: 'delivery/create',\n                component: () => import('@/views/delivery/Create'),\n                meta: {auth: true}\n            },\n            {\n                path: 'delivery/list',\n                component: () => import('@/views/delivery/List'),\n                meta: {auth: true}\n            },\n\n            {\n                path: 'analyze/in',\n                component: () => import('@/views/analyze/In'),\n                meta: {auth: true}\n            },\n\n            {\n                path: 'analyze/out',\n                component: () => import('@/views/analyze/Out'),\n                meta: {auth: true}\n            },\n\n            {\n                path: 'security',\n                component: () => import('@/views/system/Security'),\n                meta: {auth: true},\n            },\n            {\n                path: 'admin',\n                component: () => import('@/views/system/Admin'),\n                meta: {auth: true},\n            },\n            {\n                path: 'role',\n                component: () => import('@/views/system/Role'),\n                meta: {auth: true},\n            },\n\n            //403\n            {\n                path: '403',\n                component: () => import('@/views/error/403'),\n                meta: {auth: true}\n            },\n            //404\n            {\n                path: '404',\n                component: () => import('@/views/error/404'),\n                meta: {auth: true}\n            },\n            //500\n            {\n                path: '500',\n                component: () => import('@/views/error/500'),\n                meta: {auth: true}\n            },\n\n        ]\n    },\n\n    //登录页\n    {\n        path: '/login',\n        name: 'Login',\n        component: () => import('@/views/Login'),\n        meta: {auth: false}\n    },\n\n    //初始化\n    {\n        path: '/init',\n        name: 'Init',\n        component: () => import('@/views/Init'),\n        meta: {auth: false}\n    },\n\n    //404\n    {\n        path: \"*\",\n        redirect: '/404'\n    }\n\n]\n\nexport default routes"
  },
  {
    "path": "web-app/src/store/index.js",
    "content": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport user from './modules/user'\n\nVue.use(Vuex)\n\nexport default new Vuex.Store({\n  modules: {\n    user\n  }\n})\n"
  },
  {
    "path": "web-app/src/store/modules/user.js",
    "content": "const state = {\n    token: localStorage.getItem(\"token\"),\n    details: JSON.parse(localStorage.getItem(\"user\"))\n}\n\nconst getters = {}\n\nconst mutations = {\n\n    saveToken(state, token) {\n        state.token = token\n        localStorage.setItem(\"token\", token)\n    },\n\n    saveLoginUser(state, user) {\n        state.details = user\n        localStorage.setItem(\"user\", JSON.stringify(user))\n    },\n\n    userLogout(state) {\n        state.details = null\n        state.token = null\n        localStorage.removeItem(\"token\")\n        localStorage.removeItem(\"user\")\n    }\n\n}\n\nconst actions = {}\n\nexport default {\n    namespaced: true,\n    state,\n    getters,\n    mutations,\n    actions\n}"
  },
  {
    "path": "web-app/src/utils/request.js",
    "content": "import request from \"axios\"\nimport {message} from 'ant-design-vue'\nimport router from '../router/index'\n\nconst token = localStorage.getItem(\"token\")\n\nconst service = request.create({\n    baseURL: 'http://localhost:8080/api',\n    timeout: 50000,\n    headers: {'Authorization': token}\n});\n\nservice.interceptors.response.use(\n    response => {\n\n        const res = response.data;\n\n        //判断response状态\n        if (!res.status) message.error('请求错误: ' + res.msg)\n\n        if (res.code === 403) router.push(\"/403\")\n\n        return res\n    },\n\n    error => {\n        message.error(error)\n        router.push('/500')\n        return Promise.reject(error)\n    }\n);\n\nexport default service"
  },
  {
    "path": "web-app/src/views/Init.vue",
    "content": "<template>\n  <div class=\"login-box\">\n    <div>\n      <div class=\"box-header\">\n        <img class=\"logo\" src=\"../assets/logo.svg\" alt=\"\"/>\n        <div class=\"box-header-t\">系统初始化</div>\n      </div>\n      <div class=\"title\">Logistics Management 物流管理系统 - 系统初始化</div>\n      <a-input\n          v-model=\"form.email\"\n          size=\"large\"\n          style=\"margin-top: 10px\"\n          class=\"input\"\n          placeholder=\"邮箱\">\n        <a-icon slot=\"prefix\" type=\"mail\"/>\n      </a-input>\n      <a-input-password\n          v-model=\"form.password\"\n          size=\"large\"\n          class=\"input\"\n          placeholder=\"密码\">\n        <a-icon slot=\"prefix\" type=\"lock\"/>\n      </a-input-password>\n      <a-button :loading=\"submitLoading\" class=\"submit-btn\" type=\"primary\" @click=\"submitLogin\">\n        初始化系统\n      </a-button>\n      <div class=\"des\">物流管理系统 - Copyright 2021 高元明</div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport {Init, IsInit} from \"../api/admin\";\n\nexport default {\n\n  data() {\n    return {\n      spinning: true,\n      sendLoading: false,\n      submitType: '2', //1账号登录 2邮箱登录\n      submitLoading: false,\n      form: {\n        password: '',\n        email: '',\n      },\n    }\n  },\n\n  mounted() {\n    IsInit().then((res) => {\n      if (res.data) this.$router.push('/login')\n    })\n  },\n\n  methods: {\n\n    submitLogin() {\n      if (this.checkEmail()) {\n        Init(this.form).then((res) => {\n          if (res.status) this.$router.push('/login')\n        })\n      }\n    },\n\n    checkEmail() {\n      const emailRegex = new RegExp('^\\\\w{3,}(\\\\.\\\\w+)*@[A-z0-9]+(\\\\.[A-z]{2,5}){1,2}$')\n      if (!emailRegex.test(this.form.email)) {\n        this.$message.error('请输入正确格式的邮箱');\n        return false\n      } else {\n        return true\n      }\n    },\n\n  }\n\n}\n</script>\n\n<style scoped>\n\nbody {\n  background: #000000 !important;\n}\n\n>>> .ant-tabs-bar {\n  border-bottom: none !important;\n}\n\n>>> .ant-btn-primary {\n  border-color: #5a84fd;\n}\n\n.login-box {\n  width: 350px;\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n}\n\n.box-header {\n  display: flex;\n}\n\n.box-header-t {\n  font-weight: bolder;\n  font-size: 30px;\n  letter-spacing: 1px;\n}\n\n.logo {\n  width: 44px;\n  height: 44px;\n  margin-right: 20px;\n  margin-left: 43px;\n}\n\n>>> .ant-tabs-nav {\n  width: 350px;\n}\n\n>>> .ant-tabs-ink-bar {\n  left: 52px;\n}\n\n>>> .ant-input-affix-wrapper .ant-input {\n  font-size: 12px !important;\n}\n\n.title {\n  color: #91949c;\n  padding-top: 15px;\n  padding-bottom: 35px;\n  font-size: 13px;\n  text-align: center;\n}\n\n.input {\n  margin-bottom: 25px;\n  font-size: 10px;\n}\n\n.code-btn {\n  height: 40px;\n  margin-left: 30px;\n}\n\n.submit-btn {\n  letter-spacing: 2px;\n  background: #5a84fd;\n  width: 100%;\n  height: 45px;\n}\n\n.des {\n  padding-top: 25px;\n  font-size: 13px;\n  text-align: center;\n  color: #91949c;\n  letter-spacing: 2px;\n}\n</style>"
  },
  {
    "path": "web-app/src/views/Login.vue",
    "content": "<template>\n  <div class=\"login-box\">\n    <div>\n      <div class=\"box-header\">\n        <img class=\"logo\" src=\"../assets/logo.svg\" alt=\"\"/>\n        <div class=\"box-header-t\">Management</div>\n      </div>\n      <div class=\"title\">Logistics Management 物流管理系统 - 管理员登录</div>\n      <a-tabs @change=\"tabClick\" default-active-key=\"1\" :tabBarStyle=\"{ textAlign: 'center' }\">\n        <a-tab-pane key=\"1\" tab=\"密码登陆\">\n          <a-input\n              v-model=\"form.email\"\n              size=\"large\"\n              style=\"margin-top: 10px\"\n              class=\"input\"\n              placeholder=\"邮箱\">\n            <a-icon slot=\"prefix\" type=\"mail\"/>\n          </a-input>\n          <a-input-password\n              v-model=\"form.password\"\n              size=\"large\"\n              class=\"input\"\n              placeholder=\"密码\">\n            <a-icon slot=\"prefix\" type=\"lock\"/>\n          </a-input-password>\n        </a-tab-pane>\n        <a-tab-pane key=\"2\" tab=\"验证码登陆\" force-render>\n          <a-input\n              v-model=\"form.email\"\n              size=\"large\"\n              style=\"margin-top: 10px\"\n              class=\"input\"\n              placeholder=\"邮箱\">\n            <a-icon slot=\"prefix\" type=\"mail\"/>\n          </a-input>\n          <div style=\"display: flex\">\n            <a-input\n                v-model=\"form.code\"\n                size=\"large\"\n                class=\"input\"\n                placeholder=\"验证码\">\n              <a-icon slot=\"prefix\" type=\"safety-certificate\"/>\n            </a-input>\n            <a-button class=\"code-btn\" :loading=\"sendLoading\" @click=\"sendEmail\">\n              获取验证码\n            </a-button>\n          </div>\n        </a-tab-pane>\n      </a-tabs>\n      <div style=\"margin-bottom: 20px\">\n        <a-checkbox v-model=\"form.remember\">自动登录</a-checkbox>\n        <a-button type=\"link\" style=\"margin-left: 158px\">\n          忘记密码 ?\n        </a-button>\n      </div>\n      <a-button :loading=\"submitLoading\" class=\"submit-btn\" type=\"primary\" @click=\"submitLogin\">\n        确认登陆\n      </a-button>\n      <div class=\"des\">物流管理系统 - Copyright 2021 高元明</div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport {AdminLogin, AdminSendEmail} from \"@/api/admin\";\nimport {IsInit} from \"../api/admin\";\n\nexport default {\n\n  data() {\n    return {\n      sendLoading: false,\n      submitType: '1', //1账号登录 2邮箱登录\n      submitLoading: false,\n      form: {\n        password: '',\n        email: '',\n        code: '',\n        remember: false,\n      },\n    }\n  },\n\n  mounted() {\n    IsInit().then((res) => {\n      if (!res.data) this.$router.push('/init')\n    })\n  },\n\n  methods: {\n\n    sendEmail() {\n      if (this.checkEmail()) {\n        this.sendLoading = true\n        AdminSendEmail(this.form.email).then((res) => {\n          if (res.status) this.$message.success(\"验证码发送成功\")\n          this.sendLoading = false\n        })\n      }\n    },\n\n    submitLogin() {\n      if (this.checkEmail()) {\n        let type = this.submitType === '1' ? \"passwrod\" : \"email\"\n        AdminLogin(type, this.form).then((res) => {\n          console.log(res.data)\n          if (res.status) {\n            this.$store.commit('user/saveToken', res.data.token)\n            this.$store.commit('user/saveLoginUser', res.data.admin)\n            setTimeout(() => {\n              this.$router.push(\"/commodity\")\n              this.submitLoading = false\n            }, 700)\n            this.$message.success(\"登陆成功\")\n          }\n        })\n      }\n    },\n\n    tabClick(key) {\n      this.submitType = key\n    },\n\n    checkEmail() {\n      const emailRegex = new RegExp('^\\\\w{3,}(\\\\.\\\\w+)*@[A-z0-9]+(\\\\.[A-z]{2,5}){1,2}$')\n      if (!emailRegex.test(this.form.email)) {\n        this.$message.error('请输入正确格式的邮箱');\n        return false\n      } else {\n        return true\n      }\n    },\n\n  }\n\n}\n</script>\n\n<style scoped>\n\nbody {\n  background: #000000 !important;\n}\n\n>>> .ant-tabs-bar {\n  border-bottom: none !important;\n}\n\n>>> .ant-btn-primary {\n  border-color: #5a84fd;\n}\n\n.login-box {\n  width: 350px;\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n}\n\n.box-header {\n  display: flex;\n}\n\n.box-header-t {\n  font-weight: bolder;\n  font-size: 30px;\n}\n\n.logo {\n  width: 44px;\n  height: 44px;\n  margin-right: 20px;\n  margin-left: 43px;\n}\n\n>>> .ant-tabs-nav {\n  width: 350px;\n}\n\n>>> .ant-tabs-ink-bar {\n  left: 52px;\n}\n\n>>> .ant-input-affix-wrapper .ant-input {\n  font-size: 12px !important;\n}\n\n.title {\n  color: #91949c;\n  padding-top: 15px;\n  padding-bottom: 35px;\n  font-size: 13px;\n  text-align: center;\n}\n\n.input {\n  margin-bottom: 25px;\n  font-size: 10px;\n}\n\n.code-btn {\n  height: 40px;\n  margin-left: 30px;\n}\n\n.submit-btn {\n  letter-spacing: 2px;\n  background: #5a84fd;\n  width: 100%;\n  height: 45px;\n}\n\n.des {\n  padding-top: 25px;\n  font-size: 13px;\n  text-align: center;\n  color: #91949c;\n  letter-spacing: 2px;\n}\n</style>"
  },
  {
    "path": "web-app/src/views/Test.vue",
    "content": "<template>\n  <a-form-model :model=\"form\" :label-col=\"labelCol\" :wrapper-col=\"wrapperCol\">\n    <a-form-model-item label=\"Activity name\">\n      <a-input v-model=\"form.name\" />\n    </a-form-model-item>\n    <a-form-model-item label=\"Activity zone\">\n      <a-select v-model=\"form.region\" placeholder=\"please select your zone\">\n        <a-select-option value=\"shanghai\">\n          Zone one\n        </a-select-option>\n        <a-select-option value=\"beijing\">\n          Zone two\n        </a-select-option>\n      </a-select>\n    </a-form-model-item>\n    <a-form-model-item label=\"Activity time\">\n      <a-date-picker\n          v-model=\"form.date1\"\n          show-time\n          type=\"date\"\n          placeholder=\"Pick a date\"\n          style=\"width: 100%;\"\n      />\n    </a-form-model-item>\n    <a-form-model-item label=\"Instant delivery\">\n      <a-switch v-model=\"form.delivery\" />\n    </a-form-model-item>\n    <a-form-model-item label=\"Activity type\">\n      <a-checkbox-group v-model=\"form.type\">\n        <a-checkbox value=\"1\" name=\"type\">\n          Online\n        </a-checkbox>\n        <a-checkbox value=\"2\" name=\"type\">\n          Promotion\n        </a-checkbox>\n        <a-checkbox value=\"3\" name=\"type\">\n          Offline\n        </a-checkbox>\n      </a-checkbox-group>\n    </a-form-model-item>\n    <a-form-model-item label=\"Resources\">\n      <a-radio-group v-model=\"form.resource\">\n        <a-radio value=\"1\">\n          Sponsor\n        </a-radio>\n        <a-radio value=\"2\">\n          Venue\n        </a-radio>\n      </a-radio-group>\n    </a-form-model-item>\n    <a-form-model-item label=\"Activity form\">\n      <a-input v-model=\"form.desc\" type=\"textarea\" />\n    </a-form-model-item>\n    <a-form-model-item :wrapper-col=\"{ span: 14, offset: 4 }\">\n      <a-button type=\"primary\" @click=\"onSubmit\">\n        Create\n      </a-button>\n      <a-button style=\"margin-left: 10px;\">\n        Cancel\n      </a-button>\n    </a-form-model-item>\n  </a-form-model>\n</template>\n<script>\nexport default {\n  data() {\n    return {\n      labelCol: { span: 4 },\n      wrapperCol: { span: 14 },\n      form: {\n        name: '',\n        region: undefined,\n        date1: undefined,\n        delivery: false,\n        type: [],\n        resource: '',\n        desc: '',\n      },\n    };\n  },\n  methods: {\n    onSubmit() {\n      console.log('submit!', this.form);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "web-app/src/views/analyze/In.vue",
    "content": "<template>\n  <div class=\"main\" id=\"main\">\n\n  </div>\n</template>\n\n<script>\nimport * as echarts from 'echarts/core';\nimport {\n  TitleComponent,\n  TooltipComponent,\n  LegendComponent\n} from 'echarts/components';\nimport {\n  PieChart\n} from 'echarts/charts';\nimport {\n  CanvasRenderer\n} from 'echarts/renderers';\nimport {AnalyzeCommodity} from \"../../api/inventory\";\n\necharts.use(\n    [TitleComponent, TooltipComponent, LegendComponent, PieChart, CanvasRenderer]\n);\n\nexport default {\n\n  data() {\n    return {\n      commodityList: []\n    }\n  },\n\n  mounted() {\n    AnalyzeCommodity(1).then((res) => {\n      if (res.status) {\n        let commodityList = res.data\n        let chartDom = document.getElementById('main');\n        let myChart = echarts.init(chartDom);\n        let option;\n\n        option = {\n          title: {\n            text: '商品入库排行分析',\n            left: 'center'\n          },\n          tooltip: {\n            trigger: 'item'\n          },\n          legend: {\n            orient: 'vertical',\n            left: 'left',\n          },\n          series: [\n            {\n              name: '访问来源',\n              type: 'pie',\n              radius: '50%',\n              data: commodityList,\n              emphasis: {\n                itemStyle: {\n                  shadowBlur: 10,\n                  shadowOffsetX: 0,\n                  shadowColor: 'rgba(0, 0, 0, 0.5)'\n                }\n              }\n            }\n          ]\n        };\n\n        option && myChart.setOption(option);\n      }\n    })\n\n  },\n\n  methods: {},\n\n}\n</script>\n\n<style scoped>\n.main {\n  width: 100%;\n  height: 500px;\n  background: #ffffff;\n  padding: 50px;\n}\n</style>"
  },
  {
    "path": "web-app/src/views/analyze/Out.vue",
    "content": "<template>\n  <div class=\"main\" id=\"main\">\n\n  </div>\n</template>\n\n<script>\nimport * as echarts from 'echarts/core';\nimport {\n  TitleComponent,\n  TooltipComponent,\n  LegendComponent\n} from 'echarts/components';\nimport {\n  PieChart\n} from 'echarts/charts';\nimport {\n  CanvasRenderer\n} from 'echarts/renderers';\nimport {AnalyzeCommodity} from \"../../api/inventory\";\n\necharts.use(\n    [TitleComponent, TooltipComponent, LegendComponent, PieChart, CanvasRenderer]\n);\n\nexport default {\n\n  data() {\n    return {\n      commodityList: []\n    }\n  },\n\n  mounted() {\n    AnalyzeCommodity(-1).then((res) => {\n      if (res.status) {\n        let commodityList = res.data\n        let chartDom = document.getElementById('main');\n        let myChart = echarts.init(chartDom);\n        let option;\n\n        option = {\n          title: {\n            text: '商品出库排行分析',\n            left: 'center'\n          },\n          tooltip: {\n            trigger: 'item'\n          },\n          legend: {\n            orient: 'vertical',\n            left: 'left',\n          },\n          series: [\n            {\n              name: '访问来源',\n              type: 'pie',\n              radius: '50%',\n              data: commodityList,\n              emphasis: {\n                itemStyle: {\n                  shadowBlur: 10,\n                  shadowOffsetX: 0,\n                  shadowColor: 'rgba(0, 0, 0, 0.5)'\n                }\n              }\n            }\n          ]\n        };\n\n        option && myChart.setOption(option);\n      }\n    })\n\n  },\n\n  methods: {},\n\n}\n</script>\n\n<style scoped>\n.main {\n  width: 100%;\n  height: 500px;\n  background: #ffffff;\n  padding: 50px;\n}\n</style>"
  },
  {
    "path": "web-app/src/views/basics/Commodity.vue",
    "content": "<template>\n  <div>\n    <div style=\"display: flex\">\n      <a-button size=\"large\" class=\"editable-add-btn\" @click=\"commodityVisible = true\">\n        <a-icon type=\"plus\"/>\n        新增商品\n      </a-button>\n      <a-input-search\n          placeholder=\"请输入商品名\"\n          enter-button=\"搜索商品\"\n          style=\"width: 400px;margin-left: 20px\"\n          size=\"large\"\n          @search=\"onSearch\"\n      />\n      <a-button style=\"margin-left: 10px\" size=\"large\" type=\"danger\" @click=\"loadTableData\">\n        重置\n      </a-button>\n    </div>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" rowKey=\"id\">\n      <a slot=\"name\" slot-scope=\"text\">{{ text }}</a>\n      <span slot=\"customTitle\"><a-icon type=\"smile-o\"/> 商品名称</span>\n      <span slot=\"action\" slot-scope=\"text, record, index\">\n        <a-button @click=\"handleUpdate(record)\" type=\"link\"><a-icon type=\"edit\"/> Update</a-button>\n      <a-divider type=\"vertical\"/>\n         <a-button @click=\"handleDelete(record,index)\" type=\"link\"><a-icon type=\"delete\"/> Delete</a-button>\n    </span>\n    </a-table>\n\n    <a-modal\n        title=\"商品信息\"\n        :closable=\"false\"\n        :visible=\"commodityVisible\"\n    >\n      <a-form-model ref=\"ruleForm\" :model=\"commodity\">\n        <a-form-model-item ref=\"name\" label=\"商品名称\" prop=\"name\">\n          <a-input v-model=\"commodity.name\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"商品单价\" prop=\"price\">\n          <a-input-number id=\"input\" v-model=\"commodity.price\" :min=\"1\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"描述信息\" prop=\"description\">\n          <a-input v-model=\"commodity.description\" type=\"textarea\"/>\n        </a-form-model-item>\n      </a-form-model>\n      <template slot=\"footer\">\n        <a-button key=\"back\" @click=\"commodityVisible = false\">\n          Return\n        </a-button>\n        <a-button key=\"submit\" type=\"primary\" :loading=\"modalLoading\" @click=\"submitCommodity\">\n          Submit\n        </a-button>\n      </template>\n    </a-modal>\n\n  </div>\n</template>\n\n<script>\nimport {DeleteCommodityById, FindAllCommodity, SaveCommodity} from \"@/api/commodity\";\nimport {SearchCommodity} from \"../../api/commodity\";\n\nconst columns = [\n  {\n    dataIndex: 'name',\n    key: 'name',\n    slots: {title: 'customTitle'},\n    scopedSlots: {customRender: 'name'},\n  },\n  {\n    title: '库存数量',\n    dataIndex: 'count',\n    key: 'age',\n  },\n  {\n    title: '描述信息',\n    dataIndex: 'description',\n    key: 'description',\n  },\n  {\n    title: '入库时间',\n    dataIndex: 'createAt',\n    key: 'address',\n  },\n  {\n    title: '商品单价',\n    key: 'price',\n    dataIndex: 'price',\n    scopedSlots: {customRender: 'tags'},\n  },\n  {\n    title: '更多操作',\n    key: 'action',\n    scopedSlots: {customRender: 'action'},\n  },\n];\n\nconst data = [];\n\nexport default {\n\n  data() {\n    return {\n      commodity: {\n        name: '',\n        description: '商品简介',\n        count: 0,\n        price: 9.99,\n      },\n      loading: false,\n      modalLoading: false,\n      commodityVisible: false,\n      commodityLoading: false,\n      data: [],\n      columns,\n    };\n  },\n\n  mounted() {\n    this.loadTableData()\n  },\n\n  methods: {\n\n    onSearch(value) {\n      if (value){\n        this.loading = true\n        SearchCommodity(value).then((res) => {\n          console.log(res)\n          if (res.data.length === 0) {\n            this.$message.warn(\"未搜索到任何数据\")\n            setTimeout(() => {\n              this.loading = false\n              this.data = res.data\n            }, 600)\n          } else {\n            setTimeout(() => {\n              this.$message.success(\"搜索到\" + res.data.length + \"个商品\")\n              this.loading = false\n              this.data = res.data\n            }, 600)\n          }\n        })\n      }else {\n        this.$message.warn(\"请输入搜索内容\")\n      }\n    },\n\n    loadTableData() {\n      this.loading = true\n      FindAllCommodity().then((res) => {\n        setTimeout(() => {\n          this.loading = false\n          this.data = res.data\n        }, 600)\n      })\n    },\n\n    submitCommodity() {\n      this.modalLoading = true\n      SaveCommodity(this.commodity).then((res) => {\n        if (res.status) {\n          setTimeout(() => {\n            this.modalLoading = false\n            this.commodityVisible = false\n            this.$message.success('商品信息提交成功');\n            this.loadTableData()\n          }, 600)\n        } else {\n          setTimeout(() => {\n            this.modalLoading = false\n          }, 600)\n        }\n      })\n    },\n\n    handleDelete(r, index) {\n      DeleteCommodityById(r.id).then((res) => {\n        if (res.status) this.$message.success('商品信息删除成功');\n        this.loadTableData()\n      })\n      console.log(index)\n    },\n\n    handleUpdate(r) {\n      this.commodity = r\n      this.commodityVisible = true\n    },\n\n  },\n\n};\n</script>\n\n<style scoped>\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/basics/Company.vue",
    "content": "<template>\n  <div>\n    <a-input-search\n        placeholder=\"请输入公司名\"\n        enter-button=\"搜索来往公司\"\n        style=\"width: 400px;margin-bottom: 20px\"\n        size=\"large\"\n        @search=\"onSearch\"\n    />\n    <a-button style=\"margin-left: 10px\" size=\"large\" type=\"danger\" @click=\"loadTableData\">\n      重置\n    </a-button>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" rowKey=\"id\">\n      <a slot=\"company\" slot-scope=\"company\">{{ company }}</a>\n      <span slot=\"customTitle\"><a-icon type=\"bank\"/> 公司名称</span>\n    </a-table>\n\n  </div>\n</template>\n\n<script>\nimport {FindAllSale, SearchCompany} from \"../../api/sale\";\n\nconst columns = [\n  {\n    dataIndex: 'company',\n    key: 'company',\n    slots: {title: 'customTitle'},\n    scopedSlots: {customRender: 'company'},\n  },\n  {\n    title: '预留电话',\n    key: 'phone',\n    dataIndex: 'phone',\n  },\n  {\n    title: '时间',\n    dataIndex: 'createAt',\n    key: 'createAt',\n  },\n];\n\nconst data = [];\n\nexport default {\n\n  data() {\n    return {\n      loading: false,\n      data: [],\n      columns,\n    };\n  },\n\n  mounted() {\n    this.loadTableData()\n  },\n\n  methods: {\n\n    onSearch(value) {\n      if (value) {\n        this.loading = true\n        SearchCompany(value).then((res) => {\n          console.log(res)\n          if (res.data.length === 0) {\n            this.$message.warn(\"未搜索到任何数据\")\n            setTimeout(() => {\n              this.loading = false\n              this.data = res.data\n            }, 600)\n          } else {\n            setTimeout(() => {\n              this.$message.success(\"搜索到\" + res.data.length + \"个公司\")\n              this.loading = false\n              this.data = res.data\n            }, 600)\n          }\n        })\n      } else {\n        this.$message.warn(\"请输入搜索内容\")\n      }\n    },\n\n    loadTableData() {\n      this.loading = true\n      FindAllSale().then((res) => {\n        setTimeout(() => {\n          this.loading = false\n          this.data = res.data\n        }, 600)\n      })\n    }\n\n  },\n\n};\n</script>\n\n<style scoped>\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/basics/Details.vue",
    "content": "<template>\n  <div class=\"main\">\n    <div class=\"header\">\n      <router-link to=\"/warehouse\">\n        <a-icon type=\"arrow-left\" style=\"padding-right: 5px\"/>\n        返回上一页\n      </router-link>\n    </div>\n    <div style=\"display: flex\">\n      <a-button class=\"editable-btn\" @click=\"handleSubmit('in')\">\n        入库商品\n      </a-button>\n      <a-button class=\"editable-btn\" @click=\"handleSubmit('out')\">\n        出库商品\n      </a-button>\n      <download-excel\n          class=\"export-excel-wrapper\"\n          :data=\"data\"\n          :fields=\"json_fields\"\n          name=\"库存报表.xls\">\n        <a-button class=\"editable-btn\">\n          <a-icon type=\"cloud-download\"/>\n          下载库存报表 Excel\n        </a-button>\n      </download-excel>\n      <a-button class=\"editable-btn\" @click=\"recordVisible = true\">\n        <a-icon type=\"retweet\"/>\n        出入库记录 Excel\n      </a-button>\n    </div>\n\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" rowKey=\"id\">\n      <a slot=\"name\" slot-scope=\"text\">{{ text }}</a>\n      <span slot=\"customTitle\"><a-icon type=\"smile-o\"/> 商品名</span>\n      <span slot=\"count\" slot-scope=\"count\">\n        <a-tag color=\"#108ee9\">{{ count }}</a-tag>\n      </span>\n    </a-table>\n\n    <a-modal\n        title=\"入库 ｜ 出库\"\n        :closable=\"false\"\n        :visible=\"visible\"\n        @ok=\"submit\"\n        @cancel=\"visible = false\"\n    >\n      <a-form-model :model=\"form\">\n        <a-form-model-item label=\"请选商品\">\n          <a-select v-model=\"selectIndex\" placeholder=\"请选择入库的商品\">\n            <a-select-option :value=\"index\" v-for=\"(item, index) in commodityList\" :key=\"index\">\n              {{ item.name }}\n            </a-select-option>\n          </a-select>\n        </a-form-model-item>\n        <a-form-model-item label=\"商品数量\">\n          <a-input-number id=\"inputNumber\" v-model=\"form.count\" :min=\"1\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"备注\">\n          <a-input :rows=\"4\" v-model=\"form.description\" type=\"textarea\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n    <a-modal\n        title=\"出入库记录\"\n        width=\"80%\"\n        :visible=\"recordVisible\"\n        :footer=\"null\"\n        @cancel=\"recordVisible = false\"\n    >\n      <InventoryRecords :warehouse-id=\"id\"/>\n    </a-modal>\n\n  </div>\n</template>\n\n<script>\nimport {FindAllCommodity} from \"../../api/commodity\";\nimport {FindAllInventory, InAndOut} from \"../../api/inventory\";\nimport InventoryRecords from \"../../components/InventoryRecords\";\n\nconst columns = [\n  {\n    title: '商品ID',\n    dataIndex: 'id',\n    key: 'id',\n    width: '50%'\n  },\n  {\n    dataIndex: 'name',\n    key: 'name',\n    slots: {title: 'customTitle'},\n    scopedSlots: {customRender: 'name'},\n  },\n  {\n    title: '库存数量',\n    dataIndex: 'count',\n    key: 'count',\n    scopedSlots: {customRender: 'count'},\n  },\n];\n\nexport default {\n\n  components: {InventoryRecords},\n\n  data() {\n    return {\n      json_fields: {\n        \"商品ID\": \"cid\",\n        \"商品名称\": \"name\",\n        \"库存盘点数量\": \"count\",\n      },\n      id: this.$route.params.id,\n      loading: false,\n      visible: false,\n      recordVisible: false,\n      selectIndex: 0,\n      commodityVisible: false,\n      data: [],\n      columns,\n      commodityList: [],\n      submitType: '',\n      form: {\n        wid: this.$route.params.id,\n        cid: '',\n        name: '',\n        description: '',\n        count: 50,\n      },\n    }\n  },\n\n  mounted() {\n    this.loadData()\n    FindAllCommodity().then((res) => {\n      if (res.status) this.commodityList = res.data\n    })\n  },\n\n  methods: {\n\n    loadData() {\n      this.loading = true\n      FindAllInventory(this.$route.params.id).then((res) => {\n        setTimeout(() => {\n          this.data = res.data\n          this.loading = false\n        }, 500)\n      })\n    },\n\n    handleSubmit(type) {\n      this.submitType = type\n      this.visible = true\n    },\n\n    submit() {\n      this.form.cid = this.commodityList[this.selectIndex].id\n      this.form.name = this.commodityList[this.selectIndex].name\n      InAndOut(this.submitType, this.form).then((res) => {\n        if (res.status) this.$message.success(\"操作成功\")\n        this.visible = false\n        this.loadData()\n      })\n    },\n\n  }\n\n}\n</script>\n\n\n<style scoped>\n.main {\n  background: #ffffff;\n  padding: 30px;\n}\n\n.header {\n  font-size: 18px;\n  margin-bottom: 40px;\n}\n\na {\n  color: #000000;\n}\n\n.header a:hover {\n  color: #5a84fd;\n}\n\n.editable-btn {\n  margin-bottom: 20px;\n  margin-right: 10px;\n}\n\n.in-icon {\n  transform: rotate(270deg);\n}\n</style>"
  },
  {
    "path": "web-app/src/views/basics/Employee.vue",
    "content": "<template>\n  <div>\n    <a-button size=\"large\" class=\"editable-add-btn\" @click=\"visible = true\">\n      <a-icon type=\"plus\"/>\n      新增员工\n    </a-button>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" bordered rowKey=\"id\">\n      <template\n          v-for=\"col in ['name', 'gender', 'phone','idCard','department', 'address']\"\n          :slot=\"col\"\n          slot-scope=\"text, record, index\"\n      >\n        <div :key=\"col\">\n          <a-input\n              v-if=\"record.editable\"\n              style=\"margin: -5px 0\"\n              :value=\"text\"\n              @change=\"e => handleChange(e.target.value, record.id, col)\"\n          />\n          <template v-else>\n            {{ text }}\n          </template>\n        </div>\n      </template>\n      <template slot=\"operation\" slot-scope=\"text, record, index\">\n        <div class=\"editable-row-operations\">\n        <span v-if=\"record.editable\">\n          <a @click=\"() => save(record.id, index)\">保存</a>\n          <a-popconfirm title=\"Sure to cancel?\" @confirm=\"() => cancel(record.id)\">\n            <a>取消</a>\n          </a-popconfirm>\n        </span>\n          <span v-else>\n          <a :disabled=\"editingKey !== ''\" @click=\"() => edit(record.id)\">编辑</a>\n        </span>\n          <a-popconfirm placement=\"top\" ok-text=\"Yes\" cancel-text=\"No\" @confirm=\"confirm(record.id)\">\n            <template slot=\"title\">\n              <p> 删除驾驶员信息后将无法恢复，确定要删除吗？ </p>\n            </template>\n            <a-button type=\"link\">删除</a-button>\n          </a-popconfirm>\n        </div>\n      </template>\n    </a-table>\n\n    <a-modal\n        title=\"Title\"\n        :visible=\"visible\"\n        @ok=\"submitForm\"\n        @cancel=\"visible = false\"\n    >\n      <a-form-model :model=\"form\">\n        <a-form-model-item label=\"姓名\">\n          <a-input v-model=\"form.name\" placeholder=\"请输入司机姓名\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"身份证号\">\n          <a-input v-model=\"form.idCard\" placeholder=\"请输入司机身份证信息\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"联系方式\">\n          <a-input v-model=\"form.phone\" placeholder=\"请输入手机号码\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"所在仓库\">\n          <a-select v-model=\"form.department\" v-for=\"(item,index) in warehouseList\" placeholder=\"请选择员工所在仓库\">\n            <a-select-option :value=\"item.name\">{{ item.name }}</a-select-option>\n          </a-select>\n        </a-form-model-item>\n        <a-form-model-item label=\"性别\">\n          <a-radio-group v-model=\"form.gender\">\n            <a-radio value=\"男性\">男性</a-radio>\n            <a-radio value=\"女性\">女性</a-radio>\n          </a-radio-group>\n        </a-form-model-item>\n        <a-form-model-item label=\"家庭住址\">\n          <a-input v-model=\"form.address\" type=\"textarea\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n  </div>\n</template>\n\n<script>\nimport {DeleteEmployeeById, FindAllEmployee, SaveEmployee} from \"@/api/employee\";\nimport {FindAllWarehouse} from \"../../api/warehouse\";\n\nconst columns = [\n  {\n    title: '名字',\n    dataIndex: 'name',\n    scopedSlots: {customRender: 'name'},\n  },\n  {\n    title: '性别',\n    dataIndex: 'gender',\n    scopedSlots: {customRender: 'gender'},\n  },\n  {\n    title: '所在部门',\n    dataIndex: 'department',\n    scopedSlots: {customRender: 'department'},\n  },\n  {\n    title: '联系电话',\n    dataIndex: 'phone',\n    scopedSlots: {customRender: 'phone'},\n  },\n  {\n    title: '身份证',\n    dataIndex: 'idCard',\n    scopedSlots: {customRender: 'idCard'},\n  },\n  {\n    title: '家庭住址',\n    dataIndex: 'address',\n    scopedSlots: {customRender: 'address'},\n  },\n  {\n    title: '操作',\n    dataIndex: 'operation',\n    scopedSlots: {customRender: 'operation'},\n  },\n];\n\nexport default {\n  data() {\n    return {\n      loading: false,\n      warehouseList: [],\n      form: {\n        cacheData: [],\n        name: '',\n        gender: '男性',\n        phone: '',\n        department: '',\n        address: '',\n        idCard: '',\n      },\n      visible: false,\n      data: [],\n      columns,\n      editingKey: '',\n    };\n  },\n  mounted() {\n    this.loadTableData()\n  },\n  methods: {\n\n    findAllWarehouse() {\n      FindAllWarehouse().then((res) => {\n        this.warehouseList = res.data\n      })\n    },\n\n    loadTableData() {\n      this.loading = true\n      this.findAllWarehouse()\n      FindAllEmployee().then((res) => {\n        if (res.status) {\n          this.data = res.data\n          this.cacheData = res.data.map(item => ({...item}))\n        }\n        setTimeout(() => {\n          this.loading = false\n        }, 600)\n      })\n    },\n\n    submitForm() {\n      SaveEmployee(this.form).then((res) => {\n        if (res.status) this.$message.success('员工信息提交成功');\n        this.visible = false\n        this.loadTableData()\n      })\n    },\n\n    handleChange(value, id, column) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      if (target) {\n        target[column] = value;\n        this.data = newData;\n      }\n    },\n    edit(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = id;\n      if (target) {\n        target.editable = true;\n        this.data = newData;\n      }\n    },\n\n    save(id, index) {\n      const newData = [...this.data];\n      const newCacheData = [...this.cacheData];\n      const target = newData.filter(item => id === item.id)[0];\n      const targetCache = newCacheData.filter(item => id === item.id)[0];\n      if (target && targetCache) {\n        delete target.editable;\n        this.data = newData;\n        Object.assign(targetCache, target);\n        this.cacheData = newCacheData;\n      }\n      this.editingKey = '';\n      SaveEmployee(newData[index]).then((res) => {\n        if (res.status) this.$message.success(\"信息保存成功\")\n      })\n    },\n    cancel(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = '';\n      if (target) {\n        Object.assign(target, this.cacheData.filter(item => id === item.id)[0]);\n        delete target.editable;\n        this.data = newData;\n      }\n    },\n    confirm(id) {\n      DeleteEmployeeById(id).then((res) => {\n        if (res.status) this.$message.success('Delete success');\n        this.loadTableData()\n      })\n    },\n  },\n};\n</script>\n<style scoped>\n\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n\n.editable-row-operations a {\n  margin-right: 8px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/basics/Warehouse.vue",
    "content": "<template>\n  <div>\n    <a-spin size=\"large\" :spinning=\"spinning\">\n      <a-row :gutter=\"20\">\n        <a-col :span=\"8\" class=\"item\">\n          <a-card hoverable class=\"add-item\" @click=\"visible = true\">\n            <a-icon type=\"plus\"/>\n            添加仓库\n          </a-card>\n        </a-col>\n        <a-col :span=\"8\" v-for=\"(item, index) in this.data\" :key=\"index\" class=\"item\">\n          <a-card hoverable>\n            <template slot=\"actions\" class=\"ant-card-actions\">\n              <span>负责人: {{ item.principle }}</span>\n              <span>\n                <router-link :to=\"'/warehouse/' + item.id\">\n                  <a-icon type=\"bar-chart\"/> 库存管理\n                </router-link>\n              </span>\n            </template>\n            <a-card-meta\n                :title=\"item.name\"\n                :description=\"'ID: ' + item.id\">\n              <img class=\"image\" slot=\"avatar\" :src=\"imgList[Math.floor(Math.random() * 3)]\"\n                   alt=\"\"/>\n            </a-card-meta>\n          </a-card>\n        </a-col>\n      </a-row>\n    </a-spin>\n\n    <a-modal\n        title=\"新增仓库\"\n        :visible=\"visible\"\n        @ok=\"submit\"\n        @cancel=\"visible = false\"\n    >\n      <a-input v-model=\"form.name\" addon-before=\"仓库名称\" style=\"width: 300px;margin-bottom: 20px\"></a-input>\n      <a-input v-model=\"form.principle\" addon-before=\"仓库负责人\" style=\"width: 300px\"></a-input>\n    </a-modal>\n  </div>\n</template>\n\n<script>\nimport {FindAllWarehouse, SaveWarehouse} from \"@/api/warehouse\";\n\nexport default {\n  name: \"WareHouse\",\n  data() {\n    return {\n      visible: false,\n      form: {id: '', principle: '', name: ''},\n      spinning: false,\n      data: [],\n      imgList: [\n        require('../../assets/warehouse0.svg'),\n        require('../../assets/warehouse1.svg'),\n        require('../../assets/warehouse2.svg'),]\n    }\n  },\n\n  mounted() {\n    this.loadData()\n  },\n\n  methods: {\n\n    loadData() {\n      this.spinning = true\n      FindAllWarehouse().then((res) => {\n        if (res.status) this.data = res.data\n        setTimeout(() => {\n          this.spinning = false\n        }, 600)\n      })\n    },\n\n    submit() {\n      SaveWarehouse(this.form).then((res) => {\n        if (res.status) this.$message.success(\"添加成功\")\n        this.visible = false\n        this.loadData()\n      })\n    }\n\n  },\n\n}\n</script>\n\n<style scoped>\n.add-item {\n  text-align: center;\n  line-height: 120px;\n  min-height: 120px;\n  border: 1px dashed #91949c;\n}\n\n.add-item:hover {\n  border: 1px dashed #5a84fd;\n  color: #5a84fd;\n}\n\n.item {\n  margin-bottom: 20px;\n}\n\n.image {\n  width: 80px;\n  height: 80px;\n}\n</style>"
  },
  {
    "path": "web-app/src/views/delivery/Create.vue",
    "content": "<template>\n  <div class=\"main\">\n    <a-steps :current=\"current\">\n      <a-step title=\"填写申请信息\"></a-step>\n      <a-step title=\"确认配送信息\"/>\n      <a-step title=\"完成申请\"/>\n    </a-steps>\n    <div class=\"steps-content\">\n      <div v-if=\"current === 0\">\n        <a-form-model :model=\"form\" :label-col=\"labelCol\" :wrapper-col=\"wrapperCol\">\n          <a-form-model-item label=\"选择司机\" required>\n            <a-select v-model=\"selectDriverIndex\" placeholder=\"请选择配送司机\">\n              <a-select-option :value=\"index\" v-for=\"(item, index) in drivers\" :key=\"index\" :disabled=\"item.driving\">\n                {{ item.name }}\n                <i class=\"dis\" v-if=\"item.driving\">\n                  <a-icon type=\"close-circle\"/>\n                  正在途中</i>\n              </a-select-option>\n            </a-select>\n          </a-form-model-item>\n          <a-form-model-item label=\"选择运输车辆\" required>\n            <a-select v-model=\"selectVehicleIndex\" placeholder=\"请选择配送车辆\">\n              <a-select-option :value=\"index\" v-for=\"(item, index) in vehicles\" :key=\"index\" :disabled=\"item.driving\">\n                {{ item.type }} : {{ item.number }}\n                <i class=\"dis\" v-if=\"item.driving\">\n                  <a-icon type=\"close-circle\"/>\n                  正在途中</i>\n              </a-select-option>\n            </a-select>\n          </a-form-model-item>\n          <a-form-model-item label=\"预计交货时间\" required>\n            <a-date-picker\n                v-model=\"form.time\"\n                show-time\n                type=\"date\"\n                placeholder=\"选择日期\"\n                style=\"width: 100%;\"\n            />\n          </a-form-model-item>\n          <a-form-model-item label=\"加急处理\">\n            <a-switch v-model=\"form.urgent\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"注意事项\">\n            <a-checkbox-group v-model=\"form.cares\">\n              <a-checkbox value=\"冰柜冷藏\" name=\"type\">\n                冰柜冷藏\n              </a-checkbox>\n              <a-checkbox value=\"注意易碎\" name=\"type\">\n                注意易碎\n              </a-checkbox>\n              <a-checkbox value=\"防止高温\" name=\"type\">\n                防止高温\n              </a-checkbox>\n            </a-checkbox-group>\n          </a-form-model-item>\n          <a-form-model-item label=\"客户电话\" required>\n            <a-input v-model=\"form.phone\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"客户地址\" required>\n            <a-input v-model=\"form.address\" type=\"textarea\" :rows=\"4\"/>\n          </a-form-model-item>\n          <a-form-model-item :wrapper-col=\"{ span: 14, offset: 6 }\">\n            <a-button type=\"primary\" @click=\"next\">\n              下一步\n            </a-button>\n          </a-form-model-item>\n        </a-form-model>\n      </div>\n      <div v-if=\"current === 1\" class=\"check\">\n        <p>送货司机： {{ form.driver }}</p>\n        <p>车牌号码： {{ form.number }}</p>\n        <p>加急处理： {{ form.urgent }}</p>\n        <p>注意事项： {{ form.care }}</p>\n        <p>客户电话： {{ form.phone }}</p>\n        <p>客户地址： {{ form.address }}</p>\n        <p>预计送达： {{ form.time }}</p>\n        <a-button type=\"danger\" style=\"margin-right: 20px\" :loading=\"loading\" @click=\"submit\">提交</a-button>\n        <a-button @click=\"current = 0\">上一步</a-button>\n      </div>\n      <div v-if=\"current === 2\">\n        <a-result\n            status=\"success\"\n            title=\"Submitted Successfully\"\n            sub-title=\"Please wait for the administrator to review the delivery request.\"\n        >\n          <template #extra>\n            <router-link to=\"/delivery/list\">\n              <a-button key=\"console\" type=\"primary\">\n                Go Console\n              </a-button>\n            </router-link>\n            <a-button key=\"buy\" @click=\"current = 0\">\n              Submit Again\n            </a-button>\n          </template>\n        </a-result>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport {FindAllCanUse, SaveDistribution} from \"../../api/distribution\";\n\nexport default {\n\n  data() {\n    return {\n      loading: false,\n      labelCol: {span: 6},\n      wrapperCol: {span: 12},\n      current: 0,\n      selectDriverIndex: 0,\n      selectVehicleIndex: 0,\n      drivers: [],\n      vehicles: [],\n      form: {\n        id: '',\n        did: '',\n        vid: '',\n        driver: '',\n        number: '',\n        phone: '',\n        address: '',\n        urgent: false,\n        cares: [],\n        care: '',\n        time: '',\n        status: 0,\n      },\n    }\n  },\n\n  mounted() {\n    FindAllCanUse().then((res) => {\n      if (res.status) {\n        this.drivers = res.data.drivers\n        this.vehicles = res.data.vehicles\n      }\n      console.log(this.drivers)\n      console.log(this.vehicles)\n    })\n  },\n\n  methods: {\n    next() {\n      let care = ''\n      for (let i = 0; i < this.form.cares.length; i++) {\n        care += this.form.cares[i] + \", \"\n      }\n      this.form.driver = this.drivers[this.selectDriverIndex].name\n      this.form.did = this.drivers[this.selectDriverIndex].id\n      this.form.number = this.vehicles[this.selectVehicleIndex].number\n      this.form.vid = this.vehicles[this.selectVehicleIndex].id\n      this.form.care = care\n      this.current = 1\n    },\n    submit() {\n      this.loading = true\n      SaveDistribution(this.form).then((res) => {\n        if (res.status) {\n          setTimeout(() => {\n            this.loading = false\n            this.current = 2\n            this.$message.success(\"提交成功，请等待审核\")\n          }, 800)\n        } else {\n          setTimeout(() => {\n            this.loading = false\n            this.$message.error(\"提交失败\")\n          }, 800)\n        }\n      })\n    },\n  },\n\n}\n</script>\n\n<style scoped>\n.main {\n  padding: 50px 180px;\n  background: #ffffff;\n}\n\n.steps-content {\n  margin-top: 40px;\n}\n\n.check {\n  padding-left: 200px;\n}\n\n.check p {\n  padding-bottom: 10px;\n}\n\n.dis {\n  padding-left: 10px;\n  font-size: 10px;\n  letter-spacing: 1px;\n  color: red;\n}\n\n</style>"
  },
  {
    "path": "web-app/src/views/delivery/List.vue",
    "content": "<template>\n  <div>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" bordered rowKey=\"id\">\n      <span slot=\"status\" slot-scope=\"status\">\n        <a-tag v-if=\"status===0\" color=\"#f50\">等待审核</a-tag>\n        <a-tag v-if=\"status===1\" color=\"#87d068\">正在运输</a-tag>\n        <a-tag v-if=\"status===2\" color=\"#2db7f5\">配送完成</a-tag>\n      </span>\n      <template\n          v-for=\"col in ['phone','address']\"\n          :slot=\"col\"\n          slot-scope=\"text, record, index\"\n      >\n        <div :key=\"col\">\n          <a-input\n              v-if=\"record.editable\"\n              style=\"margin: -5px 0\"\n              :value=\"text\"\n              @change=\"e => handleChange(e.target.value, record.id, col)\"\n          />\n          <template v-else>\n            {{ text }}\n          </template>\n        </div>\n      </template>\n      <template slot=\"operation\" slot-scope=\"text, record, index\">\n        <div class=\"editable-row-operations\">\n          <span v-if=\"record.editable\">\n          <a @click=\"() => save(record.id, index)\">保存</a>\n          <a-popconfirm title=\"Sure to cancel?\" @confirm=\"() => cancel(record.id)\">\n            <a>取消</a>\n          </a-popconfirm>\n        </span>\n          <span v-else>\n          <a :disabled=\"editingKey !== ''\" @click=\"() => edit(record.id)\">编辑</a>\n        </span>\n          <a-button @click=\"review(index)\" type=\"link\" v-if=\"record.status===0\">审核</a-button>\n          <a-button @click=\"review(index)\" type=\"link\" v-if=\"record.status===1\">配送</a-button>\n          <a-button @click=\"review(index)\" type=\"link\" v-if=\"record.status===2\">查看</a-button>\n        </div>\n      </template>\n    </a-table>\n\n    <a-modal\n        title=\"Title\"\n        :visible=\"visible\"\n        @ok=\"submitForm\"\n        @cancel=\"visible = false\"\n    >\n      <a-form-model :model=\"form\">\n        <a-form-model-item label=\"姓名\">\n          <a-input v-model=\"form.name\" placeholder=\"请输入司机姓名\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"身份证号\">\n          <a-input v-model=\"form.idCard\" placeholder=\"请输入司机身份证信息\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"联系方式\">\n          <a-input v-model=\"form.phone\" placeholder=\"请输入手机号码\"/>\n        </a-form-model-item>\n        <a-form-item label=\"驾照信息\">\n          <a-row :gutter=\"20\">\n            <a-col :span=\"12\">\n              <a-input v-model=\"form.license\" addon-before=\"驾驶证\" default-value=\"0571\"/>\n            </a-col>\n            <a-col :span=\"7\">\n              <a-input-number v-model=\"form.score\" addon-before=\"分数\" default-value=\"12\" :min=\"0\" :max=\"12\"/>\n            </a-col>\n          </a-row>\n        </a-form-item>\n        <a-form-model-item label=\"性别\">\n          <a-radio-group v-model=\"form.gender\">\n            <a-radio value=\"男性\">男性</a-radio>\n            <a-radio value=\"女性\">女性</a-radio>\n          </a-radio-group>\n        </a-form-model-item>\n        <a-form-model-item label=\"家庭住址\">\n          <a-input v-model=\"form.address\" type=\"textarea\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n    <a-modal\n        title=\"Title\"\n        :visible=\"visible2\"\n        width=\"60%\"\n        :footer=\"null\"\n        @cancel=\"visible2 = false\"\n    >\n      <a-steps :current=\"select.status\" style=\"padding: 50px\">\n        <a-step title=\"确认信息无误\"/>\n        <a-step title=\"开始配送\"/>\n        <a-step title=\"配送完成\"/>\n      </a-steps>\n      <div class=\"content\">\n        <div v-if=\"select.status === 0\" class=\"check\">\n          <p>送货司机： {{ select.driver }}</p>\n          <p>车牌号码： {{ select.number }}</p>\n          <p>加急处理： {{ select.urgent }}</p>\n          <p>注意事项： {{ select.care }}</p>\n          <p>客户电话： {{ select.phone }}</p>\n          <p>客户地址： {{ select.address }}</p>\n          <p>预计送达： {{ select.time }}</p>\n          <a-button type=\"danger\" style=\"margin-right: 20px\" :loading=\"loading\" @click=\"agree\">通过</a-button>\n          <a-button @click=\"visible2 = false\">不通过</a-button>\n        </div>\n        <div v-if=\"select.status === 1\">\n          <a-result\n              status=\"success\"\n              title=\"Successfully passed the audit!\"\n              >\n            <template #extra>\n              <a-button @click=\"service\" key=\"console\" type=\"primary\">\n                已送达目的地\n              </a-button>\n            </template>\n          </a-result>\n        </div>\n        <div v-if=\"select.status === 2\">\n          <a-result\n              status=\"success\"\n              title=\"运输订单已成功送达\"\n          >\n            <template #extra>\n              <a-button @click=\"visible2 = false\" key=\"console\" type=\"primary\">\n                确定\n              </a-button>\n            </template>\n          </a-result>\n        </div>\n      </div>\n\n    </a-modal>\n\n  </div>\n</template>\n\n<script>\nimport {FindAllDistribution, SaveDistribution} from \"../../api/distribution\";\n\nconst columns = [\n  {\n    title: '司机',\n    dataIndex: 'driver',\n    scopedSlots: {customRender: 'driver'},\n  },\n  {\n    title: '车牌号',\n    dataIndex: 'number',\n    scopedSlots: {customRender: 'number'},\n  },\n  {\n    title: '客户电话',\n    dataIndex: 'phone',\n    scopedSlots: {customRender: 'phone'},\n  },\n  {\n    title: '客户地址',\n    dataIndex: 'address',\n    scopedSlots: {customRender: 'address'},\n  },\n  {\n    title: '注意事项',\n    dataIndex: 'care',\n    scopedSlots: {customRender: 'care'},\n  },\n  {\n    title: '预计送达',\n    dataIndex: 'time',\n    scopedSlots: {customRender: 'time'},\n  },\n  {\n    title: '当前状态',\n    dataIndex: 'status',\n    scopedSlots: {customRender: 'status'},\n  },\n  {\n    title: '操作',\n    dataIndex: 'operation',\n    scopedSlots: {customRender: 'operation'},\n  },\n];\n\nexport default {\n  data() {\n    return {\n      select: {},\n      loading: false,\n      form: {\n        cacheData: [],\n        name: '',\n        gender: '男性',\n        phone: '',\n        address: '',\n        idCard: '',\n        license: '',\n        score: 12,\n      },\n      visible: false,\n      visible2: false,\n      data: [],\n      columns,\n      editingKey: '',\n    };\n  },\n  mounted() {\n    this.loadTableData()\n  },\n  methods: {\n    loadTableData() {\n      this.loading = true\n      FindAllDistribution().then((res) => {\n        if (res.status) {\n          this.data = res.data\n          this.cacheData = res.data.map(item => ({...item}))\n        }\n        setTimeout(() => {\n          this.loading = false\n        }, 600)\n      })\n    },\n    submitForm() {\n      SaveDistribution(this.form).then((res) => {\n        if (res.status) this.$message.success('司机信息提交成功');\n        this.visible = false\n        this.loadTableData()\n      })\n    },\n    handleChange(value, id, column) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      if (target) {\n        target[column] = value;\n        this.data = newData;\n      }\n    },\n    edit(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = id;\n      if (target) {\n        target.editable = true;\n        this.data = newData;\n      }\n    },\n\n    save(id, index) {\n      const newData = [...this.data];\n      const newCacheData = [...this.cacheData];\n      const target = newData.filter(item => id === item.id)[0];\n      const targetCache = newCacheData.filter(item => id === item.id)[0];\n      if (target && targetCache) {\n        delete target.editable;\n        this.data = newData;\n        Object.assign(targetCache, target);\n        this.cacheData = newCacheData;\n      }\n      this.editingKey = '';\n      SaveDistribution(newData[index]).then((res) => {\n        if (res.status) this.$message.success(\"信息保存成功\")\n      })\n    },\n\n    cancel(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = '';\n      if (target) {\n        Object.assign(target, this.cacheData.filter(item => id === item.id)[0]);\n        delete target.editable;\n        this.data = newData;\n      }\n    },\n\n    review(index) {\n      this.select = this.data[index]\n      this.visible2 = true\n    },\n\n    agree() {\n      this.select.status = 1\n      SaveDistribution(this.select)\n    },\n\n    service(){\n      this.select.status = 2\n      SaveDistribution(this.select)\n    },\n\n  },\n};\n</script>\n<style scoped>\n\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n\n.editable-row-operations a {\n  margin-right: 8px;\n}\n\n.content {\n  padding: 50px 0;\n}\n\n\n.check {\n  padding-left: 200px;\n}\n\n.check p {\n  padding-bottom: 20px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/error/403.vue",
    "content": "<template>\n  <a-result status=\"403\" title=\"403\" sub-title=\"Sorry, you are not authorized to access this page.\">\n    <template #extra>\n      <a-button type=\"primary\" @click=\"clickBtn\" style=\"letter-spacing: 1px\">\n        <a-icon type=\"enter\" />Return\n      </a-button>\n    </template>\n  </a-result>\n</template>\n<script>\nexport default {\n  data() {\n    return {};\n  },\n\n  methods: {\n\n    clickBtn() {\n      this.$router.go(-1)\n    },\n\n  }\n\n};\n</script>\n"
  },
  {
    "path": "web-app/src/views/error/404.vue",
    "content": "<template>\n  <a-result status=\"404\" title=\"404\" sub-title=\"Sorry, the page you visited does not exist.\">\n    <template #extra>\n      <a-button type=\"primary\" @click=\"clickBtn\" style=\"letter-spacing: 1px\">\n        <a-icon type=\"enter\" />Return\n      </a-button>\n    </template>\n  </a-result>\n</template>\n<script>\nexport default {\n  data() {\n    return {};\n  },\n\n  methods: {\n\n    clickBtn() {\n      this.$router.go(-1)\n    },\n\n  }\n\n};\n</script>\n"
  },
  {
    "path": "web-app/src/views/error/500.vue",
    "content": "<template>\n  <a-result status=\"500\" title=\"500\" sub-title=\"Sorry, the server is wrong.\">\n    <template #extra>\n      <a-button type=\"primary\" @click=\"clickBtn\" style=\"letter-spacing: 1px\">\n        <a-icon type=\"enter\" />Return\n      </a-button>\n    </template>\n  </a-result>\n</template>\n<script>\nexport default {\n  data() {\n    return {};\n  },\n\n  methods: {\n\n    clickBtn() {\n      this.$router.go(-1)\n    },\n\n  }\n\n};\n</script>\n"
  },
  {
    "path": "web-app/src/views/sale/Create.vue",
    "content": "<template>\n  <div class=\"main\">\n    <a-steps :current=\"current\">\n      <a-step title=\"填写信息\"></a-step>\n      <a-step title=\"确认信息\"/>\n      <a-step title=\"完成\"/>\n    </a-steps>\n    <div class=\"steps-content\">\n      <div v-if=\"current === 0\">\n        <a-form-model :model=\"form\" :label-col=\"labelCol\" :wrapper-col=\"wrapperCol\">\n          <a-form-model-item label=\"公司名称\" required>\n            <a-input v-model=\"form.company\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"打款账号\" required>\n            <a-input v-model=\"form.number\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"售出商品\" required>\n            <a-select v-model=\"selectIndex\" placeholder=\"请选择商品\">\n              <a-select-option :value=\"index\" v-for=\"(item, index) in commodityList\" :key=\"index\">\n                {{ item.name }}\n              </a-select-option>\n            </a-select>\n          </a-form-model-item>\n          <a-form-model-item label=\"商品数量\" required>\n            <a-input-number v-model=\"form.count\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"预留电话\" required>\n            <a-input v-model=\"form.phone\"/>\n          </a-form-model-item>\n          <a-form-model-item label=\"备注信息\" required>\n            <a-input v-model=\"form.description\" type=\"textarea\" :rows=\"4\"/>\n          </a-form-model-item>\n          <a-form-model-item :wrapper-col=\"{ span: 14, offset: 6 }\">\n            <a-button type=\"primary\" @click=\"next\">\n              下一步\n            </a-button>\n          </a-form-model-item>\n        </a-form-model>\n      </div>\n      <div v-if=\"current === 1\" class=\"check\">\n        <p>收货公司： {{ form.company }}</p>\n        <p>打款账号： {{ form.number }}</p>\n        <p>售出商品： {{ form.commodity }}</p>\n        <p>商品数量： {{ form.count }}</p>\n        <p>预留电话： {{ form.phone }}</p>\n        <p>备注信息： {{ form.description }}</p>\n        <a-divider orientation=\"right\">\n          金额总计： {{ form.price }}\n        </a-divider>\n        <a-button type=\"danger\" style=\"margin-right: 20px\" :loading=\"loading\" @click=\"submit\">提交</a-button>\n        <a-button @click=\"current = 0\">上一步</a-button>\n      </div>\n      <div v-if=\"current === 2\">\n        <a-result\n            status=\"success\"\n            title=\"Submitted Successfully\"\n            sub-title=\"Please wait for the administrator to review the delivery request.\"\n        >\n          <template #extra>\n            <router-link to=\"/sale/record\">\n              <a-button key=\"console\" type=\"primary\">\n                Go Back\n              </a-button>\n            </router-link>\n            <a-button key=\"buy\" @click=\"current = 0\">\n              Submit Again\n            </a-button>\n          </template>\n        </a-result>\n      </div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport {FindAllCommodity} from \"../../api/commodity\";\nimport {SaveSale} from \"../../api/sale\";\n\nexport default {\n\n  data() {\n    return {\n      loading: false,\n      labelCol: {span: 6},\n      wrapperCol: {span: 12},\n      current: 0,\n      selectIndex: 0,\n      drivers: [],\n      vehicles: [],\n      commodityList: [],\n      form: {\n        company: '',\n        number: '',\n        commodity: '',\n        count: 50,\n        price: 0,\n        phone: '',\n        description: '',\n      },\n    }\n  },\n\n  mounted() {\n    FindAllCommodity().then((res) => {\n      if (res.status) this.commodityList = res.data\n    })\n  },\n\n  methods: {\n    next() {\n      let commodity = this.commodityList[this.selectIndex]\n      this.form.price = this.form.count * commodity.price\n      this.form.commodity = commodity.name\n      console.log(this.form)\n      this.current = 1\n    },\n    submit() {\n      this.loading = true\n      SaveSale(this.form).then((res) => {\n        if (res.status) {\n          setTimeout(() => {\n            this.loading = false\n            this.current = 2\n            this.$message.success(\"提交成功\")\n          }, 800)\n        } else {\n          setTimeout(() => {\n            this.loading = false\n            this.$message.error(\"提交失败\")\n          }, 800)\n        }\n      })\n    },\n  },\n\n}\n</script>\n\n<style scoped>\n.main {\n  padding: 50px 180px;\n  background: #ffffff;\n}\n\n.steps-content {\n  margin-top: 40px;\n}\n\n.check {\n  padding-left: 200px;\n}\n\n.check p {\n  padding-bottom: 10px;\n}\n\n.dis {\n  padding-left: 10px;\n  font-size: 10px;\n  letter-spacing: 1px;\n  color: red;\n}\n\n</style>"
  },
  {
    "path": "web-app/src/views/sale/Record.vue",
    "content": "<template>\n  <div>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" rowKey=\"id\">\n      <a slot=\"company\" slot-scope=\"company\">{{ company }}</a>\n      <span slot=\"customTitle\"><a-icon type=\"bank\" /> 公司名称</span>\n      <span slot=\"action\" slot-scope=\"text, record, index\">\n        <a-tag color=\"red\" v-if=\"!record.pay\">等待结款</a-tag>\n        <a-tag color=\"green\" v-if=\"record.pay\">结款完成</a-tag>\n        <a-button v-if=\"!record.pay\" type=\"link\" @click=\"confirm(record, index)\">结款</a-button>\n      </span>\n    </a-table>\n\n  </div>\n</template>\n\n<script>\nimport {FindAllSale, SaveSale} from \"../../api/sale\";\n\nconst columns = [\n  {\n    dataIndex: 'company',\n    key: 'company',\n    slots: {title: 'customTitle'},\n    scopedSlots: {customRender: 'company'},\n  },\n  {\n    title: '打款帐号',\n    dataIndex: 'number',\n    key: 'number',\n  },\n  {\n    title: '商品',\n    dataIndex: 'commodity',\n    key: 'commodity',\n  },\n  {\n    title: '数量',\n    dataIndex: 'count',\n    key: 'count',\n  },\n  {\n    title: '总计',\n    dataIndex: 'price',\n    key: 'price',\n  },\n  {\n    title: '预留电话',\n    key: 'phone',\n    dataIndex: 'phone',\n  },\n  {\n    title: '备注',\n    dataIndex: 'description',\n    key: 'description',\n  },\n  {\n    title: '开票时间',\n    dataIndex: 'createAt',\n    key: 'createAt',\n  },\n  {\n    title: '更多操作',\n    key: 'action',\n    scopedSlots: {customRender: 'action'},\n  },\n];\n\nconst data = [];\n\nexport default {\n\n  data() {\n    return {\n      loading: false,\n      data: [],\n      columns,\n    };\n  },\n\n  mounted() {\n    this.loadTableData()\n  },\n\n  methods: {\n\n    loadTableData() {\n      this.loading = true\n      FindAllSale().then((res) => {\n        setTimeout(() => {\n          this.loading = false\n          this.data = res.data\n        }, 600)\n      })\n    },\n\n    confirm(record, index) {\n      let that = this\n      this.$confirm({\n        title: '销售结款',\n        content: '我已确定' + record.company + '的销售金额 ¥' + record.price + '已经打入账户!',\n        okText: '确认',\n        cancelText: '取消',\n        onOk() {\n          that.data[index].pay = true\n          SaveSale(that.data[index]).then((res) => {\n            if (res.status) that.$message.success(\"销售结款成功\")\n          })\n        },\n      });\n    },\n\n\n  },\n\n};\n</script>\n\n<style scoped>\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/system/Admin.vue",
    "content": "<template>\n  <div>\n    <a-button size=\"large\" class=\"editable-add-btn\" @click=\"addVisible = true\">\n      <a-icon type=\"plus\"/>\n      添加操作员\n    </a-button>\n    <a-table :columns=\"columns\" :data-source=\"admins\" rowKey=\"id\" :loading=\"loading\">\n      <a slot=\"email\" slot-scope=\"email\">{{ email }}</a>\n      <span slot=\"customTitle\"><a-icon type=\"smile-o\"/> 邮箱</span>\n      <span slot=\"tags\" slot-scope=\"tags\">\n      <a-tag\n          v-for=\"tag in tags\"\n          :key=\"tag\"\n          :color=\"tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'\"\n      >\n        {{ tag.toUpperCase() }}\n      </a-tag>\n    </span>\n      <span slot=\"action\" slot-scope=\"text, record, index\">\n      <a-dropdown>\n        <a class=\"ant-dropdown-link\" @click=\"e => e.preventDefault()\">Hover me <a-icon type=\"down\"/></a>\n        <a-menu slot=\"overlay\">\n          <a-menu-item>\n          <a-button type=\"link\" @click=\"updateEmail(index)\"><a-icon type=\"mail\"/> 邮箱修改</a-button>\n        </a-menu-item>\n      <a-menu-item>\n        <a-button type=\"link\" @click=\"updatePassword(index)\"><a-icon type=\"lock\"/> 密码修改</a-button>\n      </a-menu-item>\n      <a-menu-item>\n        <a-button type=\"link\" @click=\"updateRoles(index)\"><a-icon type=\"gateway\"/> 权限修改</a-button>\n      </a-menu-item>\n          <a-menu-item>\n        <a-button type=\"link\" @click=\"remove(record.id)\"><a-icon type=\"delete\"/> 删除</a-button>\n      </a-menu-item>\n    </a-menu>\n  </a-dropdown>\n    </span>\n    </a-table>\n\n    <a-modal\n        title=\"添加操作员\"\n        :visible=\"addVisible\"\n        @ok=\"submit\"\n        @cancel=\"addVisible = false\"\n    >\n      <a-form-model :model=\"selectAdmin\">\n        <a-form-model-item label=\"邮箱\">\n          <a-input v-model=\"selectAdmin.email\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"密码\">\n          <a-input v-model=\"selectAdmin.password\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n    <a-modal\n        title=\"密码修改\"\n        :visible=\"passwordVisible\"\n        @ok=\"submit\"\n        @cancel=\"passwordVisible = false\"\n    >\n      <a-form-model :model=\"selectAdmin\">\n        <a-form-model-item label=\"密码\">\n          <a-input v-model=\"selectAdmin.password\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n    <a-modal\n        title=\"邮箱修改\"\n        :visible=\"emailVisible\"\n        @ok=\"submit\"\n        @cancel=\"emailVisible = false\"\n    >\n      <a-form-model :model=\"selectAdmin\">\n        <a-form-model-item label=\"绑定邮箱\">\n          <a-input v-model=\"selectAdmin.email\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n    <a-modal\n        title=\"权限修改\"\n        width=\"500px\"\n        :visible=\"rolesVisible\"\n        @ok=\"submitRoles\"\n        @cancel=\"rolesVisible = false\"\n    >\n      <a-select\n          v-model=\"selectRoles\"\n          mode=\"multiple\"\n          style=\"width: 100%\"\n          placeholder=\"select one country\"\n          option-label-prop=\"label\"\n      >\n        <a-select-option :value=\"item.value\"\n                         :label=\"item.value\"\n                         v-for=\"(item ,index) in roles\"\n                         :key=\"index\">\n          <span role=\"img\" :aria-label=\"item.value\">🇨🇳</span>{{ item.value + ' (描述: ' + item.description + ')' }}\n        </a-select-option>\n      </a-select>\n    </a-modal>\n\n  </div>\n</template>\n<script>\nimport {DeleteAdmin, FindAllAdmin, SaveAdmin} from \"../../api/admin\";\nimport {FindAllRole} from \"../../api/role\";\n\nconst columns = [\n  {\n    dataIndex: 'email',\n    key: 'email',\n    slots: {title: 'customTitle'},\n    scopedSlots: {customRender: 'email'},\n  },\n  {\n    title: '密码',\n    dataIndex: 'password',\n    key: 'password',\n  },\n  {\n    title: '权限',\n    dataIndex: 'roles',\n    key: 'roles',\n  },\n  {\n    title: '添加日期',\n    key: 'createAt',\n    dataIndex: 'createAt',\n    scopedSlots: {customRender: 'createAt'},\n  },\n  {\n    title: 'Action',\n    key: 'action',\n    scopedSlots: {customRender: 'action'},\n  },\n];\n\nexport default {\n  data() {\n    return {\n      roles: [],\n      selectRoles: [],\n      admins: [],\n      loading: false,\n      addVisible: false,\n      emailVisible: false,\n      passwordVisible: false,\n      rolesVisible: false,\n      columns,\n      selectAdmin: {},\n    };\n  },\n\n  mounted() {\n    this.load()\n  },\n\n  methods: {\n\n    load() {\n      this.loading = true\n      FindAllRole().then((res) => {\n        if (res.status) this.roles = res.data\n      })\n      FindAllAdmin().then((res) => {\n        setTimeout(() => {\n          this.admins = res.data\n          this.loading = false\n        }, 600)\n      })\n    },\n\n    submit() {\n      SaveAdmin(this.selectAdmin).then((res) => {\n        if (res.status) this.$message.success(\"操作员信息更新成功\")\n        this.addVisible = false\n        this.emailVisible = false\n        this.rolesVisible = false\n        this.passwordVisible = false\n        this.load()\n      })\n    },\n\n    submitRoles() {\n      let str = ''\n      for (let i = 0; i < this.selectRoles.length; i++) {\n        if (i === this.selectRoles.length - 1) {\n          str += this.selectRoles[i]\n        } else {\n          str += this.selectRoles[i] + \";\"\n        }\n      }\n      this.selectAdmin.roles = str\n      this.submit()\n    },\n\n    updateEmail(index) {\n      this.emailVisible = true\n      this.selectAdmin = this.admins[index]\n    },\n\n    updatePassword(index) {\n      this.passwordVisible = true\n      this.selectAdmin = this.admins[index]\n    },\n\n    updateRoles(index) {\n      this.rolesVisible = true\n      this.selectAdmin = this.admins[index]\n      this.selectRoles = this.selectAdmin.roles.split(\";\")\n      console.log(this.selectRoles)\n    },\n\n    remove(id) {\n      DeleteAdmin(id).then((res) => {\n        if (res.status) this.$message.success(\"操作员删除成功\")\n        this.load()\n      })\n    },\n\n\n  },\n\n};\n</script>\n\n<style scoped>\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/system/Role.vue",
    "content": "<template>\n  <div class=\"main\">\n    <div class=\"title\">系统权限列表</div>\n    <a-spin size=\"large\" :spinning=\"spinning\">\n      <div v-for=\"(item, index) in roles\" :key=\"index\">\n        <a class=\"item-title\" type=\"link\">{{ item.value }}</a>\n        <p class=\"des\">描述信息： {{ item.description }}</p>\n        <a-divider/>\n      </div>\n    </a-spin>\n  </div>\n</template>\n\n<script>\n\nimport {FindAllRole} from \"../../api/role\";\n\nexport default {\n  name: \"Me\",\n\n  data() {\n    return {\n      roles: [],\n      spinning: false,\n    }\n  },\n\n  mounted() {\n    this.spinning = true\n    FindAllRole().then((res) => {\n      if (res.status) this.roles = res.data\n      setTimeout(() => {\n        this.spinning = false\n      }, 500)\n    })\n  },\n\n}\n</script>\n\n<style scoped>\n.main {\n  background: #ffffff;\n  padding: 50px 70px;\n}\n\n.title {\n  letter-spacing: 1px;\n  font-size: 20px;\n  font-weight: bolder;\n  color: #000000;\n  margin-bottom: 30px;\n}\n\n.btn {\n  float: right;\n}\n\n.item-title {\n  color: rgba(0, 0, 0, .8);\n  line-height: 35px;\n}\n\n.item-title:hover {\n  color: #5a84fd;\n}\n\n.des {\n  color: rgba(0, 0, 0, .5);\n}\n</style>"
  },
  {
    "path": "web-app/src/views/system/Security.vue",
    "content": "<template>\n  <div class=\"main\">\n    <div class=\"title\">安全设置</div>\n    <a-spin size=\"large\" :spinning=\"spinning\">\n      <div>\n        <a class=\"item-title\" type=\"link\">账号密码</a>\n        <a-button class=\"btn\" @click=\"passwordVisible = true\" type=\"link\">修改</a-button>\n        <p class=\"des\">账号密码： {{ show ? this.$store.state.user.details.password : '********' }}\n          <a @click=\"show = !show\" style=\"padding-left: 10px\">\n            <a-icon :type=\"!show ? 'eye' : 'eye-invisible' \"/>\n          </a>\n        </p>\n        <a-divider/>\n      </div>\n      <div>\n        <a class=\"item-title\" type=\"link\">绑定邮箱</a>\n        <a-button class=\"btn\" @click=\"emailVisible = true\" type=\"link\">修改</a-button>\n        <p class=\"des\">已绑定邮箱： {{ this.$store.state.user.details.email }}</p>\n        <a-divider/>\n      </div>\n    </a-spin>\n\n    <a-modal\n        title=\"密码修改\"\n        :visible=\"passwordVisible\"\n        @ok=\"submit\"\n        @cancel=\"passwordVisible = false\"\n    >\n      <a-form-model :model=\"admin\">\n        <a-form-model-item label=\"密码\">\n          <a-input v-model=\"admin.password\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n    <a-modal\n        title=\"邮箱修改\"\n        :visible=\"emailVisible\"\n        @ok=\"submit\"\n        @cancel=\"emailVisible = false\"\n    >\n      <a-form-model :model=\"admin\">\n        <a-form-model-item label=\"绑定邮箱\">\n          <a-input v-model=\"admin.email\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n  </div>\n</template>\n\n<script>\nimport {SaveAdmin} from \"@/api/admin\";\n\nexport default {\n  name: \"Me\",\n\n  data() {\n    return {\n      admin: this.$store.state.user.details,\n      show: false,\n      emailVisible: false,\n      passwordVisible: false,\n      spinning: false,\n    }\n  },\n\n  mounted() {\n    this.load()\n  },\n\n\n  methods: {\n\n    load() {\n      this.spinning = true\n      setTimeout(() => {\n        this.spinning = false\n      }, 500)\n    },\n\n    submit() {\n      SaveAdmin(this.admin).then((res) => {\n        if (res.status) {\n          this.$message.success(\"账号信息修改成功\")\n          this.$store.commit('user/saveLoginUser', res.data)\n        }\n      })\n      this.emailVisible = false\n      this.passwordVisible = false\n      this.load()\n    },\n\n  }\n\n}\n</script>\n\n<style scoped>\n.main {\n  background: #ffffff;\n  padding: 50px 70px;\n}\n\n.title {\n  letter-spacing: 1px;\n  font-size: 20px;\n  font-weight: bolder;\n  color: #000000;\n  margin-bottom: 30px;\n}\n\n.btn {\n  float: right;\n}\n\n.item-title {\n  color: rgba(0, 0, 0, .8);\n  line-height: 35px;\n}\n\n.item-title:hover {\n  color: #5a84fd;\n}\n\n.des {\n  color: rgba(0, 0, 0, .5);\n}\n</style>"
  },
  {
    "path": "web-app/src/views/transport/Driver.vue",
    "content": "<template>\n  <div>\n    <a-button size=\"large\" class=\"editable-add-btn\" @click=\"visible = true\">\n      <a-icon type=\"plus\"/>\n      新增驾驶员\n    </a-button>\n    <a-table :loading=\"loading\" :columns=\"columns\" :data-source=\"data\" bordered rowKey=\"id\">\n      <template\n          v-for=\"col in ['name', 'gender', 'phone','score','idCard','address', 'license']\"\n          :slot=\"col\"\n          slot-scope=\"text, record, index\"\n      >\n        <div :key=\"col\">\n          <a-input\n              v-if=\"record.editable\"\n              style=\"margin: -5px 0\"\n              :value=\"text\"\n              @change=\"e => handleChange(e.target.value, record.id, col)\"\n          />\n          <template v-else>\n            {{ text }}\n          </template>\n        </div>\n      </template>\n      <template slot=\"operation\" slot-scope=\"text, record, index\">\n        <div class=\"editable-row-operations\">\n        <span v-if=\"record.editable\">\n          <a @click=\"() => save(record.id, index)\">保存</a>\n          <a-popconfirm title=\"Sure to cancel?\" @confirm=\"() => cancel(record.id)\">\n            <a>取消</a>\n          </a-popconfirm>\n        </span>\n          <span v-else>\n          <a :disabled=\"editingKey !== ''\" @click=\"() => edit(record.id)\">编辑</a>\n        </span>\n          <a-popconfirm placement=\"top\" ok-text=\"Yes\" cancel-text=\"No\" @confirm=\"confirm(record.id)\">\n            <template slot=\"title\">\n              <p> 删除驾驶员信息后将无法恢复，确定要删除吗？ </p>\n            </template>\n            <a-button type=\"link\">删除</a-button>\n          </a-popconfirm>\n        </div>\n      </template>\n    </a-table>\n\n    <a-modal\n        title=\"Title\"\n        :visible=\"visible\"\n        @ok=\"submitForm\"\n        @cancel=\"visible = false\"\n    >\n      <a-form-model :model=\"form\">\n        <a-form-model-item label=\"姓名\">\n          <a-input v-model=\"form.name\" placeholder=\"请输入司机姓名\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"身份证号\">\n          <a-input v-model=\"form.idCard\" placeholder=\"请输入司机身份证信息\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"联系方式\">\n          <a-input v-model=\"form.phone\" placeholder=\"请输入手机号码\"/>\n        </a-form-model-item>\n        <a-form-item label=\"驾照信息\">\n          <a-row :gutter=\"20\">\n            <a-col :span=\"12\">\n              <a-input v-model=\"form.license\" addon-before=\"驾驶证\" default-value=\"0571\"/>\n            </a-col>\n            <a-col :span=\"7\">\n              <a-input-number v-model=\"form.score\" addon-before=\"分数\" default-value=\"12\" :min=\"0\" :max=\"12\"/>\n            </a-col>\n          </a-row>\n        </a-form-item>\n        <a-form-model-item label=\"性别\">\n          <a-radio-group v-model=\"form.gender\">\n            <a-radio value=\"男性\">男性</a-radio>\n            <a-radio value=\"女性\">女性</a-radio>\n          </a-radio-group>\n        </a-form-model-item>\n        <a-form-model-item label=\"家庭住址\">\n          <a-input v-model=\"form.address\" type=\"textarea\"/>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n\n  </div>\n</template>\n\n<script>\nimport {DeleteDriverById, FindAllDriver, SaveDriver} from \"@/api/driver\";\n\nconst columns = [\n  {\n    title: '名字',\n    dataIndex: 'name',\n    scopedSlots: {customRender: 'name'},\n  },\n  {\n    title: '性别',\n    dataIndex: 'gender',\n    scopedSlots: {customRender: 'gender'},\n  },\n  {\n    title: '联系电话',\n    dataIndex: 'phone',\n    scopedSlots: {customRender: 'phone'},\n  },\n  {\n    title: '驾驶证',\n    dataIndex: 'license',\n    scopedSlots: {customRender: 'license'},\n  },\n  {\n    title: '驾证分数',\n    dataIndex: 'score',\n    scopedSlots: {customRender: 'score'},\n  },\n  {\n    title: '身份证',\n    dataIndex: 'idCard',\n    scopedSlots: {customRender: 'idCard'},\n  },\n  {\n    title: '家庭住址',\n    dataIndex: 'address',\n    scopedSlots: {customRender: 'address'},\n  },\n  {\n    title: '操作',\n    dataIndex: 'operation',\n    scopedSlots: {customRender: 'operation'},\n  },\n];\n\nexport default {\n  data() {\n    return {\n      loading: false,\n      form: {\n        cacheData: [],\n        name: '',\n        gender: '男性',\n        phone: '',\n        address: '',\n        idCard: '',\n        license: '',\n        score: 12,\n      },\n      visible: false,\n      data: [],\n      columns,\n      editingKey: '',\n    };\n  },\n  mounted() {\n    this.loadTableData()\n  },\n  methods: {\n    loadTableData() {\n      this.loading = true\n      FindAllDriver().then((res) => {\n        if (res.status) {\n          this.data = res.data\n          this.cacheData = res.data.map(item => ({...item}))\n        }\n        setTimeout(() => {\n          this.loading = false\n        }, 600)\n      })\n    },\n    submitForm() {\n      SaveDriver(this.form).then((res) => {\n        if (res.status) this.$message.success('司机信息提交成功');\n        this.visible = false\n        this.loadTableData()\n      })\n    },\n    handleChange(value, id, column) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      if (target) {\n        target[column] = value;\n        this.data = newData;\n      }\n    },\n    edit(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = id;\n      if (target) {\n        target.editable = true;\n        this.data = newData;\n      }\n    },\n    save(id, index) {\n      const newData = [...this.data];\n      const newCacheData = [...this.cacheData];\n      const target = newData.filter(item => id === item.id)[0];\n      const targetCache = newCacheData.filter(item => id === item.id)[0];\n      if (target && targetCache) {\n        delete target.editable;\n        this.data = newData;\n        Object.assign(targetCache, target);\n        this.cacheData = newCacheData;\n      }\n      this.editingKey = '';\n      SaveDriver(newData[index]).then((res) => {\n        if (res.status) this.$message.success(\"信息保存成功\")\n      })\n    },\n    cancel(id) {\n      const newData = [...this.data];\n      const target = newData.filter(item => id === item.id)[0];\n      this.editingKey = '';\n      if (target) {\n        Object.assign(target, this.cacheData.filter(item => id === item.id)[0]);\n        delete target.editable;\n        this.data = newData;\n      }\n    },\n    confirm(id) {\n      DeleteDriverById(id).then((res) => {\n        if (res.status)  this.$message.success('Delete success');\n        this.loadTableData()\n      })\n    },\n  },\n};\n</script>\n<style scoped>\n\n.editable-add-btn {\n  margin-bottom: 15px;\n}\n\n.editable-row-operations a {\n  margin-right: 8px;\n}\n</style>\n"
  },
  {
    "path": "web-app/src/views/transport/Vehicle.vue",
    "content": "<template>\n  <div>\n    <a-spin size=\"large\" :spinning=\"spinning\">\n      <a-row :gutter=\"20\">\n        <a-col :span=\"8\" class=\"item\">\n          <a-card hoverable class=\"add-item\" @click=\"visible = true\">\n            <a-icon type=\"plus\"/>\n            添加车辆\n          </a-card>\n        </a-col>\n        <a-col :span=\"8\" v-for=\"(item, index) in this.data\" :key=\"index\" class=\"item\">\n          <a-card hoverable>\n            <template slot=\"actions\" class=\"ant-card-actions\">\n              <a-tag :color=\" item.driving ? 'orange': 'green'\">{{ item.driving ? '正在途中' : '正在休息' }}</a-tag>\n              <span>使用记录</span>\n            </template>\n            <a-card-meta\n                :title=\"'车牌号：' + item.number\"\n                :description=\"'ID: ' + item.id\">\n              <a-badge :number-style=\"{ backgroundColor: '#52c41a' }\"\n                       slot=\"avatar\"\n                       :count=\"item.type\"\n                       :offset=\"[-80,10]\">\n                <img class=\"image\" :src=\"require('../../assets/' +item.type+'.svg')\" alt=\"\"/>\n              </a-badge>\n            </a-card-meta>\n          </a-card>\n        </a-col>\n      </a-row>\n    </a-spin>\n    <a-modal\n        title=\"新增仓库\"\n        :visible=\"visible\"\n        @ok=\"submit\"\n        @cancel=\"visible = false\"\n    >\n      <a-form-model :model=\"form\">\n        <a-form-model-item label=\"车牌号码\">\n          <a-input v-model=\"form.number\"/>\n        </a-form-model-item>\n        <a-form-model-item label=\"车辆类型\">\n          <a-select v-model=\"form.type\">\n            <a-select-option value=\"小型汽车\">小型汽车</a-select-option>\n            <a-select-option value=\"货车\">货车</a-select-option>\n            <a-select-option value=\"卡车\">卡车</a-select-option>\n          </a-select>\n        </a-form-model-item>\n      </a-form-model>\n    </a-modal>\n  </div>\n</template>\n\n<script>\n\nimport {FindAllVehicle, SaveVehicle} from \"@/api/vehicle\";\n\nexport default {\n  name: \"WareHouse\",\n  data() {\n    return {\n      visible: false,\n      spinning: false,\n      form: {\n        number: '京A0000',\n        type: '货车',\n        driving: false,\n      },\n      data: [],\n      imgList: [\n        require('../../assets/warehouse0.svg'),\n        require('../../assets/warehouse1.svg'),\n        require('../../assets/warehouse2.svg'),]\n    }\n  },\n\n  mounted() {\n    this.loadData()\n  },\n\n  methods: {\n\n    loadData() {\n      this.spinning = true\n      FindAllVehicle().then((res) => {\n        if (res.status) this.data = res.data\n        setTimeout(() => {\n          this.spinning = false\n        }, 600)\n      })\n    },\n\n    submit() {\n      SaveVehicle(this.form).then((res) => {\n        if (res.status) this.$message.success(\"添加成功\")\n        this.visible = false\n        this.loadData()\n      })\n    }\n\n  },\n\n}\n</script>\n\n<style scoped>\n.add-item {\n  text-align: center;\n  line-height: 120px;\n  min-height: 120px;\n  border: 1px dashed #91949c;\n}\n\n.add-item:hover {\n  border: 1px dashed #5a84fd;\n  color: #5a84fd;\n}\n\n.item {\n  margin-bottom: 20px;\n}\n\n.image {\n  width: 80px;\n  height: 80px;\n  margin-left: 20px;\n}\n</style>"
  }
]