Merge branch 'main' into production
							
								
								
									
										52
									
								
								README.md
									
									
									
									
									
								
							
							
						
						@@ -214,9 +214,7 @@ cd ../
 | 
			
		||||
# ############
 | 
			
		||||
# 进入 frontend 目录
 | 
			
		||||
cd frontend
 | 
			
		||||
# 建议使用 cnpm 安装依赖,如果没有安装 cnpm,可以通过 npm i cnpm 进行安装
 | 
			
		||||
cnpm install
 | 
			
		||||
# npm install --legacy-peer-deps
 | 
			
		||||
npm install
 | 
			
		||||
# 回到项目根目录下
 | 
			
		||||
cd ../
 | 
			
		||||
```
 | 
			
		||||
@@ -306,6 +304,17 @@ npm run package
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 管理员前端项目打包并嵌入后端
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cd frontend
 | 
			
		||||
npm run build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
然后将 `frontend/dist` 文件夹移动到 `backend/microservice-gateway/src/main/resources/static` 文件夹下,并修改文件夹名称 `dist` 为 `manage`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 后端配置
 | 
			
		||||
 | 
			
		||||
##### 配置业务域名
 | 
			
		||||
@@ -314,6 +323,9 @@ npm run package
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
const baseUrl = "https://【⚠此处修改为你的业务域名】/" // 以 / 结尾,例如:https://epp.only4.work/
 | 
			
		||||
 | 
			
		||||
// 或者也可使用相对路径,例如:
 | 
			
		||||
const baseUrl = "/"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -321,7 +333,7 @@ const baseUrl = "https://【⚠此处修改为你的业务域名】/" // 以 / 
 | 
			
		||||
修改 `backend/microservice-provider-access-8002/src/main/resources/static/access/assets/js/websocket.js` 文件
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
window.wsUrl = 'ws://【⚠此处修改为你的业务域名】/access/websocket/1';
 | 
			
		||||
window.wsUrl = 'ws://【⚠此处修改为你的业务域名】/access/websocket/';
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> 注意,如果使用了 SSL 证书,那么 ws:// 要换成 wss://
 | 
			
		||||
@@ -350,6 +362,22 @@ const envVersion = "【⚠此处修改为当前小程序环境】" // 正式版
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##### 配置 Gateway 限流策略(可选)
 | 
			
		||||
 | 
			
		||||
> 如果你不懂这是在做什么,请直接跳过这一步
 | 
			
		||||
 | 
			
		||||
修改 `backend/microservice-gateway/src/main/resources/application.yml` 文件中 `routes` 中各个微服务的 `filters` 例如:
 | 
			
		||||
 | 
			
		||||
```yml
 | 
			
		||||
          filters: # 路由过滤器,使用自定义的限流过滤器工厂
 | 
			
		||||
            - name: RateLimitByIp # 设置每秒允许5个请求,每次请求需要1个令牌
 | 
			
		||||
              args:
 | 
			
		||||
                rate: 5.0
 | 
			
		||||
                permits: 1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##### 打 jar 包
 | 
			
		||||
 | 
			
		||||
IDEA 中右侧 Maven 双击 Lifestyle 的 package,打包完成后的 jar 包可在以下位置找到
 | 
			
		||||
@@ -389,6 +417,7 @@ IDEA 中右侧 Maven 双击 Lifestyle 的 package,打包完成后的 jar 包
 | 
			
		||||
🌟若使用的 Nacos 版本大于或等于 Nacos 2.2.0.1,则需要配置自定义密钥:
 | 
			
		||||
 | 
			
		||||
```properties
 | 
			
		||||
# 密钥值可以自己指定,此处的自定义密钥来自 nacos 官网
 | 
			
		||||
nacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@@ -396,7 +425,9 @@ nacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### nginx 代理配置(可选)
 | 
			
		||||
#### nginx 代理配置
 | 
			
		||||
 | 
			
		||||
##### 反向代理(可选)
 | 
			
		||||
 | 
			
		||||
配置文件在 `nginx-conf` 目录下(不能直接拿来用,需要根据自己的实际情况来改)
 | 
			
		||||
 | 
			
		||||
@@ -409,6 +440,13 @@ server
 | 
			
		||||
    listen 80;
 | 
			
		||||
    listen 443 ssl http2;
 | 
			
		||||
 | 
			
		||||
    # 并发限制 限制当前站点最大并发数
 | 
			
		||||
    limit_conn perserver 50;
 | 
			
		||||
    # 单IP限制 限制单个IP访问最大并发数
 | 
			
		||||
    limit_conn perip 10;
 | 
			
		||||
    # 流量限制 限制每个请求的流量上限(单位:KB)
 | 
			
		||||
    limit_rate 8192k;
 | 
			
		||||
 | 
			
		||||
    # 核心配置
 | 
			
		||||
    location / {
 | 
			
		||||
        proxy_pass http://127.0.0.1:5203; # ⚠ Gateway 微服务项目本地运行的端口
 | 
			
		||||
@@ -425,6 +463,10 @@ server
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
##### SSL证书配置(可选)
 | 
			
		||||
 | 
			
		||||
如果域名配置为 https:// 则需要配置 SSL 证书。SSL证书可在 nginx 中进行配置,具体配置方法此处省略。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 启动项目
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								TODOs.md
									
									
									
									
									
								
							
							
						
						@@ -42,6 +42,28 @@
 | 
			
		||||
Java代码中小程序AppID、密钥处理,小程序代码中小程序AppID处理
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# TODO 全部域名配置的地方添加 FIXME 环境配置
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# VSCode 全局搜索排除
 | 
			
		||||
 | 
			
		||||
node_modules,./postman-collection,target,out,.idea,@deprecated
 | 
			
		||||
 | 
			
		||||
# host 文件地址
 | 
			
		||||
 | 
			
		||||
C:\Windows\System32\drivers\etc
 | 
			
		||||
 | 
			
		||||
配置项
 | 
			
		||||
 | 
			
		||||
127.0.0.1		epp.only4.work
 | 
			
		||||
127.0.0.1		epp-prod.only4.work
 | 
			
		||||
 | 
			
		||||
查看配置
 | 
			
		||||
 | 
			
		||||
ping epp.only4.work
 | 
			
		||||
ping epp-prod.only4.work
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 后端项目启动命令
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import java.util.Arrays;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public enum OrderStatus {
 | 
			
		||||
    PENDING("Pending", "等待确认"),
 | 
			
		||||
    PENDING("Pending", "等待支付"),
 | 
			
		||||
    PROCESSING("Processing", "已支付,等待发货中"),
 | 
			
		||||
    SHIPPED("Shipped", "已发货,等待确认收货"),
 | 
			
		||||
    DELIVERED("Delivered", "已送达"),
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,12 @@ import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@Accessors(chain = true) // 链式写法
 | 
			
		||||
public class Good {
 | 
			
		||||
public class Good implements Serializable {
 | 
			
		||||
    Long id;
 | 
			
		||||
    String goodsName;
 | 
			
		||||
    Integer categoryId;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,12 @@ import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@Accessors(chain = true) // 链式写法
 | 
			
		||||
public class GoodCategory {
 | 
			
		||||
public class GoodCategory implements Serializable {
 | 
			
		||||
    Long id;
 | 
			
		||||
    String categoryName;
 | 
			
		||||
    Integer order;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,14 @@ import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.math.BigDecimal;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@Accessors(chain = true) // 链式写法
 | 
			
		||||
public class Order {
 | 
			
		||||
public class Order implements Serializable {
 | 
			
		||||
    private Long id;
 | 
			
		||||
    private Integer userId;
 | 
			
		||||
    private LocalDateTime orderDate;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,12 @@ import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@Accessors(chain = true) // 链式写法
 | 
			
		||||
public class OrderDetail {
 | 
			
		||||
public class OrderDetail implements Serializable {
 | 
			
		||||
    private Long id;
 | 
			
		||||
    private Long orderId;
 | 
			
		||||
    private Long goodId;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
package com.cxyxiaomo.epp.common.query;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@Accessors(chain = true) // 链式写法
 | 
			
		||||
// 微服务必须要实现Serializable
 | 
			
		||||
public class OrderQuery implements Serializable {
 | 
			
		||||
    private Long id;
 | 
			
		||||
    private Integer userId;
 | 
			
		||||
    private String orderStatusCode;
 | 
			
		||||
    private String expressId;
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,6 @@ import org.springframework.beans.BeanUtils;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.math.RoundingMode;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@@ -22,10 +21,10 @@ import java.util.stream.Collectors;
 | 
			
		||||
public class OrderVO implements Serializable {
 | 
			
		||||
    private String id;
 | 
			
		||||
    private Integer userId;
 | 
			
		||||
    private LocalDateTime orderDate;
 | 
			
		||||
    private String orderStatus;
 | 
			
		||||
    private String orderStatusCode;
 | 
			
		||||
    private String orderPrice;
 | 
			
		||||
    private String orderDate;
 | 
			
		||||
    private String payDate;
 | 
			
		||||
    private String cancelDate;
 | 
			
		||||
    private String shipDate;
 | 
			
		||||
@@ -47,6 +46,9 @@ public class OrderVO implements Serializable {
 | 
			
		||||
        String price = order.getOrderPrice().setScale(2, RoundingMode.FLOOR).toPlainString();
 | 
			
		||||
        orderVO.setOrderPrice(price);
 | 
			
		||||
 | 
			
		||||
        if (order.getOrderDate() != null) {
 | 
			
		||||
            orderVO.setOrderDate(order.getOrderDate().toString().replace("T", " "));
 | 
			
		||||
        }
 | 
			
		||||
        if (order.getPayDate() != null) {
 | 
			
		||||
            orderVO.setPayDate(order.getPayDate().toString().replace("T", " "));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
package com.cxyxiaomo.epp.gateway.Factory;
 | 
			
		||||
 | 
			
		||||
import com.google.common.util.concurrent.RateLimiter;
 | 
			
		||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
 | 
			
		||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.server.reactive.ServerHttpRequest;
 | 
			
		||||
import org.springframework.http.server.reactive.ServerHttpResponse;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
// 一个自定义的限流过滤器工厂
 | 
			
		||||
public class RateLimitByIpGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimitByIpGatewayFilterFactory.Config> {
 | 
			
		||||
 | 
			
		||||
    // 用于存储IP地址和对应的计数器
 | 
			
		||||
    private static final Map<String, RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
    public RateLimitByIpGatewayFilterFactory() {
 | 
			
		||||
        super(Config.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public GatewayFilter apply(Config config) {
 | 
			
		||||
        return (exchange, chain) -> {
 | 
			
		||||
            // 获取请求的IP地址
 | 
			
		||||
            ServerHttpRequest request = exchange.getRequest();
 | 
			
		||||
            String ip = request.getRemoteAddress().getAddress().getHostAddress();
 | 
			
		||||
 | 
			
		||||
            // 根据IP地址获取对应的限流器
 | 
			
		||||
            RateLimiter rateLimiter = RATE_LIMITER_CACHE.get(ip);
 | 
			
		||||
            if (rateLimiter == null) {
 | 
			
		||||
                // 如果不存在,则创建一个新的限流器,并放入缓存中
 | 
			
		||||
                rateLimiter = RateLimiter.create(config.getRate());
 | 
			
		||||
                RATE_LIMITER_CACHE.put(ip, rateLimiter);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 判断请求是否被限流
 | 
			
		||||
            if (rateLimiter.tryAcquire(config.getPermits())) {
 | 
			
		||||
                // 如果没有被限流,则放行
 | 
			
		||||
                return chain.filter(exchange);
 | 
			
		||||
            } else {
 | 
			
		||||
                System.out.println("限流!ip: " + ip);
 | 
			
		||||
                // 如果被限流,则返回429状态码(Too Many Requests)
 | 
			
		||||
                ServerHttpResponse response = exchange.getResponse();
 | 
			
		||||
                response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
 | 
			
		||||
                return response.setComplete();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 配置类,用于接收配置参数
 | 
			
		||||
    public static class Config {
 | 
			
		||||
 | 
			
		||||
        // 每秒允许的请求数
 | 
			
		||||
        private double rate;
 | 
			
		||||
 | 
			
		||||
        // 每次请求需要的令牌数
 | 
			
		||||
        private int permits;
 | 
			
		||||
 | 
			
		||||
        public double getRate() {
 | 
			
		||||
            return rate;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setRate(double rate) {
 | 
			
		||||
            this.rate = rate;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int getPermits() {
 | 
			
		||||
            return permits;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setPermits(int permits) {
 | 
			
		||||
            this.permits = permits;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -40,20 +40,38 @@ spring:
 | 
			
		||||
          predicates:
 | 
			
		||||
            - Path=/user/**
 | 
			
		||||
            - Method=GET,POST
 | 
			
		||||
          filters: # 路由过滤器,使用自定义的限流过滤器工厂
 | 
			
		||||
            - name: RateLimitByIp # 设置每秒允许5个请求,每次请求需要1个令牌
 | 
			
		||||
              args:
 | 
			
		||||
                rate: 10.0
 | 
			
		||||
                permits: 1
 | 
			
		||||
 | 
			
		||||
        - id: access
 | 
			
		||||
          uri: lb://microservice-provider-access
 | 
			
		||||
          predicates:
 | 
			
		||||
            - Path=/access/**
 | 
			
		||||
            - Method=GET,POST
 | 
			
		||||
          filters: # 路由过滤器,使用自定义的限流过滤器工厂
 | 
			
		||||
            - name: RateLimitByIp # 设置每秒允许5个请求,每次请求需要1个令牌
 | 
			
		||||
              args:
 | 
			
		||||
                rate: 10.0
 | 
			
		||||
                permits: 1
 | 
			
		||||
 | 
			
		||||
        - id: access-websocket
 | 
			
		||||
          uri: lb:ws://microservice-provider-access
 | 
			
		||||
          predicates:
 | 
			
		||||
            - Path=/access/websocket/**
 | 
			
		||||
 | 
			
		||||
        - id: shop
 | 
			
		||||
          uri: lb://microservice-provider-shop
 | 
			
		||||
          predicates:
 | 
			
		||||
            - Path=/shop/**
 | 
			
		||||
            - Method=GET,POST
 | 
			
		||||
          filters: # 路由过滤器,使用自定义的限流过滤器工厂
 | 
			
		||||
            - name: RateLimitByIp # 设置每秒允许5个请求,每次请求需要1个令牌
 | 
			
		||||
              args:
 | 
			
		||||
                rate: 10.0
 | 
			
		||||
                permits: 1
 | 
			
		||||
 | 
			
		||||
        - id: test1
 | 
			
		||||
          uri: lb://microservice-provider-test
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,3 @@
 | 
			
		||||
编辑后右键 Compile And Reload File 修改即可生效,不用频繁重启项目
 | 
			
		||||
 | 
			
		||||
manage 文件夹下为 frontend 项目打包产物
 | 
			
		||||
| 
		 After Width: | Height: | Size: 86 KiB  | 
@@ -1,6 +1,7 @@
 | 
			
		||||
* {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    user-select: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html,
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
.scan-result-container {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    z-index: 20;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    place-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.scan-result-image {
 | 
			
		||||
    width: min(55vw, 55vh);
 | 
			
		||||
    transition: 0.3s;
 | 
			
		||||
    transform: scale(0.001);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.scan-result-image-show {
 | 
			
		||||
    transform: scale(1);
 | 
			
		||||
}
 | 
			
		||||
@@ -62,7 +62,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hidden {
 | 
			
		||||
    display: none;
 | 
			
		||||
    display: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 弹窗列表样式 */
 | 
			
		||||
@@ -82,6 +82,7 @@
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    place-items: center;
 | 
			
		||||
    background-color: #f6f6f6;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gate-list-item > p {
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
const URLScanSuccessImage = "./assets/svg/scan-success.svg"
 | 
			
		||||
const URLEnterGateImage = "./assets/svg/enter-gate.svg"
 | 
			
		||||
const DOMFullScreenMask = document.getElementById("full-screen-mask")
 | 
			
		||||
const DOMScanResultContainer = document.getElementById("scan-result-container")
 | 
			
		||||
const DOMQRCodeScanSuccessImage = document.getElementById("qrcode-scan-success")
 | 
			
		||||
 | 
			
		||||
var isShowing = false
 | 
			
		||||
 | 
			
		||||
function showResult(imageType) {
 | 
			
		||||
    console.log("showResult")
 | 
			
		||||
    if (isShowing) {
 | 
			
		||||
        // console.log("showResult() skipped coz showing.")
 | 
			
		||||
        // 等待 0.1s 重试
 | 
			
		||||
        setTimeout(() => showResult(imageType), 100)
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    isShowing = true
 | 
			
		||||
    DOMQRCodeScanSuccessImage.src = imageType === "onscan" ? URLScanSuccessImage : URLEnterGateImage
 | 
			
		||||
    DOMFullScreenMask.classList.remove("hidden")
 | 
			
		||||
    DOMScanResultContainer.classList.remove("hidden")
 | 
			
		||||
    //
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
        DOMQRCodeScanSuccessImage.classList.add("scan-result-image-show")
 | 
			
		||||
    }, 100)
 | 
			
		||||
 | 
			
		||||
    setTimeout(function hideResult() {
 | 
			
		||||
        console.log("hideResult")
 | 
			
		||||
        DOMQRCodeScanSuccessImage.classList.remove("scan-result-image-show")
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
            DOMQRCodeScanSuccessImage.src = ""
 | 
			
		||||
            DOMFullScreenMask.classList.add("hidden")
 | 
			
		||||
            DOMScanResultContainer.classList.add("hidden")
 | 
			
		||||
            isShowing = false
 | 
			
		||||
        }, 300)
 | 
			
		||||
    }, 3000)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setTimeout(showResult, 100)
 | 
			
		||||
window.showResult = showResult
 | 
			
		||||
@@ -1,6 +1,12 @@
 | 
			
		||||
window.wsUrl = 'wss://epp-prod.only4.work/access/websocket/1';
 | 
			
		||||
// window.wsUrl = 'ws://127.0.0.1:80/access/websocket/1';
 | 
			
		||||
// window.wsUrl = 'ws://127.0.0.1:8002/access/websocket/1';
 | 
			
		||||
/**
 | 
			
		||||
 * FIXME 环境配置
 | 
			
		||||
 *
 | 
			
		||||
 * window.wsUrl
 | 
			
		||||
 * - 线上环境:'wss://epp.only4.work/access/websocket/'
 | 
			
		||||
 * - 开发环境:'ws://127.0.0.1:80/access/websocket/'
 | 
			
		||||
 *            'ws://127.0.0.1:8002/access/websocket/'
 | 
			
		||||
 */
 | 
			
		||||
window.wsUrl = 'wss://epp.only4.work/access/websocket/';
 | 
			
		||||
 | 
			
		||||
window.ws = null; // WebSocket 实例对象
 | 
			
		||||
 | 
			
		||||
@@ -10,9 +16,20 @@ window.ws = null; // WebSocket 实例对象
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getWsUrl() {
 | 
			
		||||
        function getUUID() {
 | 
			
		||||
            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
 | 
			
		||||
                var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
 | 
			
		||||
                return v.toString(16);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return `${window.wsUrl}${getUUID()}`
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createConn() {
 | 
			
		||||
        // 创建webscoket 对象
 | 
			
		||||
        const ws = new WebSocket(window.wsUrl)
 | 
			
		||||
        const ws = new WebSocket(getWsUrl() /* window.wsUrl */)
 | 
			
		||||
        // 执行上面的语句之后,客户端就会与服务器进行连接
 | 
			
		||||
 | 
			
		||||
        // readyState返回当前实例对象的当前状态
 | 
			
		||||
@@ -34,9 +51,23 @@ window.ws = null; // WebSocket 实例对象
 | 
			
		||||
        ws.onmessage = ({data}) => {
 | 
			
		||||
            console.log('onmessage readyState', ws.readyState)
 | 
			
		||||
            // 注意此时的data是json格式的 需要转化下
 | 
			
		||||
            console.log('onmessage 有新消息啦=======>', JSON.parse(data))
 | 
			
		||||
            let result = JSON.parse(data)
 | 
			
		||||
            console.log('onmessage 有新消息啦=======>', result)
 | 
			
		||||
            // 实例对象的send方法给服务器发送消息
 | 
			
		||||
            ws.send('客户端发送的消息')
 | 
			
		||||
 | 
			
		||||
            switch (result.action) {
 | 
			
		||||
                case 'onscan':
 | 
			
		||||
                case 'onopen':
 | 
			
		||||
                    if (window.currentGate && result.gateId === window.currentGate.id) {
 | 
			
		||||
                        console.log(result.action)
 | 
			
		||||
                        window.showResult(result.action)
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    console.log("switch=>default", result.action)
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 实例对象的onclose属性,用于连接关闭后的回调 函数
 | 
			
		||||
@@ -58,5 +89,6 @@ window.ws = null; // WebSocket 实例对象
 | 
			
		||||
        }
 | 
			
		||||
        return ws
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window.ws = createConn()
 | 
			
		||||
})()
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 886 B After Width: | Height: | Size: 886 B  | 
@@ -0,0 +1,33 @@
 | 
			
		||||
<?xml version="1.0" standalone="no"?>
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
			
		||||
<svg width="100" height="100" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
 | 
			
		||||
  <circle cx="50" cy="50" r="45" stroke="white" stroke-width="7" fill="white"/>
 | 
			
		||||
 | 
			
		||||
  <!-- 外围圆圈 -->
 | 
			
		||||
  <circle cx="50" cy="50" r="45" stroke="#006600" stroke-width="8" fill="none">
 | 
			
		||||
    <animate id="circle" attributeName="stroke-dasharray" from="0,282.743" to="282.743,0" dur="1s" begin="0s" fill="freeze"/>
 | 
			
		||||
    <animateTransform attributeName="transform" type="rotate" from="-90 50 50" to="270 50 50" dur="1s" begin="0s" fill="freeze"/>
 | 
			
		||||
  </circle>
 | 
			
		||||
 | 
			
		||||
  <!-- 对勾动画 -->
 | 
			
		||||
  <path d="M20 50 L40 70 L80 30" stroke="#006600" stroke-width="8" fill="none" visibility="hidden">
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="circle.end+0.1s"/>
 | 
			
		||||
    <!-- 对勾开始动画 -->
 | 
			
		||||
    <!-- <animate attributeName="stroke-dasharray" from="0,120" to="120,0" dur="1s" begin="circle.end+0.1s" repeatCount="indefinite"/> -->
 | 
			
		||||
    <animate id="check" attributeName="stroke-dasharray" from="0,120" to="120,0" dur="1s" begin="circle.end+0.1s" repeatCount="1"/>
 | 
			
		||||
    <!-- 对勾隐藏动画 -->
 | 
			
		||||
    <set attributeName="visibility" from="visible" to="hidden" begin="check.end+0.1s"/>
 | 
			
		||||
  </path>
 | 
			
		||||
 | 
			
		||||
  <!-- 扫码成功 -->
 | 
			
		||||
  <!-- <text x="50" y="55" font-size="20" text-anchor="middle" fill="#006600" visibility="hidden">
 | 
			
		||||
    扫码成功
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="check.end+0.1s"/>
 | 
			
		||||
  </text> -->
 | 
			
		||||
  <text x="50" y="50" font-weight="bold" text-anchor="middle" fill="#006600" visibility="hidden">
 | 
			
		||||
    <tspan x="50" dx="3" dy="-3" font-size="26">大门</tspan>
 | 
			
		||||
    <tspan x="50" dy="23" font-size="20">已开启</tspan>
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="check.end+0.1s"/>
 | 
			
		||||
  </text>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB  | 
@@ -0,0 +1,33 @@
 | 
			
		||||
<?xml version="1.0" standalone="no"?>
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
			
		||||
<svg width="100" height="100" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
 | 
			
		||||
  <circle cx="50" cy="50" r="45" stroke="white" stroke-width="7" fill="white"/>
 | 
			
		||||
 | 
			
		||||
  <!-- 外围圆圈 -->
 | 
			
		||||
  <circle cx="50" cy="50" r="45" stroke="#006600" stroke-width="8" fill="none">
 | 
			
		||||
    <animate id="circle" attributeName="stroke-dasharray" from="0,282.743" to="282.743,0" dur="1s" begin="0s" fill="freeze"/>
 | 
			
		||||
    <animateTransform attributeName="transform" type="rotate" from="-90 50 50" to="270 50 50" dur="1s" begin="0s" fill="freeze"/>
 | 
			
		||||
  </circle>
 | 
			
		||||
 | 
			
		||||
  <!-- 对勾动画 -->
 | 
			
		||||
  <path d="M20 50 L40 70 L80 30" stroke="#006600" stroke-width="8" fill="none" visibility="hidden">
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="circle.end+0.1s"/>
 | 
			
		||||
    <!-- 对勾开始动画 -->
 | 
			
		||||
    <!-- <animate attributeName="stroke-dasharray" from="0,120" to="120,0" dur="1s" begin="circle.end+0.1s" repeatCount="indefinite"/> -->
 | 
			
		||||
    <animate id="check" attributeName="stroke-dasharray" from="0,120" to="120,0" dur="1s" begin="circle.end+0.1s" repeatCount="1"/>
 | 
			
		||||
    <!-- 对勾隐藏动画 -->
 | 
			
		||||
    <set attributeName="visibility" from="visible" to="hidden" begin="check.end+0.1s"/>
 | 
			
		||||
  </path>
 | 
			
		||||
 | 
			
		||||
  <!-- 扫码成功 -->
 | 
			
		||||
  <!-- <text x="50" y="55" font-size="20" text-anchor="middle" fill="#006600" visibility="hidden">
 | 
			
		||||
    扫码成功
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="check.end+0.1s"/>
 | 
			
		||||
  </text> -->
 | 
			
		||||
  <text x="50" y="50" font-size="27" font-weight="bold" text-anchor="middle" fill="#006600" visibility="hidden">
 | 
			
		||||
    <tspan x="50" dx="4" dy="-5">扫码</tspan>
 | 
			
		||||
    <tspan x="50" dy="28">成功</tspan>
 | 
			
		||||
    <set attributeName="visibility" from="hidden" to="visible" begin="check.end+0.1s"/>
 | 
			
		||||
  </text>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB  | 
@@ -10,6 +10,7 @@
 | 
			
		||||
    <title>社区疫情防控系统 - 门禁端</title>
 | 
			
		||||
    <link rel="stylesheet" href="./assets/css/index.css"/>
 | 
			
		||||
    <link rel="stylesheet" href="./assets/css/setting-panel.css"/>
 | 
			
		||||
    <link rel="stylesheet" href="./assets/css/scan-result.css"/>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
@@ -36,11 +37,12 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="right-container">
 | 
			
		||||
        <h1 id="no-qrcode">请选择大门</h1>
 | 
			
		||||
        <img id="qrcode" src="" style="display: none">
 | 
			
		||||
        <img id="qrcode" src="" style="display: none;"><br>
 | 
			
		||||
        <p id="refreshTimeCountDown"></p>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<!-- 设置页面 -->
 | 
			
		||||
<div id="full-screen-mask" class="full-screen-mask hidden"></div>
 | 
			
		||||
<div id="setting-container" class="setting-container hidden">
 | 
			
		||||
    <div class="setting-panel">
 | 
			
		||||
@@ -63,8 +65,15 @@
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<!-- 扫码成功 -->
 | 
			
		||||
<div id="scan-result-container" class="scan-result-container hidden">
 | 
			
		||||
    <img id="qrcode-scan-success" class="scan-result-image" src="./assets/svg/scan-success.svg">
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<script src="./assets/js/setting-panel.js" type="module"></script>
 | 
			
		||||
<script src="./renderer.js" type="module"></script>
 | 
			
		||||
<script src="assets/js/websocket-message-panel.js"></script>
 | 
			
		||||
<script src="./assets/js/websocket.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
@@ -1,3 +1,13 @@
 | 
			
		||||
/**
 | 
			
		||||
 * FIXME 环境配置
 | 
			
		||||
 *
 | 
			
		||||
 * baseUrl
 | 
			
		||||
 * - 线上环境:"https://epp.only4.work/"
 | 
			
		||||
 * - 开发环境:"/"
 | 
			
		||||
 * envVersion
 | 
			
		||||
 * - 线上环境:"release"
 | 
			
		||||
 * - 开发环境:"develop"
 | 
			
		||||
 */
 | 
			
		||||
// 定义常量
 | 
			
		||||
const baseUrl = "https://epp-prod.only4.work/"
 | 
			
		||||
const url = baseUrl + "access/wechat/getUnlimitedQRCode"
 | 
			
		||||
@@ -0,0 +1,92 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>基于微服务的社区疫情防控系统</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        body {
 | 
			
		||||
            font-size: 1.2em;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .grid-item {
 | 
			
		||||
            border: 1px solid black;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .grid-item ul {
 | 
			
		||||
            text-align: left;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<div>
 | 
			
		||||
    <h1 style="text-align: center;">基于微服务的社区疫情防控系统</h1>
 | 
			
		||||
    <p style="text-align: center;">epp.only4.work</p>
 | 
			
		||||
 | 
			
		||||
    <div style="display: grid; grid-template-columns: repeat(2, 1fr);">
 | 
			
		||||
        <div class="grid-item">
 | 
			
		||||
            <h3>
 | 
			
		||||
                门禁端 跨端桌面应用
 | 
			
		||||
            </h3>
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li>
 | 
			
		||||
                    方式1:访问
 | 
			
		||||
                    <a target="_blank" href="./guard/index.html">https://epp.only4.work/guard/index.html</a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    方式2:运行跨端桌面应用
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="grid-item">
 | 
			
		||||
            <h3>
 | 
			
		||||
                居民端 小程序
 | 
			
		||||
            </h3>
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li>
 | 
			
		||||
                    方式1:扫描下方小程序码
 | 
			
		||||
                    <p style="text-align: center">
 | 
			
		||||
                        <img src="./assets/image/miniprogram.jpg" style="width: 180px;">
 | 
			
		||||
                    </p>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    方式2:微信搜索小程序 <b>devprogram</b>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="grid-item">
 | 
			
		||||
            <h3>
 | 
			
		||||
                社区管理员端 管理后台
 | 
			
		||||
            </h3>
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li>
 | 
			
		||||
                    访问
 | 
			
		||||
                    <a target="_blank" href="./manage/index.html">https://epp.only4.work/manage/index.html</a>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="grid-item">
 | 
			
		||||
            <h3>
 | 
			
		||||
            系统管理员端 管理后台
 | 
			
		||||
            </h3>
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li>
 | 
			
		||||
                    访问
 | 
			
		||||
                    <a target="_blank" href="./manage/index.html">https://epp.only4.work/manage/index.html</a>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div>
 | 
			
		||||
    <h2>开发</h2>
 | 
			
		||||
    <p>小程序后台:<a target="_blank">https://mp.weixin.qq.com/</a></p>
 | 
			
		||||
</div>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{d as r,dJ as p,b0 as l,r as i,o as m,c as E,e as o,b as s,w as a,p as f,h,f as t,_ as v}from"./index.f859bf4e.js";const c=e=>(f("data-v-d4771405"),e=e(),h(),e),B={class:"error-page"},g=c(()=>o("div",{class:"error-code"},[t("4"),o("span",null,"0"),t("3")],-1)),k=c(()=>o("div",{class:"error-desc"},"\u554A\u54E6~ \u4F60\u6CA1\u6709\u6743\u9650\u8BBF\u95EE\u8BE5\u9875\u9762\u54E6",-1)),x={class:"error-handle"},y=r({name:"403"}),C=r({...y,setup(e){const u=p(),n=()=>{u.go(-2)};return(b,D)=>{const _=l,d=i("router-link");return m(),E("div",B,[g,k,o("div",x,[s(d,{to:"/"},{default:a(()=>[s(_,{type:"primary",size:"large"},{default:a(()=>[t("\u8FD4\u56DE\u9996\u9875")]),_:1})]),_:1}),s(_,{class:"error-btn",type:"primary",size:"large",onClick:n},{default:a(()=>[t("\u8FD4\u56DE\u4E0A\u4E00\u9875")]),_:1})])])}}});const I=v(C,[["__scopeId","data-v-d4771405"]]);export{I as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
.error-page[data-v-d4771405]{display:flex;justify-content:center;align-items:center;flex-direction:column;width:100%;height:100%;background:#f3f3f3;box-sizing:border-box}.error-code[data-v-d4771405]{line-height:1;font-size:250px;font-weight:bolder;color:#f02d2d}.error-code span[data-v-d4771405]{color:#00a854}.error-desc[data-v-d4771405]{font-size:30px;color:#777}.error-handle[data-v-d4771405]{margin-top:30px;padding-bottom:200px}.error-btn[data-v-d4771405]{margin-left:100px}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m as s}from"./manage-list.8ab8e06b.js";import{s as t}from"./send_request.cc43fdb9.js";import{d as n,o as r,c,b as o}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";function u(e){return t({url:"/access/gate/manage/getGateList",method:"GET",params:e})}function a(e){return t({url:"/access/gate/manage/editGate",method:"POST",useQS:!0,params:e})}function i(e){return t({url:"/access/gate/manage/deleteGate",method:"POST",useQS:!0,params:e})}function m(e){return t({url:"/access/gate/manage/exportGateList",method:"GET",params:e})}const d={class:"container"},L=n({__name:"access-gate-setting",setup(e){return(p,f)=>(r(),c("div",d,[o(s,{"list-func":u,"add-func":a,"edit-func":a,"delete-func":i,"export-func":m,"edit-permiss":"access-gate-setting"},null,8,["list-func","add-func","edit-func","delete-func","export-func"])]))}});export{L as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m as o}from"./manage-list.8ab8e06b.js";import{s as m}from"./send_request.cc43fdb9.js";import{d as r,o as c,c as a,b as n}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";function p(e){var s,i;let t=JSON.parse(JSON.stringify(e));return delete t.timestamp,Array.isArray(e.timestamp)&&e.timestamp.length==2&&(t.startTime=(s=e.timestamp[0])==null?void 0:s.getTime(),t.endTime=(i=e.timestamp[1])==null?void 0:i.getTime()),m({url:"/access/access-log/manage/getAccessLogList",method:"GET",params:t})}function g(e){var s,i;let t=JSON.parse(JSON.stringify(e));return delete t.timestamp,Array.isArray(e.timestamp)&&e.timestamp.length==2&&(t.startTime=(s=e.timestamp[0])==null?void 0:s.getTime(),t.endTime=(i=e.timestamp[1])==null?void 0:i.getTime()),m({url:"/access/access-log/manage/exportAccessLogList",method:"GET",params:t})}const l={class:"container"},y=r({__name:"access-log",setup(e){return(t,s)=>(c(),a("div",l,[n(o,{"list-func":p,"export-func":g,"edit-permiss":"access-log"},null,8,["list-func","export-func"])]))}});export{y as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
.el-row[data-v-e670d298]{margin-bottom:20px}.grid-content[data-v-e670d298]{display:flex;align-items:center;height:100px}.grid-cont-right[data-v-e670d298]{flex:1;text-align:center;font-size:14px;color:#999}.grid-num[data-v-e670d298]{font-size:30px;font-weight:700}.grid-con-icon[data-v-e670d298]{font-size:50px;width:100px;height:100px;text-align:center;line-height:100px;color:#fff}.grid-con-1 .grid-con-icon[data-v-e670d298]{background:rgb(45,140,240)}.grid-con-1 .grid-num[data-v-e670d298]{color:#2d8cf0}.grid-con-2 .grid-con-icon[data-v-e670d298]{background:rgb(100,213,114)}.grid-con-2 .grid-num[data-v-e670d298]{color:#64d572}.grid-con-3 .grid-con-icon[data-v-e670d298]{background:rgb(242,94,67)}.grid-con-3 .grid-num[data-v-e670d298]{color:#f25e43}.user-info[data-v-e670d298]{display:flex;align-items:center;padding-bottom:20px;border-bottom:2px solid #ccc;margin-bottom:20px}.user-info-cont[data-v-e670d298]{padding-left:50px;flex:1;font-size:14px;color:#999}.user-info-cont div[data-v-e670d298]:first-child{font-size:30px;color:#222}.user-info-list[data-v-e670d298]{font-size:14px;color:#999;line-height:25px}.user-info-list span[data-v-e670d298]{margin-left:70px}.mgb20[data-v-e670d298]{margin-bottom:20px}.todo-item[data-v-e670d298]{font-size:14px}.todo-item-del[data-v-e670d298]{text-decoration:line-through;color:#999}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{d as g,E as C,r as _,a as F,o as x,c as y,b as s,w as e,e as o,u as r,t as h,f as t,g as b,p as w,h as A,_ as S}from"./index.f859bf4e.js";import{E as D,a as I,b as V}from"./el-card.0035c23b.js";import{E as N}from"./el-progress.d53d438b.js";const a=d=>(w("data-v-e670d298"),d=d(),A(),d),R={class:"container"},T={class:"user-info"},k={class:"user-info-cont"},G={class:"user-info-name"},U=a(()=>o("div",{class:"user-info-list"},[t(" \u4E0A\u6B21\u767B\u5F55\u65F6\u95F4\uFF1A "),o("span",null,"2022-10-01")],-1)),z=a(()=>o("div",{class:"user-info-list"},[t(" \u4E0A\u6B21\u767B\u5F55\u5730\u70B9\uFF1A "),o("span",null,"\u4E1C\u839E")],-1)),H=a(()=>o("div",{class:"clearfix"},[o("span",null,"\u8BED\u8A00\u8BE6\u60C5")],-1)),L={class:"grid-content grid-con-1"},M=a(()=>o("div",{class:"grid-cont-right"},[o("div",{class:"grid-num"},"1234"),o("div",null,"\u7528\u6237\u8BBF\u95EE\u91CF")],-1)),P={class:"grid-content grid-con-2"},j=a(()=>o("div",{class:"grid-cont-right"},[o("div",{class:"grid-num"},"321"),o("div",null,"\u7CFB\u7EDF\u6D88\u606F")],-1)),q={class:"grid-content grid-con-3"},J=a(()=>o("div",{class:"grid-cont-right"},[o("div",{class:"grid-num"},"500"),o("div",null,"\u5546\u54C1\u6570\u91CF")],-1)),K=g({name:"dashboard"}),O=g({...K,setup(d){const i=localStorage.getItem("ms_username"),f=i==="admin"?"\u8D85\u7EA7\u7BA1\u7406\u5458":"\u666E\u901A\u7528\u6237";return(Q,W)=>{const v=C,n=D,l=N,c=I,m=_("User"),u=F,E=_("ChatDotRound"),B=_("Goods"),p=V;return x(),y("div",R,[s(p,{gutter:20},{default:e(()=>[s(c,{span:8},{default:e(()=>[s(n,{shadow:"hover",class:"mgb20",style:{height:"252px"}},{default:e(()=>[o("div",T,[s(v,{size:120,src:r(b)},null,8,["src"]),o("div",k,[o("div",G,h(r(i)),1),o("div",null,h(r(f)),1)])]),U,z]),_:1}),s(n,{shadow:"hover",style:{height:"252px"}},{header:e(()=>[H]),default:e(()=>[t(" Vue "),s(l,{percentage:79.4,color:"#42b983"},null,8,["percentage"]),t(" TypeScript "),s(l,{percentage:14,color:"#f1e05a"}),t(" CSS "),s(l,{percentage:5.6},null,8,["percentage"]),t(" HTML "),s(l,{percentage:1,color:"#f56c6c"})]),_:1})]),_:1}),s(c,{span:16},{default:e(()=>[s(p,{gutter:20,class:"mgb20"},{default:e(()=>[s(c,{span:8},{default:e(()=>[s(n,{shadow:"hover","body-style":{padding:"0px"}},{default:e(()=>[o("div",L,[s(u,{class:"grid-con-icon"},{default:e(()=>[s(m)]),_:1}),M])]),_:1})]),_:1}),s(c,{span:8},{default:e(()=>[s(n,{shadow:"hover","body-style":{padding:"0px"}},{default:e(()=>[o("div",P,[s(u,{class:"grid-con-icon"},{default:e(()=>[s(E)]),_:1}),j])]),_:1})]),_:1}),s(c,{span:8},{default:e(()=>[s(n,{shadow:"hover","body-style":{padding:"0px"}},{default:e(()=>[o("div",q,[s(u,{class:"grid-con-icon"},{default:e(()=>[s(B)]),_:1}),J])]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})])}}});const $=S(O,[["__scopeId","data-v-e670d298"]]);export{$ as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{i as g,j as r,d as u,k as h,o as f,c as N,n as d,u as o,l as m,f as R,t as x,m as B,e as K,q as w,s as _,v,x as p,y as P,z as n,A as j,B as A,C as S,w as k,D as E,F as D}from"./index.f859bf4e.js";const O=Symbol("rowContextKey"),V=g({header:{type:String,default:""},bodyStyle:{type:r([String,Object,Array]),default:""},shadow:{type:String,values:["always","hover","never"],default:"always"}}),L=u({name:"ElCard"}),T=u({...L,props:V,setup(i){const t=h("card");return(s,l)=>(f(),N("div",{class:d([o(t).b(),o(t).is(`${s.shadow}-shadow`)])},[s.$slots.header||s.header?(f(),N("div",{key:0,class:d(o(t).e("header"))},[m(s.$slots,"header",{},()=>[R(x(s.header),1)])],2)):B("v-if",!0),K("div",{class:d(o(t).e("body")),style:w(s.bodyStyle)},[m(s.$slots,"default")],6)],2))}});var q=_(T,[["__file","/home/runner/work/element-plus/element-plus/packages/components/card/src/card.vue"]]);const z=v(q),F=g({tag:{type:String,default:"div"},span:{type:Number,default:24},offset:{type:Number,default:0},pull:{type:Number,default:0},push:{type:Number,default:0},xs:{type:r([Number,Object]),default:()=>p({})},sm:{type:r([Number,Object]),default:()=>p({})},md:{type:r([Number,Object]),default:()=>p({})},lg:{type:r([Number,Object]),default:()=>p({})},xl:{type:r([Number,Object]),default:()=>p({})}}),I=u({name:"ElCol"}),J=u({...I,props:F,setup(i){const t=i,{gutter:s}=P(O,{gutter:n(()=>0)}),l=h("col"),y=n(()=>{const e={};return s.value&&(e.paddingLeft=e.paddingRight=`${s.value/2}px`),e}),b=n(()=>{const e=[];return["span","offset","pull","push"].forEach(a=>{const c=t[a];j(c)&&(a==="span"?e.push(l.b(`${t[a]}`)):c>0&&e.push(l.b(`${a}-${t[a]}`)))}),["xs","sm","md","lg","xl"].forEach(a=>{j(t[a])?e.push(l.b(`${a}-${t[a]}`)):A(t[a])&&Object.entries(t[a]).forEach(([c,C])=>{e.push(c!=="span"?l.b(`${a}-${c}-${C}`):l.b(`${a}-${C}`))})}),s.value&&e.push(l.is("guttered")),[l.b(),e]});return(e,$)=>(f(),S(E(e.tag),{class:d(o(b)),style:w(o(y))},{default:k(()=>[m(e.$slots,"default")]),_:3},8,["class","style"]))}});var G=_(J,[["__file","/home/runner/work/element-plus/element-plus/packages/components/col/src/col.vue"]]);const ee=v(G),H=["start","center","end","space-around","space-between","space-evenly"],M=["top","middle","bottom"],Q=g({tag:{type:String,default:"div"},gutter:{type:Number,default:0},justify:{type:String,values:H,default:"start"},align:{type:String,values:M,default:"top"}}),U=u({name:"ElRow"}),W=u({...U,props:Q,setup(i){const t=i,s=h("row"),l=n(()=>t.gutter);D(O,{gutter:l});const y=n(()=>{const e={};return t.gutter&&(e.marginRight=e.marginLeft=`-${t.gutter/2}px`),e}),b=n(()=>[s.b(),s.is(`justify-${t.justify}`,t.justify!=="start"),s.is(`align-${t.align}`,t.align!=="top")]);return(e,$)=>(f(),S(E(e.tag),{class:d(o(b)),style:w(o(y))},{default:k(()=>[m(e.$slots,"default")]),_:3},8,["class","style"]))}});var X=_(W,[["__file","/home/runner/work/element-plus/element-plus/packages/components/row/src/row.vue"]]);const te=v(X);export{z as E,ee as a,te as b};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
:root{--el-popup-modal-bg-color:var(--el-color-black);--el-popup-modal-opacity:.5}.v-modal-enter{-webkit-animation:v-modal-in var(--el-transition-duration-fast) ease;animation:v-modal-in var(--el-transition-duration-fast) ease}.v-modal-leave{-webkit-animation:v-modal-out var(--el-transition-duration-fast) ease forwards;animation:v-modal-out var(--el-transition-duration-fast) ease forwards}@-webkit-keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{to{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:var(--el-popup-modal-opacity);background:var(--el-popup-modal-bg-color)}.el-popup-parent--hidden{overflow:hidden}.el-dialog{--el-dialog-width:50%;--el-dialog-margin-top:15vh;--el-dialog-bg-color:var(--el-bg-color);--el-dialog-box-shadow:var(--el-box-shadow);--el-dialog-title-font-size:var(--el-font-size-large);--el-dialog-content-font-size:14px;--el-dialog-font-line-height:var(--el-font-line-height-primary);--el-dialog-padding-primary:20px;--el-dialog-border-radius:var(--el-border-radius-small);position:relative;margin:var(--el-dialog-margin-top,15vh) auto 50px;background:var(--el-dialog-bg-color);border-radius:var(--el-dialog-border-radius);box-shadow:var(--el-dialog-box-shadow);box-sizing:border-box;width:var(--el-dialog-width,50%)}.el-dialog:focus{outline:0!important}.el-dialog.is-align-center{margin:auto}.el-dialog.is-fullscreen{--el-dialog-width:100%;--el-dialog-margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog.is-draggable .el-dialog__header{cursor:move;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-dialog__header{padding:var(--el-dialog-padding-primary);padding-bottom:10px;margin-right:16px}.el-dialog__headerbtn{position:absolute;top:6px;right:0;padding:0;width:54px;height:54px;background:0 0;border:none;outline:0;cursor:pointer;font-size:var(--el-message-close-size,16px)}.el-dialog__headerbtn .el-dialog__close{color:var(--el-color-info);font-size:inherit}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:var(--el-color-primary)}.el-dialog__title{line-height:var(--el-dialog-font-line-height);font-size:var(--el-dialog-title-font-size);color:var(--el-text-color-primary)}.el-dialog__body{padding:calc(var(--el-dialog-padding-primary) + 10px) var(--el-dialog-padding-primary);color:var(--el-text-color-regular);font-size:var(--el-dialog-content-font-size)}.el-dialog__footer{padding:var(--el-dialog-padding-primary);padding-top:10px;text-align:right;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px calc(var(--el-dialog-padding-primary) + 5px) 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.el-overlay-dialog{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto}.dialog-fade-enter-active{-webkit-animation:modal-fade-in var(--el-transition-duration);animation:modal-fade-in var(--el-transition-duration)}.dialog-fade-enter-active .el-overlay-dialog{-webkit-animation:dialog-fade-in var(--el-transition-duration);animation:dialog-fade-in var(--el-transition-duration)}.dialog-fade-leave-active{-webkit-animation:modal-fade-out var(--el-transition-duration);animation:modal-fade-out var(--el-transition-duration)}.dialog-fade-leave-active .el-overlay-dialog{-webkit-animation:dialog-fade-out var(--el-transition-duration);animation:dialog-fade-out var(--el-transition-duration)}@-webkit-keyframes dialog-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@keyframes dialog-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}@-webkit-keyframes modal-fade-in{0%{opacity:0}to{opacity:1}}@keyframes modal-fade-in{0%{opacity:0}to{opacity:1}}@-webkit-keyframes modal-fade-out{0%{opacity:1}to{opacity:0}}@keyframes modal-fade-out{0%{opacity:1}to{opacity:0}}.el-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:2000;height:100%;background-color:var(--el-overlay-color-lighter);overflow:auto}.el-overlay .el-overlay-root{height:0}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
.el-progress{position:relative;line-height:1;display:flex;align-items:center}.el-progress__text{font-size:14px;color:var(--el-text-color-regular);margin-left:5px;min-width:50px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;transform:translateY(-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:var(--el-color-success)}.el-progress.is-success .el-progress__text{color:var(--el-color-success)}.el-progress.is-warning .el-progress-bar__inner{background-color:var(--el-color-warning)}.el-progress.is-warning .el-progress__text{color:var(--el-color-warning)}.el-progress.is-exception .el-progress-bar__inner{background-color:var(--el-color-danger)}.el-progress.is-exception .el-progress__text{color:var(--el-color-danger)}.el-progress-bar{flex-grow:1;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:var(--el-border-color-lighter);overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:var(--el-color-primary);text-align:right;border-radius:100px;line-height:1;white-space:nowrap;transition:width .6s ease}.el-progress-bar__inner:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-progress-bar__inner--indeterminate{transform:translateZ(0);-webkit-animation:indeterminate 3s infinite;animation:indeterminate 3s infinite}.el-progress-bar__innerText{display:inline-block;vertical-align:middle;color:#fff;font-size:12px;margin:0 5px}@-webkit-keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}@-webkit-keyframes indeterminate{0%{left:-100%}to{left:100%}}@keyframes indeterminate{0%{left:-100%}to{left:100%}}
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
import{i as M,j as m,d as T,k as A,z as r,G as V,H as O,I as j,J as q,K as G,L as H,M as C,o as l,c,n as i,u as t,e as y,q as f,l as _,t as D,m as I,C as N,w as J,D as K,a as R,s as U,v as Q}from"./index.f859bf4e.js";const X=M({type:{type:String,default:"line",values:["line","circle","dashboard"]},percentage:{type:Number,default:0,validator:u=>u>=0&&u<=100},status:{type:String,default:"",values:["","success","exception","warning"]},indeterminate:{type:Boolean,default:!1},duration:{type:Number,default:3},strokeWidth:{type:Number,default:6},strokeLinecap:{type:m(String),default:"round"},textInside:{type:Boolean,default:!1},width:{type:Number,default:126},showText:{type:Boolean,default:!0},color:{type:m([String,Array,Function]),default:""},format:{type:m(Function),default:u=>`${u}%`}}),Y=["aria-valuenow"],Z={viewBox:"0 0 100 100"},ee=["d","stroke","stroke-width"],te=["d","stroke","opacity","stroke-linecap","stroke-width"],se={key:0},ae=T({name:"ElProgress"}),re=T({...ae,props:X,setup(u){const s=u,v={success:"#13ce66",exception:"#ff4949",warning:"#e6a23c",default:"#20a0ff"},a=A("progress"),x=r(()=>({width:`${s.percentage}%`,animationDuration:`${s.duration}s`,backgroundColor:P(s.percentage)})),g=r(()=>(s.strokeWidth/s.width*100).toFixed(1)),b=r(()=>["circle","dashboard"].includes(s.type)?Number.parseInt(`${50-Number.parseFloat(g.value)/2}`,10):0),$=r(()=>{const e=b.value,o=s.type==="dashboard";return`
 | 
			
		||||
          M 50 50
 | 
			
		||||
          m 0 ${o?"":"-"}${e}
 | 
			
		||||
          a ${e} ${e} 0 1 1 0 ${o?"-":""}${e*2}
 | 
			
		||||
          a ${e} ${e} 0 1 1 0 ${o?"":"-"}${e*2}
 | 
			
		||||
          `}),h=r(()=>2*Math.PI*b.value),k=r(()=>s.type==="dashboard"?.75:1),w=r(()=>`${-1*h.value*(1-k.value)/2}px`),B=r(()=>({strokeDasharray:`${h.value*k.value}px, ${h.value}px`,strokeDashoffset:w.value})),z=r(()=>({strokeDasharray:`${h.value*k.value*(s.percentage/100)}px, ${h.value}px`,strokeDashoffset:w.value,transition:"stroke-dasharray 0.6s ease 0s, stroke 0.6s ease, opacity ease 0.6s"})),E=r(()=>{let e;return s.color?e=P(s.percentage):e=v[s.status]||v.default,e}),F=r(()=>s.status==="warning"?V:s.type==="line"?s.status==="success"?O:j:s.status==="success"?q:G),W=r(()=>s.type==="line"?12+s.strokeWidth*.4:s.width*.111111+2),S=r(()=>s.format(s.percentage));function L(e){const o=100/e.length;return e.map((n,p)=>C(n)?{color:n,percentage:(p+1)*o}:n).sort((n,p)=>n.percentage-p.percentage)}const P=e=>{var o;const{color:d}=s;if(H(d))return d(e);if(C(d))return d;{const n=L(d);for(const p of n)if(p.percentage>e)return p.color;return(o=n[n.length-1])==null?void 0:o.color}};return(e,o)=>(l(),c("div",{class:i([t(a).b(),t(a).m(e.type),t(a).is(e.status),{[t(a).m("without-text")]:!e.showText,[t(a).m("text-inside")]:e.textInside}]),role:"progressbar","aria-valuenow":e.percentage,"aria-valuemin":"0","aria-valuemax":"100"},[e.type==="line"?(l(),c("div",{key:0,class:i(t(a).b("bar"))},[y("div",{class:i(t(a).be("bar","outer")),style:f({height:`${e.strokeWidth}px`})},[y("div",{class:i([t(a).be("bar","inner"),{[t(a).bem("bar","inner","indeterminate")]:e.indeterminate}]),style:f(t(x))},[(e.showText||e.$slots.default)&&e.textInside?(l(),c("div",{key:0,class:i(t(a).be("bar","innerText"))},[_(e.$slots,"default",{percentage:e.percentage},()=>[y("span",null,D(t(S)),1)])],2)):I("v-if",!0)],6)],6)],2)):(l(),c("div",{key:1,class:i(t(a).b("circle")),style:f({height:`${e.width}px`,width:`${e.width}px`})},[(l(),c("svg",Z,[y("path",{class:i(t(a).be("circle","track")),d:t($),stroke:`var(${t(a).cssVarName("fill-color-light")}, #e5e9f2)`,"stroke-width":t(g),fill:"none",style:f(t(B))},null,14,ee),y("path",{class:i(t(a).be("circle","path")),d:t($),stroke:t(E),fill:"none",opacity:e.percentage?1:0,"stroke-linecap":e.strokeLinecap,"stroke-width":t(g),style:f(t(z))},null,14,te)]))],6)),(e.showText||e.$slots.default)&&!e.textInside?(l(),c("div",{key:2,class:i(t(a).e("text")),style:f({fontSize:`${t(W)}px`})},[_(e.$slots,"default",{percentage:e.percentage},()=>[e.status?(l(),N(t(R),{key:1},{default:J(()=>[(l(),N(K(t(F))))]),_:1})):(l(),c("span",se,D(t(S)),1))])],6)):I("v-if",!0)],10,Y))}});var oe=U(re,[["__file","/home/runner/work/element-plus/element-plus/packages/components/progress/src/progress.vue"]]);const le=Q(oe);export{le as E};
 | 
			
		||||
| 
		 After Width: | Height: | Size: 6.0 KiB  | 
@@ -0,0 +1 @@
 | 
			
		||||
.login-wrap[data-v-0fd4c22f]{width:100%;height:100%}.login-container[data-v-0fd4c22f]{width:100%;height:100%;display:grid;place-items:center}.ms-title[data-v-0fd4c22f]{width:100%;padding:18px 24px;box-sizing:border-box;text-align:center;font-size:20px;color:#fff;border-bottom:1px solid #ddd}.ms-login[data-v-0fd4c22f]{width:min(380px,95vw);padding:5px 10px;border-radius:5px;background:rgba(255,255,255,.3);overflow:hidden}.ms-content[data-v-0fd4c22f]{padding:30px}.login-btn[data-v-0fd4c22f]{text-align:center}.login-btn button[data-v-0fd4c22f]{width:100%;height:36px;margin-bottom:10px}.company-info[data-v-0fd4c22f]{color:#7589b6;text-align:center;position:absolute;left:0;right:0;bottom:10px;font-size:13px;letter-spacing:1px}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{d as E,dJ as x,aR as C,ac as k,dK as N,r as R,o as b,c as h,e as d,t as F,u,b as o,w as a,aT as S,f as T,m as q,bP as B,b0 as D,a as K,bX as f,dL as L,dM as M,_ as U}from"./index.f859bf4e.js";import{E as $,s as j,t as A}from"./el-input.f35758e8.js";import{u as J}from"./user.0bac8e4f.js";import"./send_request.cc43fdb9.js";const O={class:"login-wrap"},P={class:"login-container"},X={class:"ms-login"},z={class:"ms-title"},G={class:"login-btn"},H={key:0,class:"company-info"},Q=E({__name:"login",setup(W){const _=x(),r=C({username:"root",password:"root"}),V={username:[{required:!0,message:"\u8BF7\u8F93\u5165\u7528\u6237\u540D",trigger:"blur"}],password:[{required:!0,message:"\u8BF7\u8F93\u5165\u5BC6\u7801",trigger:"blur"}]},p=k(),v=g=>{!g||g.validate(async(s,l)=>{if(!s){console.log("invalidFields",l),Object.values(l).forEach(e=>{e.forEach(t=>{B.error({message:t.message,grouping:!0})})});return}J({username:r.username,password:r.password}).then(async e=>{var i,c,m,n,y,I,w;if(!e)return;console.log("login data",e,e.userInfo),B.success("\u767B\u5F55\u6210\u529F"),localStorage.setItem("ms_username",(i=e.userInfo)==null?void 0:i.username),localStorage.setItem("ms_realname",(c=e.userInfo)==null?void 0:c.realname),localStorage.setItem("ms_user_id",(m=e.userInfo)==null?void 0:m.id),localStorage.setItem("ms_role_id",(n=e.userInfo)==null?void 0:n.roleId);let t=(w=(I=(y=_.currentRoute)==null?void 0:y.value)==null?void 0:I.query)==null?void 0:w.redirectTo;t&&!t.includes("/login")?_.push(t):_.push("/")})})};return N().clearTags(),(g,s)=>{const l=D,e=$,t=j,i=R("Right"),c=K,m=A;return b(),h("div",O,[d("div",P,[d("div",X,[d("div",z,F(u(f).siteFullTitle),1),o(m,{model:r,rules:V,ref_key:"login",ref:p,"label-width":"0px",class:"ms-content"},{default:a(()=>[o(t,{prop:"username"},{default:a(()=>[o(e,{modelValue:r.username,"onUpdate:modelValue":s[0]||(s[0]=n=>r.username=n),placeholder:"\u7528\u6237\u540D"},{prepend:a(()=>[o(l,{icon:u(L)},null,8,["icon"])]),_:1},8,["modelValue"])]),_:1}),o(t,{prop:"password"},{default:a(()=>[o(e,{type:"password",placeholder:"\u5BC6\u7801",modelValue:r.password,"onUpdate:modelValue":s[1]||(s[1]=n=>r.password=n),onKeyup:s[2]||(s[2]=S(n=>v(p.value),["enter"]))},{prepend:a(()=>[o(l,{icon:u(M)},null,8,["icon"])]),_:1},8,["modelValue"])]),_:1}),d("div",G,[o(l,{type:"primary",onClick:s[3]||(s[3]=n=>v(p.value))},{default:a(()=>[T(" \u767B \u5F55\xA0"),o(c,null,{default:a(()=>[o(i)]),_:1})]),_:1})])]),_:1},8,["model"])])]),u(f).companyName?(b(),h("div",H,F(u(f).companyName),1)):q("",!0)])}}});const te=U(Q,[["__scopeId","data-v-0fd4c22f"]]);export{te as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m as t}from"./manage-list.8ab8e06b.js";import{g as s,e,d as r,a as i}from"./user.0bac8e4f.js";import{d as n,o,c as a,b as c}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";import"./send_request.cc43fdb9.js";const p={class:"container"},L=n({__name:"privilege-user-setting",setup(d){return(m,u)=>(o(),a("div",p,[c(t,{"list-func":s,"add-func":e,"edit-func":e,"delete-func":r,"export-func":i,"edit-permiss":"privilege-user-setting"},null,8,["list-func","add-func","edit-func","delete-func","export-func"])]))}});export{L as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m}from"./manage-list.8ab8e06b.js";import{s}from"./send_request.cc43fdb9.js";import{d as o,o as n,c as p,b as a}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";function c(e){var r,i;let t=JSON.parse(JSON.stringify(e));return delete t.timestamp,Array.isArray(e.timestamp)&&e.timestamp.length==2&&(t.startTime=(r=e.timestamp[0])==null?void 0:r.getTime(),t.endTime=(i=e.timestamp[1])==null?void 0:i.getTime()),s({url:"/access/report/manage/getReportList",method:"GET",params:t})}function l(e){var r,i;let t=JSON.parse(JSON.stringify(e));return delete t.timestamp,Array.isArray(e.timestamp)&&e.timestamp.length==2&&(t.startTime=(r=e.timestamp[0])==null?void 0:r.getTime(),t.endTime=(i=e.timestamp[1])==null?void 0:i.getTime()),s({url:"/access/report/manage/exportReportList",method:"GET",params:t})}const u={class:"container"},h=o({__name:"report-log",setup(e){return(t,r)=>(n(),p("div",u,[a(m,{"list-func":c,"export-func":l,"edit-permiss":"privilege-user-setting"},null,8,["list-func","export-func"])]))}});export{h as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{bU as O,bV as S,bW as P,bX as j,bY as L,bP as b}from"./index.f859bf4e.js";import{v as N}from"./el-input.f35758e8.js";var o=O,g=Object.prototype.hasOwnProperty,x=Array.isArray,s={allowDots:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decoder:o.decode,delimiter:"&",depth:5,ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictNullHandling:!1},E=function(i){return i.replace(/&#(\d+);/g,function(e,r){return String.fromCharCode(parseInt(r,10))})},v=function(i,e){return i&&typeof i=="string"&&e.comma&&i.indexOf(",")>-1?i.split(","):i},A="utf8=%26%2310003%3B",D="utf8=%E2%9C%93",H=function(e,r){var n={},c=r.ignoreQueryPrefix?e.replace(/^\?/,""):e,u=r.parameterLimit===1/0?void 0:r.parameterLimit,t=c.split(r.delimiter,u),l=-1,a,f=r.charset;if(r.charsetSentinel)for(a=0;a<t.length;++a)t[a].indexOf("utf8=")===0&&(t[a]===D?f="utf-8":t[a]===A&&(f="iso-8859-1"),l=a,a=t.length);for(a=0;a<t.length;++a)if(a!==l){var d=t[a],p=d.indexOf("]="),h=p===-1?d.indexOf("="):p+1,y,m;h===-1?(y=r.decoder(d,s.decoder,f,"key"),m=r.strictNullHandling?null:""):(y=r.decoder(d.slice(0,h),s.decoder,f,"key"),m=o.maybeMap(v(d.slice(h+1),r),function(w){return r.decoder(w,s.decoder,f,"value")})),m&&r.interpretNumericEntities&&f==="iso-8859-1"&&(m=E(m)),d.indexOf("[]=")>-1&&(m=x(m)?[m]:m),g.call(n,y)?n[y]=o.combine(n[y],m):n[y]=m}return n},C=function(i,e,r,n){for(var c=n?e:v(e,r),u=i.length-1;u>=0;--u){var t,l=i[u];if(l==="[]"&&r.parseArrays)t=[].concat(c);else{t=r.plainObjects?Object.create(null):{};var a=l.charAt(0)==="["&&l.charAt(l.length-1)==="]"?l.slice(1,-1):l,f=parseInt(a,10);!r.parseArrays&&a===""?t={0:c}:!isNaN(f)&&l!==a&&String(f)===a&&f>=0&&r.parseArrays&&f<=r.arrayLimit?(t=[],t[f]=c):a!=="__proto__"&&(t[a]=c)}c=t}return c},Q=function(e,r,n,c){if(!!e){var u=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,t=/(\[[^[\]]*])/,l=/(\[[^[\]]*])/g,a=n.depth>0&&t.exec(u),f=a?u.slice(0,a.index):u,d=[];if(f){if(!n.plainObjects&&g.call(Object.prototype,f)&&!n.allowPrototypes)return;d.push(f)}for(var p=0;n.depth>0&&(a=l.exec(u))!==null&&p<n.depth;){if(p+=1,!n.plainObjects&&g.call(Object.prototype,a[1].slice(1,-1))&&!n.allowPrototypes)return;d.push(a[1])}return a&&d.push("["+u.slice(a.index)+"]"),C(d,r,n,c)}},T=function(e){if(!e)return s;if(e.decoder!==null&&e.decoder!==void 0&&typeof e.decoder!="function")throw new TypeError("Decoder has to be a function.");if(typeof e.charset<"u"&&e.charset!=="utf-8"&&e.charset!=="iso-8859-1")throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var r=typeof e.charset>"u"?s.charset:e.charset;return{allowDots:typeof e.allowDots>"u"?s.allowDots:!!e.allowDots,allowPrototypes:typeof e.allowPrototypes=="boolean"?e.allowPrototypes:s.allowPrototypes,allowSparse:typeof e.allowSparse=="boolean"?e.allowSparse:s.allowSparse,arrayLimit:typeof e.arrayLimit=="number"?e.arrayLimit:s.arrayLimit,charset:r,charsetSentinel:typeof e.charsetSentinel=="boolean"?e.charsetSentinel:s.charsetSentinel,comma:typeof e.comma=="boolean"?e.comma:s.comma,decoder:typeof e.decoder=="function"?e.decoder:s.decoder,delimiter:typeof e.delimiter=="string"||o.isRegExp(e.delimiter)?e.delimiter:s.delimiter,depth:typeof e.depth=="number"||e.depth===!1?+e.depth:s.depth,ignoreQueryPrefix:e.ignoreQueryPrefix===!0,interpretNumericEntities:typeof e.interpretNumericEntities=="boolean"?e.interpretNumericEntities:s.interpretNumericEntities,parameterLimit:typeof e.parameterLimit=="number"?e.parameterLimit:s.parameterLimit,parseArrays:e.parseArrays!==!1,plainObjects:typeof e.plainObjects=="boolean"?e.plainObjects:s.plainObjects,strictNullHandling:typeof e.strictNullHandling=="boolean"?e.strictNullHandling:s.strictNullHandling}},_=function(i,e){var r=T(e);if(i===""||i===null||typeof i>"u")return r.plainObjects?Object.create(null):{};for(var n=typeof i=="string"?H(i,r):i,c=r.plainObjects?Object.create(null):{},u=Object.keys(n),t=0;t<u.length;++t){var l=u[t],a=Q(l,n[l],r,typeof i=="string");c=o.merge(c,a,r)}return r.allowSparse===!0?c:o.compact(c)},$=S,I=_,U=P,V={formats:U,parse:I,stringify:$};async function M({url:i,method:e="POST",params:r,useQS:n=!1,callback:c}){if(!i)return!1;const u=N.service({lock:!0,text:"\u8BF7\u7A0D\u5019",background:"rgba(0, 0, 0, 0.7)"});let t={baseURL:j.backendHost,url:i,method:e,withCredentials:!0};return e.toUpperCase()=="POST"?(t.headers={"content-type":"application/x-www-form-urlencoded"},t.data=n?V.stringify(r):r):e.toUpperCase()=="GET"&&(t.params=r),L(t).then(l=>{let a=l.data;if(!a.success)return b.error((a==null?void 0:a.msg)||"\u670D\u52A1\u5668\u9519\u8BEF"),null;let f=a.data;return typeof c=="function"&&c(f),f}).catch(l=>(console.error(l),b.error(l.message),!1)).finally(()=>{u.close()})}export{M as s};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m as r}from"./manage-list.8ab8e06b.js";import{s as t}from"./send_request.cc43fdb9.js";import{d as a,o as n,c as s,b as u}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";function i(e){return t({url:"/shop/good/manage/getCategoryList",method:"GET",params:e})}function o(e){return t({url:"/shop/good/manage/editCategory",method:"POST",useQS:!0,params:e})}function c(e){return t({url:"/shop/good/manage/deleteCategory",method:"POST",useQS:!0,params:e})}function d(e){return t({url:"/shop/good/manage/exportCategoryList",method:"GET",params:e})}const m={class:"container"},L=a({__name:"shop-cate-setting",setup(e){return(p,f)=>(n(),s("div",m,[u(r,{"list-func":i,"add-func":o,"edit-func":o,"delete-func":c,"export-func":d,"edit-permiss":"shop-cate-setting"},null,8,["list-func","add-func","edit-func","delete-func","export-func"])]))}});export{L as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{m as n}from"./manage-list.8ab8e06b.js";import{s as e}from"./send_request.cc43fdb9.js";import{d as r,o as s,c as d,b as a}from"./index.f859bf4e.js";import"./el-overlay.1542ee54.js";import"./el-input.f35758e8.js";import"./el-progress.d53d438b.js";function u(o){return e({url:"/shop/good/manage/getGoodList",method:"GET",params:o})}function t(o){return e({url:"/shop/good/manage/editGood",method:"POST",useQS:!0,params:o})}function i(o){return e({url:"/shop/good/manage/deleteGood",method:"POST",useQS:!0,params:o})}function m(o){return e({url:"/shop/good/manage/exportGoodList",method:"GET",params:o})}const c={class:"container"},L=r({__name:"shop-good-setting",setup(o){return(p,f)=>(s(),d("div",c,[a(n,{"list-func":u,"add-func":t,"edit-func":t,"delete-func":i,"export-func":m,"edit-permiss":"shop-good-setting"},null,8,["list-func","add-func","edit-func","delete-func","export-func"])]))}});export{L as default};
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
import{s as r}from"./send_request.cc43fdb9.js";function u({username:e,password:s}){return r({url:"/user/login",method:"POST",useQS:!0,params:{username:e,password:s}})}function a(e){return r({url:"/user/manage/getUserList",method:"GET",params:e})}function n(e){return r({url:"/user/manage/editUser",method:"POST",useQS:!0,params:e})}function o(e){return r({url:"/user/manage/deleteUser",method:"POST",useQS:!0,params:e})}function m(e){return r({url:"/user/manage/exportUserList",method:"GET",params:e})}export{m as a,o as d,n as e,a as g,u};
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
/*!
 | 
			
		||||
 * Cropper.js v1.5.13
 | 
			
		||||
 * https://fengyuanchen.github.io/cropperjs
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2015-present Chen Fengyuan
 | 
			
		||||
 * Released under the MIT license
 | 
			
		||||
 *
 | 
			
		||||
 * Date: 2022-11-20T05:30:43.444Z
 | 
			
		||||
 */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-wrap-box,.cropper-canvas,.cropper-drag-box,.cropper-crop-box,.cropper-modal{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-wrap-box,.cropper-canvas{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:#3399ffbf;overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:calc(100% / 3);left:0;top:calc(100% / 3);width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:calc(100% / 3);top:0;width:calc(100% / 3)}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:before,.cropper-center:after{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width: 768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width: 992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width: 1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC)}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}.info[data-v-cdea44c0]{text-align:center;padding:35px 0}.info-image[data-v-cdea44c0]{position:relative;margin:auto;width:100px;height:100px;background:#f8f8f8;border:1px solid #eee;border-radius:50px;overflow:hidden}.info-edit[data-v-cdea44c0]{display:flex;justify-content:center;align-items:center;position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0,0,0,.5);opacity:0;transition:opacity .3s ease}.info-edit i[data-v-cdea44c0]{color:#eee;font-size:25px}.info-image:hover .info-edit[data-v-cdea44c0]{opacity:1}.info-name[data-v-cdea44c0]{margin:15px 0 10px;font-size:24px;font-weight:500;color:#262626}.crop-demo-btn[data-v-cdea44c0]{position:relative}.crop-input[data-v-cdea44c0]{position:absolute;width:100px;height:40px;left:0;top:0;opacity:0;cursor:pointer}
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="">
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="utf-8">
 | 
			
		||||
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
 | 
			
		||||
  <title></title>
 | 
			
		||||
  <link rel="stylesheet" href="https://at.alicdn.com/t/font_830376_qzecyukz0s.css">
 | 
			
		||||
  <script type="module" crossorigin src="./assets/index.f859bf4e.js"></script>
 | 
			
		||||
  <link rel="stylesheet" href="./assets/index.87e2e9b7.css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
  <noscript>
 | 
			
		||||
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
 | 
			
		||||
      Please enable it to continue.</strong>
 | 
			
		||||
  </noscript>
 | 
			
		||||
  <div id="app"></div>
 | 
			
		||||
  
 | 
			
		||||
  <!-- built files will be auto injected -->
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
@@ -61,6 +61,13 @@ public class AccessLogController {
 | 
			
		||||
            return Res.error("参数错误");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 推送到门禁端
 | 
			
		||||
        JSONObject websocketData = new JSONObject();
 | 
			
		||||
        websocketData.put("gateId", gateId);
 | 
			
		||||
        websocketData.put("action", "onopen");
 | 
			
		||||
        String websocketJSON = websocketData.toString();
 | 
			
		||||
        WebSocketServer.sendAllMessage(websocketJSON);
 | 
			
		||||
 | 
			
		||||
        AccessLog accessLog = new AccessLog();
 | 
			
		||||
        accessLog.setId(null);
 | 
			
		||||
        accessLog.setType(type);
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,14 @@ public class GateController {
 | 
			
		||||
        Long gateId = Long.valueOf(id);
 | 
			
		||||
        Gate gate = gateService.getGateById(gateId);
 | 
			
		||||
        GateVO gateVO = GateVO.convertFrom(gate);
 | 
			
		||||
 | 
			
		||||
        // 推送到门禁端
 | 
			
		||||
        JSONObject websocketData = new JSONObject();
 | 
			
		||||
        websocketData.put("gateId", id);
 | 
			
		||||
        websocketData.put("action", "onscan");
 | 
			
		||||
        String websocketJSON = websocketData.toString();
 | 
			
		||||
        WebSocketServer.sendAllMessage(websocketJSON);
 | 
			
		||||
 | 
			
		||||
        return Res.success(gateVO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package com.cxyxiaomo.epp.access.controller;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.fastjson2.JSONObject;
 | 
			
		||||
import com.cxyxiaomo.epp.access.pojo.UnlimitedQRCodeParam;
 | 
			
		||||
import com.cxyxiaomo.epp.access.service.WeChatTokenServiceImpl;
 | 
			
		||||
import com.cxyxiaomo.epp.common.response.Res;
 | 
			
		||||
@@ -47,7 +48,28 @@ public class WeChatTokenController {
 | 
			
		||||
        unlimitedQRCodeParam.setIsHyaline(isHyaline);
 | 
			
		||||
        okhttp3.ResponseBody responseBody = weChatTokenService.getUnlimitedQRCodeFromApi(accessToken, unlimitedQRCodeParam);
 | 
			
		||||
 | 
			
		||||
        return responseBody.bytes();
 | 
			
		||||
        try {
 | 
			
		||||
            // {"errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest, could get access_token by getStableAccessToken, more details at https://mmbizurl.cn/s/JtxxFh33r rid: 6446bac4-4a6b0410-118a16e7"}
 | 
			
		||||
            if (Objects.requireNonNull(responseBody.contentType()).subtype().equals("json")) {
 | 
			
		||||
                // 返回了 JSON 说明失败了
 | 
			
		||||
                String jsonString = responseBody.string();
 | 
			
		||||
                JSONObject jsonObject = JSONObject.parseObject(jsonString);
 | 
			
		||||
                String errcode = jsonObject.getString("errcode");
 | 
			
		||||
                if (errcode.equals("40001")) {
 | 
			
		||||
                    // 重新获取 Access Token
 | 
			
		||||
                    accessToken = weChatTokenService.getAccessToken(true);
 | 
			
		||||
                    responseBody = weChatTokenService.getUnlimitedQRCodeFromApi(accessToken, unlimitedQRCodeParam);
 | 
			
		||||
                } else if (errcode.equals("40013")) {
 | 
			
		||||
                    System.out.println("40013 invalid appid 不合法的 AppID ,请开发者检查 AppID 的正确性,避免异常字符,注意大小写\n" +
 | 
			
		||||
                            "docs: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html");
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // 返回了图片,直接返回
 | 
			
		||||
            return responseBody.bytes();
 | 
			
		||||
        } catch (NullPointerException ignored) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping(value = "/rpc/getOpenIdFromApi")
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ public class WebSocketServer {
 | 
			
		||||
    private Session session;
 | 
			
		||||
 | 
			
		||||
    // session集合,存放对应的session
 | 
			
		||||
    private static ConcurrentHashMap<Integer, Session> sessionPool = new ConcurrentHashMap<>();
 | 
			
		||||
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();
 | 
			
		||||
 | 
			
		||||
    // concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
 | 
			
		||||
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
 | 
			
		||||
@@ -30,7 +30,7 @@ public class WebSocketServer {
 | 
			
		||||
     * @param userId  用户ID
 | 
			
		||||
     */
 | 
			
		||||
    @OnOpen
 | 
			
		||||
    public void onOpen(Session session, @PathParam(value = "userId") Integer userId) {
 | 
			
		||||
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
 | 
			
		||||
        log.info("WebSocket建立连接中,连接用户ID:{}", userId);
 | 
			
		||||
        try {
 | 
			
		||||
            Session historySession = sessionPool.get(userId);
 | 
			
		||||
@@ -84,7 +84,7 @@ public class WebSocketServer {
 | 
			
		||||
     * @param userId  用户ID
 | 
			
		||||
     * @param message 发送的消息
 | 
			
		||||
     */
 | 
			
		||||
    public static void sendMessageByUser(Integer userId, String message) {
 | 
			
		||||
    public static void sendMessageByUser(String userId, String message) {
 | 
			
		||||
        log.info("用户ID:" + userId + ",推送内容:" + message);
 | 
			
		||||
        Session session = sessionPool.get(userId);
 | 
			
		||||
        try {
 | 
			
		||||
 
 | 
			
		||||
@@ -35,11 +35,17 @@ public class WeChatTokenServiceImpl implements WeChatTokenService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getAccessToken() {
 | 
			
		||||
        // 首先从数据库中查询是否存在 access_token
 | 
			
		||||
        // 如果存在且没有过期,那么就直接返回(距离失效时间小于 3 分钟就当作过期)
 | 
			
		||||
        Setting atSetting = accessDao.getValueByKey(SETTING_KEY);
 | 
			
		||||
        if (atSetting != null && LocalDateTime.now().plusMinutes(3L).compareTo(atSetting.getTime()) < 0) {
 | 
			
		||||
            return atSetting.getValue();
 | 
			
		||||
        return getAccessToken(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getAccessToken(Boolean forceUpdate) {
 | 
			
		||||
        if (!forceUpdate) {
 | 
			
		||||
            // 首先从数据库中查询是否存在 access_token
 | 
			
		||||
            // 如果存在且没有过期,那么就直接返回(距离失效时间小于 3 分钟就当作过期)
 | 
			
		||||
            Setting atSetting = accessDao.getValueByKey(SETTING_KEY);
 | 
			
		||||
            if (atSetting != null && LocalDateTime.now().plusMinutes(3L).compareTo(atSetting.getTime()) < 0) {
 | 
			
		||||
                return atSetting.getValue();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 否则则去请求一个新的 access_token
 | 
			
		||||
 
 | 
			
		||||
@@ -2,18 +2,31 @@ package com.cxyxiaomo.epp.shop.controller;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.fastjson2.JSONArray;
 | 
			
		||||
import com.alibaba.fastjson2.JSONObject;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.enums.AddType;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.enums.EditType;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.enums.FieldType;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.enums.SearchType;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.query.PageQuery;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.utils.FieldBuilder;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.utils.FieldMapperBuilder;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.utils.FieldRuleBuilder;
 | 
			
		||||
import com.cxyxiaomo.epp.PageTable.utils.FieldRuleListBuilder;
 | 
			
		||||
import com.cxyxiaomo.epp.common.enums.OrderStatus;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.Order;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.OrderDetail;
 | 
			
		||||
import com.cxyxiaomo.epp.common.query.OrderQuery;
 | 
			
		||||
import com.cxyxiaomo.epp.common.response.Res;
 | 
			
		||||
import com.cxyxiaomo.epp.common.vo.GoodVO;
 | 
			
		||||
import com.cxyxiaomo.epp.common.vo.OrderDetailVO;
 | 
			
		||||
import com.cxyxiaomo.epp.common.vo.OrderVO;
 | 
			
		||||
import com.cxyxiaomo.epp.shop.service.GoodService;
 | 
			
		||||
import com.cxyxiaomo.epp.shop.service.OrderService;
 | 
			
		||||
import com.github.pagehelper.PageHelper;
 | 
			
		||||
import com.github.pagehelper.PageInfo;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@@ -30,8 +43,8 @@ public class OrderController {
 | 
			
		||||
    /**
 | 
			
		||||
     * 小程序端创建订单
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId    下单用户
 | 
			
		||||
     * @param orderList 下单商品 [ { goodId, count }, ... ]
 | 
			
		||||
     * @param params userId    下单用户
 | 
			
		||||
     * @param params orderList 下单商品 [ { goodId, count }, ... ]
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/miniprogram/createOrder")
 | 
			
		||||
@@ -184,6 +197,12 @@ public class OrderController {
 | 
			
		||||
        return Res.success(success ? "支付成功" : "支付失败");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户取消订单
 | 
			
		||||
     *
 | 
			
		||||
     * @param params
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/miniprogram/cancelOrder")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res cancelOrder(@RequestBody JSONObject params) {
 | 
			
		||||
@@ -224,6 +243,106 @@ public class OrderController {
 | 
			
		||||
        return Res.success(success ? "取消成功" : "取消失败");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单发货
 | 
			
		||||
     *
 | 
			
		||||
     * @param orderId
 | 
			
		||||
     * @param expressId
 | 
			
		||||
     * @param comment
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/manage/deliverOrder")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res deliverOrder(Long orderId, String expressId, String comment) {
 | 
			
		||||
        if (orderId == null || expressId == null || comment == null) {
 | 
			
		||||
            return Res.error("参数错误");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (expressId.equals("") && comment.equals("")) {
 | 
			
		||||
            return Res.error("运单号 和 发货备注 不可同时为空");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 查询订单详情
 | 
			
		||||
        Order order = orderService.getOrderById(orderId);
 | 
			
		||||
        if (order == null) {
 | 
			
		||||
            return Res.error("订单不存在");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //判断是否可以发货
 | 
			
		||||
        OrderStatus orderStatus = OrderStatus.get(order.getOrderStatus());
 | 
			
		||||
        switch (orderStatus) {
 | 
			
		||||
            case PENDING:
 | 
			
		||||
                return Res.error("订单尚未支付,不可发货");
 | 
			
		||||
            case PROCESSING: // 订单未发货
 | 
			
		||||
                // 更新订单发货信息
 | 
			
		||||
                orderService.updateOrderShipInfo(orderId, expressId, comment);
 | 
			
		||||
                // 更新支付信息
 | 
			
		||||
                orderService.updateOrderStatus(orderId, OrderStatus.SHIPPED);
 | 
			
		||||
                return Res.success("发货成功");
 | 
			
		||||
            case SHIPPED: // 订单已发货,修改发货信息
 | 
			
		||||
                // 更新订单发货信息
 | 
			
		||||
                orderService.updateOrderShipInfo(orderId, expressId, comment);
 | 
			
		||||
                return Res.success("发货信息修改成功");
 | 
			
		||||
            case DELIVERED:
 | 
			
		||||
                return Res.error("订单已完成,无法再次发货");
 | 
			
		||||
            case CANCELLED:
 | 
			
		||||
                return Res.error("订单已取消,不可发货");
 | 
			
		||||
            default:
 | 
			
		||||
                return Res.error("当前订单状态不可发货");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 管理员取消订单
 | 
			
		||||
     *
 | 
			
		||||
     * @param orderId
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/manage/cancelOrder")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res cancelOrderByManager(Long orderId) {
 | 
			
		||||
        if (orderId == null) {
 | 
			
		||||
            return Res.error("参数错误");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 查询订单详情
 | 
			
		||||
        Order order = orderService.getOrderById(orderId);
 | 
			
		||||
        if (order == null) {
 | 
			
		||||
            return Res.error("订单不存在");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //判断是否可以取消
 | 
			
		||||
        OrderStatus orderStatus = OrderStatus.get(order.getOrderStatus());
 | 
			
		||||
        switch (orderStatus) {
 | 
			
		||||
            case PENDING:
 | 
			
		||||
                // 更新订单发货信息
 | 
			
		||||
                orderService.updateOrderShipInfo(orderId, "", "管理员取消了您的订单,如有疑问请联系管理员");
 | 
			
		||||
                // 更新支付信息
 | 
			
		||||
                orderService.updateOrderStatus(orderId, OrderStatus.CANCELLED);
 | 
			
		||||
                return Res.success("操作成功");
 | 
			
		||||
            case PROCESSING:
 | 
			
		||||
                // 更新订单发货信息
 | 
			
		||||
                orderService.updateOrderShipInfo(orderId, "", "管理员取消了您的订单,费用已退回至您的帐户,如有疑问请联系管理员");
 | 
			
		||||
                // 更新支付信息
 | 
			
		||||
                orderService.updateOrderStatus(orderId, OrderStatus.CANCELLED);
 | 
			
		||||
                return Res.success("操作成功");
 | 
			
		||||
            case SHIPPED:
 | 
			
		||||
                return Res.error("订单已发货,不可取消");
 | 
			
		||||
            case DELIVERED:
 | 
			
		||||
                return Res.error("订单已送达,不可取消");
 | 
			
		||||
            case CANCELLED:
 | 
			
		||||
                return Res.error("订单已取消");
 | 
			
		||||
            default:
 | 
			
		||||
                return Res.error("当前订单状态无法取消");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单确认收货
 | 
			
		||||
     *
 | 
			
		||||
     * @param params
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/miniprogram/confirmOrder")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res confirmOrder(@RequestBody JSONObject params) {
 | 
			
		||||
@@ -261,4 +380,189 @@ public class OrderController {
 | 
			
		||||
 | 
			
		||||
        return Res.success(success ? "确认收货成功" : "确认收货失败");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取订单列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/manage/getOrderList")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res getOrderList(PageQuery pageQuery, OrderQuery orderQuery) {
 | 
			
		||||
        // 查询分页数据
 | 
			
		||||
        PageHelper.startPage(pageQuery.getPageIndex(), pageQuery.getPageSize());
 | 
			
		||||
        List<Order> orderList = orderService.getOrderList(orderQuery);
 | 
			
		||||
        PageInfo<Order> orderPageInfo = new PageInfo<>(orderList);
 | 
			
		||||
        List<Order> list = orderPageInfo.getList();
 | 
			
		||||
        List<OrderVO> voList = OrderVO.convertFrom(list);
 | 
			
		||||
 | 
			
		||||
        // id列 字段名(区分大小写;以VO中的变量名为准)
 | 
			
		||||
        // 新增、修改弹窗时,使用该列作为主键列进行操作
 | 
			
		||||
        String idFieldName = "id";
 | 
			
		||||
 | 
			
		||||
        // 当前管理页面
 | 
			
		||||
        String pageName = "订单管理";
 | 
			
		||||
 | 
			
		||||
        // 指定前端表格显示列
 | 
			
		||||
        JSONArray columns = FieldBuilder.create()
 | 
			
		||||
                .add("userId", "userId", "用户ID", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.INPUT, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("orderStatusCode", "orderStatusName", "订单状态", true,
 | 
			
		||||
                        FieldType.TEXT, SearchType.SELECT, AddType.CAN_NOT_ADD, EditType.SELECT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, "订单状态",
 | 
			
		||||
                        FieldRuleListBuilder.create()
 | 
			
		||||
                                .add(FieldRuleBuilder.create("订单状态").required()),
 | 
			
		||||
                        null
 | 
			
		||||
                )
 | 
			
		||||
                .add("orderPrice", "orderPrice", "订单价格", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("orderDate", "orderDate", "下单时间", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("payDate", "payDate", "支付时间", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("cancelDate", "cancelDate", "取消时间", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("shipDate", "shipDate", "发货时间", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("deliverDate", "deliverDate", "送达时间", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("expressId", "expressId", "运单号", "",
 | 
			
		||||
                        FieldType.TEXT, SearchType.INPUT, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .add("comment", "comment", "发货备注", "",
 | 
			
		||||
                        FieldType.LONG_TEXT, SearchType.CAN_NOT_SEARCH, AddType.CAN_NOT_ADD, EditType.CAN_NOT_EDIT,
 | 
			
		||||
                        FieldBuilder.SEARCH_PLACEHOLDER_SAME_AS_FIELDNAME,
 | 
			
		||||
                        null, null, null, null
 | 
			
		||||
                )
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        // 指定需要翻译的字段
 | 
			
		||||
        OrderStatus[] orderStatusList = OrderStatus.values();
 | 
			
		||||
        HashMap<String, String> orderStatusMap = new HashMap<>(orderStatusList.length);
 | 
			
		||||
        for (OrderStatus orderStatus : orderStatusList) {
 | 
			
		||||
            orderStatusMap.put(orderStatus.getValue(), orderStatus.toString());
 | 
			
		||||
        }
 | 
			
		||||
        // build
 | 
			
		||||
        JSONArray fieldMapper = FieldMapperBuilder.create()
 | 
			
		||||
                .add("orderStatusCode", "orderStatusName", orderStatusMap)
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        // 拼装返回结果
 | 
			
		||||
        JSONObject map = new JSONObject(6);
 | 
			
		||||
        map.put("total", orderPageInfo.getTotal());
 | 
			
		||||
        map.put("list", voList);
 | 
			
		||||
        map.put("columns", columns);
 | 
			
		||||
        map.put("fieldMapper", fieldMapper);
 | 
			
		||||
        map.put("idFieldName", idFieldName);
 | 
			
		||||
        map.put("pageName", pageName);
 | 
			
		||||
 | 
			
		||||
        // 返回结果
 | 
			
		||||
        return Res.success(map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /**
 | 
			
		||||
    //  * 编辑订单
 | 
			
		||||
    //  *
 | 
			
		||||
    //  * @return
 | 
			
		||||
    //  */
 | 
			
		||||
    // @PostMapping("/manage/editOrder")
 | 
			
		||||
    // @ResponseBody
 | 
			
		||||
    // public Res editOrder(@ModelAttribute OrderVO OrderVO) {
 | 
			
		||||
    //     Order Order = OrderVO.convertTo(OrderVO);
 | 
			
		||||
    //
 | 
			
		||||
    //     // 先查询订单是否存在
 | 
			
		||||
    //     Order existOrder = orderService.getOrderById(Order.getId());
 | 
			
		||||
    //
 | 
			
		||||
    //     if (Order.getId() == null || Order.getId() < 1) {
 | 
			
		||||
    //         // 新增订单
 | 
			
		||||
    //         if (existOrder != null) {
 | 
			
		||||
    //             return Res.error("订单已存在,操作失败");
 | 
			
		||||
    //         }
 | 
			
		||||
    //
 | 
			
		||||
    //         if (Order.getOrdersName() == null || "".equals(Order.getOrdersName())) {
 | 
			
		||||
    //             return Res.error("订单名称不能为空");
 | 
			
		||||
    //         }
 | 
			
		||||
    //         Order.setId(null);
 | 
			
		||||
    //         orderService.addOrder(Order);
 | 
			
		||||
    //     } else {
 | 
			
		||||
    //         // 修改订单
 | 
			
		||||
    //         if (existOrder == null) {
 | 
			
		||||
    //             return Res.error("订单不存在,操作失败");
 | 
			
		||||
    //         }
 | 
			
		||||
    //
 | 
			
		||||
    //         orderService.updateOrder(Order);
 | 
			
		||||
    //     }
 | 
			
		||||
    //     return Res.success(true);
 | 
			
		||||
    // }
 | 
			
		||||
    //
 | 
			
		||||
    // /**
 | 
			
		||||
    //  * 关闭订单
 | 
			
		||||
    //  *
 | 
			
		||||
    //  * @param id
 | 
			
		||||
    //  * @return
 | 
			
		||||
    //  */
 | 
			
		||||
    // @PostMapping("/manage/deleteOrder")
 | 
			
		||||
    // @ResponseBody
 | 
			
		||||
    // public Res deleteOrder(Long id) {
 | 
			
		||||
    //     if (id == null || id <= 0) {
 | 
			
		||||
    //         return Res.error("订单不存在,删除失败");
 | 
			
		||||
    //     }
 | 
			
		||||
    //     // 先查询订单是否存在
 | 
			
		||||
    //     Order existOrder = orderService.getOrderById(id);
 | 
			
		||||
    //     if (existOrder == null) {
 | 
			
		||||
    //         return Res.error("订单不存在,删除失败");
 | 
			
		||||
    //     }
 | 
			
		||||
    //     boolean b = orderService.deleteOrder(existOrder.getId());
 | 
			
		||||
    //     return Res.success(b);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 导出订单列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping("/manage/exportOrderList")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public Res exportOrderList(OrderQuery orderQuery) {
 | 
			
		||||
        List<Order> orderList = orderService.getOrderList(orderQuery);
 | 
			
		||||
        List<OrderVO> orderVOList = OrderVO.convertFrom(orderList);
 | 
			
		||||
 | 
			
		||||
        // 当前时间
 | 
			
		||||
        Date now = Calendar.getInstance().getTime();
 | 
			
		||||
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
 | 
			
		||||
        String dateTime = format.format(now);
 | 
			
		||||
 | 
			
		||||
        HashMap<String, Object> map = new HashMap<>();
 | 
			
		||||
        map.put("list", orderVOList);
 | 
			
		||||
        map.put("sheetName", "订单表-" + System.currentTimeMillis());
 | 
			
		||||
        map.put("fileName", "订单表_导出时间_" + dateTime);
 | 
			
		||||
 | 
			
		||||
        return Res.success(map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,13 +27,7 @@ public interface GoodDao {
 | 
			
		||||
    Integer deleteById(Integer id);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Manage
 | 
			
		||||
    public boolean addGood(Good good);
 | 
			
		||||
 | 
			
		||||
    public boolean updateGood(Good good);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package com.cxyxiaomo.epp.shop.dao;
 | 
			
		||||
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.Order;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.OrderDetail;
 | 
			
		||||
import com.cxyxiaomo.epp.common.query.OrderQuery;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
import org.apache.ibatis.annotations.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
@@ -62,6 +63,19 @@ public interface OrderDao {
 | 
			
		||||
     */
 | 
			
		||||
    int updateOrderStatus(@Param("orderId") Long orderId, @Param("orderStatus") String orderStatus);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新订单发货信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param orderId
 | 
			
		||||
     * @param expressId
 | 
			
		||||
     * @param comment
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    int updateOrderShipInfo(@Param("orderId") Long orderId, @Param("expressId") String expressId, @Param("comment") String comment);
 | 
			
		||||
 | 
			
		||||
    // 根据订单 ID 删除订单信息及订单详情信息
 | 
			
		||||
    int deleteOrderById(Long orderId);
 | 
			
		||||
    boolean deleteOrderById(Long orderId);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public List<Order> getOrderList(OrderQuery orderQuery);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import com.cxyxiaomo.epp.common.enums.OrderStatus;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.Good;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.Order;
 | 
			
		||||
import com.cxyxiaomo.epp.common.pojo.OrderDetail;
 | 
			
		||||
import com.cxyxiaomo.epp.common.query.OrderQuery;
 | 
			
		||||
import com.cxyxiaomo.epp.common.utils.SnowflakeManager;
 | 
			
		||||
import com.cxyxiaomo.epp.common.vo.OrderDetailVO;
 | 
			
		||||
import com.cxyxiaomo.epp.shop.dao.GoodDao;
 | 
			
		||||
@@ -132,4 +133,15 @@ public class OrderService {
 | 
			
		||||
        int affectRows = orderDao.updateOrderStatus(orderId, orderStatus.getValue());
 | 
			
		||||
        return affectRows > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Boolean updateOrderShipInfo(Long orderId, String expressId, String comment) {
 | 
			
		||||
        int affectRows = orderDao.updateOrderShipInfo(orderId, expressId, comment);
 | 
			
		||||
        return affectRows > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public List<Order> getOrderList(OrderQuery orderQuery) {
 | 
			
		||||
        return orderDao.getOrderList(orderQuery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@
 | 
			
		||||
    </update>
 | 
			
		||||
 | 
			
		||||
    <!-- 根据订单 ID 删除订单信息及订单详情信息 -->
 | 
			
		||||
    <delete id="deleteOrderById" parameterType="java.lang.Integer">
 | 
			
		||||
    <delete id="deleteOrderById" parameterType="java.lang.Long">
 | 
			
		||||
        DELETE
 | 
			
		||||
        FROM `order`
 | 
			
		||||
        WHERE id = #{orderId};
 | 
			
		||||
@@ -104,4 +104,39 @@
 | 
			
		||||
--         FROM goods_order_details
 | 
			
		||||
--         WHERE order_id = #{orderId};
 | 
			
		||||
    </delete>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <!-- manage 相关的 SQL -->
 | 
			
		||||
    <select id="getOrderList" resultType="com.cxyxiaomo.epp.common.pojo.Order"
 | 
			
		||||
            parameterType="com.cxyxiaomo.epp.common.query.OrderQuery">
 | 
			
		||||
        SELECT * FROM `order`
 | 
			
		||||
        <where>
 | 
			
		||||
            <if test="id != null">
 | 
			
		||||
                AND id = #{id}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="userId != null">
 | 
			
		||||
                AND user_id = #{userId}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="orderStatusCode != null and orderStatusCode != ''">
 | 
			
		||||
                AND order_status = #{orderStatusCode}
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="expressId != null and expressId != ''">
 | 
			
		||||
                AND express_id = #{expressId}
 | 
			
		||||
            </if>
 | 
			
		||||
        </where>
 | 
			
		||||
    </select>
 | 
			
		||||
 | 
			
		||||
    <!-- 更新发货信息 -->
 | 
			
		||||
    <update id="updateOrderShipInfo" parameterType="com.cxyxiaomo.epp.common.pojo.Order">
 | 
			
		||||
        UPDATE `order`
 | 
			
		||||
        <set>
 | 
			
		||||
            <if test="expressId != null">
 | 
			
		||||
                express_id = #{expressId},
 | 
			
		||||
            </if>
 | 
			
		||||
            <if test="comment != null">
 | 
			
		||||
                `comment` = #{comment},
 | 
			
		||||
            </if>
 | 
			
		||||
        </set>
 | 
			
		||||
        WHERE id = #{orderId}
 | 
			
		||||
    </update>
 | 
			
		||||
</mapper>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,13 @@
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
    <!--
 | 
			
		||||
        FIXME 环境配置
 | 
			
		||||
 | 
			
		||||
        src
 | 
			
		||||
        - 线上环境:"https://epp.only4.work/access/index.html?inElectron=true"
 | 
			
		||||
        - 开发环境:"http://localhost/access/index.html?inElectron=true"
 | 
			
		||||
    -->
 | 
			
		||||
    <iframe src="https://epp-prod.only4.work/access/index.html?inElectron=true" frameborder="0"></iframe>
 | 
			
		||||
    <script src="./renderer.js" type="module"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								frontend/components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -7,13 +7,10 @@ export {}
 | 
			
		||||
 | 
			
		||||
declare module '@vue/runtime-core' {
 | 
			
		||||
  export interface GlobalComponents {
 | 
			
		||||
    Calender: typeof import('./src/components/calender.vue')['default']
 | 
			
		||||
    ContextMenu: typeof import('./src/components/context-menu.vue')['default']
 | 
			
		||||
    ElAlert: typeof import('element-plus/es')['ElAlert']
 | 
			
		||||
    ElAvatar: typeof import('element-plus/es')['ElAvatar']
 | 
			
		||||
    ElButton: typeof import('element-plus/es')['ElButton']
 | 
			
		||||
    ElCard: typeof import('element-plus/es')['ElCard']
 | 
			
		||||
    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
 | 
			
		||||
    ElCol: typeof import('element-plus/es')['ElCol']
 | 
			
		||||
    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
 | 
			
		||||
    ElDialog: typeof import('element-plus/es')['ElDialog']
 | 
			
		||||
@@ -38,6 +35,7 @@ declare module '@vue/runtime-core' {
 | 
			
		||||
    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
 | 
			
		||||
    ElTable: typeof import('element-plus/es')['ElTable']
 | 
			
		||||
    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
 | 
			
		||||
    ElTag: typeof import('element-plus/es')['ElTag']
 | 
			
		||||
    ElTooltip: typeof import('element-plus/es')['ElTooltip']
 | 
			
		||||
    ElUpload: typeof import('element-plus/es')['ElUpload']
 | 
			
		||||
    Header: typeof import('./src/components/header.vue')['default']
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						@@ -24,6 +24,7 @@
 | 
			
		||||
				"xlsx": "^0.18.5"
 | 
			
		||||
			},
 | 
			
		||||
			"devDependencies": {
 | 
			
		||||
				"@types/mockjs": "^1.0.7",
 | 
			
		||||
				"@vitejs/plugin-vue": "^3.0.0",
 | 
			
		||||
				"@vue/compiler-sfc": "^3.1.2",
 | 
			
		||||
				"typescript": "^4.6.4",
 | 
			
		||||
@@ -223,6 +224,12 @@
 | 
			
		||||
				"@types/lodash": "*"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@types/mockjs": {
 | 
			
		||||
			"version": "1.0.7",
 | 
			
		||||
			"resolved": "https://registry.npmmirror.com/@types/mockjs/-/mockjs-1.0.7.tgz",
 | 
			
		||||
			"integrity": "sha512-OCxXz6hEaJOVpRwuJMiVY5a6LtJcih+br9gwB/Q8ooOBikvk5FpBQ31OlNimXo3EqKha1Z7PFBni+q9m+8NCWg==",
 | 
			
		||||
			"dev": true
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@types/node": {
 | 
			
		||||
			"version": "18.14.0",
 | 
			
		||||
			"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.14.0.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
		"xlsx": "^0.18.5"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@types/mockjs": "^1.0.7",
 | 
			
		||||
		"@vitejs/plugin-vue": "^3.0.0",
 | 
			
		||||
		"@vue/compiler-sfc": "^3.1.2",
 | 
			
		||||
		"typescript": "^4.6.4",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								frontend/src/api/shop-order.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,63 @@
 | 
			
		||||
import send_request from '../utils/send_request';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取订单列表
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function getOrderList(params) {
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/shop/order/manage/getOrderList',
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        params: params,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取订单详情
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function getOrderDetail(params) {
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/shop/order/miniprogram/orderDetail',
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        params: params,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 订单发货
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function deliverOrder(params) {
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/shop/order/manage/deliverOrder',
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        useQS: true,
 | 
			
		||||
        params: params,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 关闭订单
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function withdrawOrder(params) {
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/shop/order/manage/cancelOrder',
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        useQS: true,
 | 
			
		||||
        params: params,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 导出订单列表
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function exportOrderList(params) {
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/shop/order/manage/exportOrderList',
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        params: params,
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
@@ -24,6 +24,24 @@ export function userLogout() {
 | 
			
		||||
    return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 修改密码
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export function updatePwd({ oldpwd, newpwd }) {
 | 
			
		||||
    let userId = localStorage.getItem("ms_user_id")
 | 
			
		||||
    return send_request({
 | 
			
		||||
        url: '/user/updatePwd',
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
        useQS: true,
 | 
			
		||||
        params: {
 | 
			
		||||
            "userId": userId,
 | 
			
		||||
            "oldpwd": oldpwd,
 | 
			
		||||
            "newpwd": newpwd,
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 获取用户列表
 | 
			
		||||
 * @returns
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
        <div class="header-right">
 | 
			
		||||
            <div class="header-user-con">
 | 
			
		||||
                <!-- 消息中心 -->
 | 
			
		||||
                <div class="btn-bell" @click="router.push('/tabs')">
 | 
			
		||||
                <div class="btn-bell" @click="router.push('/tabs')" v-if="false">
 | 
			
		||||
                    <el-tooltip effect="dark" :content="message ? `有${message}条未读消息` : `消息中心`" placement="bottom">
 | 
			
		||||
                        <i class="el-icon-lx-notice"></i>
 | 
			
		||||
                    </el-tooltip>
 | 
			
		||||
 
 | 
			
		||||
@@ -56,16 +56,27 @@
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                    </template>
 | 
			
		||||
                </el-table-column>
 | 
			
		||||
                <el-table-column label="操作" width="220" align="center" v-if="props.editFunc || props.deleteFunc">
 | 
			
		||||
                <el-table-column label="操作" width="220" align="center"
 | 
			
		||||
                    v-if="props.editFunc || props.deleteFunc || props.customEditHandle">
 | 
			
		||||
                    <template #default="scope">
 | 
			
		||||
                        <el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)"
 | 
			
		||||
                            v-permiss="props.editPermiss" v-if="props.editFunc">
 | 
			
		||||
                            编辑
 | 
			
		||||
                        </el-button>
 | 
			
		||||
                        <el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index, scope.row)"
 | 
			
		||||
                            v-permiss="props.editPermiss" v-if="props.deleteFunc">
 | 
			
		||||
                            删除
 | 
			
		||||
                        </el-button>
 | 
			
		||||
                        <template v-if="props.customEditHandle">
 | 
			
		||||
                            <el-button text :icon="List"
 | 
			
		||||
                                @click="props.customEditHandle((scope as any).$index, (scope as any).row, getData)"
 | 
			
		||||
                                v-permiss="props.editPermiss">
 | 
			
		||||
                                管理
 | 
			
		||||
                            </el-button>
 | 
			
		||||
                        </template>
 | 
			
		||||
                        <template v-else>
 | 
			
		||||
                            <el-button text :icon="Edit" @click="handleEdit((scope as any).$index, (scope as any).row)"
 | 
			
		||||
                                v-permiss="props.editPermiss" v-if="props.editFunc">
 | 
			
		||||
                                编辑
 | 
			
		||||
                            </el-button>
 | 
			
		||||
                            <el-button text :icon="Delete" class="red"
 | 
			
		||||
                                @click="handleDelete((scope as any).$index, (scope as any).row)"
 | 
			
		||||
                                v-permiss="props.editPermiss" v-if="props.deleteFunc">
 | 
			
		||||
                                删除
 | 
			
		||||
                            </el-button>
 | 
			
		||||
                        </template>
 | 
			
		||||
                    </template>
 | 
			
		||||
                </el-table-column>
 | 
			
		||||
            </el-table>
 | 
			
		||||
@@ -141,7 +152,7 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, reactive, onMounted, computed } from 'vue';
 | 
			
		||||
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
 | 
			
		||||
import { Delete, Edit, Search, Plus, Filter, Download } from '@element-plus/icons-vue';
 | 
			
		||||
import { Delete, Edit, Search, Plus, Filter, Download, List } from '@element-plus/icons-vue';
 | 
			
		||||
import * as xlsx from 'xlsx';
 | 
			
		||||
import Mock from 'mockjs';
 | 
			
		||||
import ImageUpload from './image-upload.vue';
 | 
			
		||||
@@ -176,6 +187,12 @@ const props = defineProps({
 | 
			
		||||
    'editPermiss': {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 自定义修改按钮点击事件
 | 
			
		||||
    'customEditHandle': {
 | 
			
		||||
        type: Function,
 | 
			
		||||
        required: false,
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -431,10 +448,10 @@ const saveEdit = async (formEl: FormInstance | undefined) => {
 | 
			
		||||
        var result;
 | 
			
		||||
        if (formId > 0) {
 | 
			
		||||
            // 修改记录
 | 
			
		||||
            var result = await props.editFunc(form)
 | 
			
		||||
            var result = await props.editFunc?.(form)
 | 
			
		||||
        } else {
 | 
			
		||||
            // 新增记录
 | 
			
		||||
            var result = await props.addFunc(form)
 | 
			
		||||
            var result = await props.addFunc?.(form)
 | 
			
		||||
            query.pageIndex = Math.ceil((pageTotal.value + 1) / query.pageSize);
 | 
			
		||||
        }
 | 
			
		||||
        console.log("result", result)
 | 
			
		||||
@@ -460,7 +477,7 @@ const handleDelete = (index: number, row: any) => {
 | 
			
		||||
    // 二次确认删除
 | 
			
		||||
    ElMessageBox.confirm('确定要删除吗?', '提示', { type: 'warning' })
 | 
			
		||||
        .then(async () => {
 | 
			
		||||
            var result = await props.deleteFunc({
 | 
			
		||||
            var result = await props.deleteFunc?.({
 | 
			
		||||
                id: row[idFieldName],
 | 
			
		||||
            })
 | 
			
		||||
            if (result) {
 | 
			
		||||
@@ -540,7 +557,7 @@ const handleExport = async () => {
 | 
			
		||||
        // 数据部分
 | 
			
		||||
        let excelList = dataList.map((row: any) => {
 | 
			
		||||
            // 通过翻译前的 key 拿数据
 | 
			
		||||
            return fieldNameList.map((field: any) => String(row[field]))
 | 
			
		||||
            return fieldNameList.map((field: any) => String(row[field] || ""))
 | 
			
		||||
        })
 | 
			
		||||
        excelList.unshift(firstRow) // 插入表头
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,11 @@ const items = [
 | 
			
		||||
                title: '商品管理',
 | 
			
		||||
                permiss: 'shop-good-setting',
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                index: '/shop-order-setting',
 | 
			
		||||
                title: '订单管理',
 | 
			
		||||
                permiss: 'shop-order-setting',
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,15 @@ const routes: RouteRecordRaw[] = [
 | 
			
		||||
                },
 | 
			
		||||
                component: () => import('../views/shop-good-setting.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/shop-order-setting',
 | 
			
		||||
                name: 'shop-order-setting',
 | 
			
		||||
                meta: {
 | 
			
		||||
                    title: '订单管理',
 | 
			
		||||
                    permiss: 'shop-order-setting',
 | 
			
		||||
                },
 | 
			
		||||
                component: () => import('../views/shop-order-setting.vue'),
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ export const usePermissStore = defineStore('permiss', {
 | 
			
		||||
                "shop",
 | 
			
		||||
                "shop-cate-setting",
 | 
			
		||||
                "shop-good-setting",
 | 
			
		||||
                "shop-order-setting",
 | 
			
		||||
 | 
			
		||||
                "privilege",
 | 
			
		||||
                "privilege-user-setting",
 | 
			
		||||
@@ -46,6 +47,7 @@ export const usePermissStore = defineStore('permiss', {
 | 
			
		||||
                "shop",
 | 
			
		||||
                "shop-cate-setting",
 | 
			
		||||
                "shop-good-setting",
 | 
			
		||||
                "shop-order-setting",
 | 
			
		||||
 | 
			
		||||
                "privilege",
 | 
			
		||||
                "privilege-user-setting",
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,12 @@ export default {
 | 
			
		||||
    /**
 | 
			
		||||
     * 后端接口请求地址
 | 
			
		||||
     * (结尾加不加 / 都可)
 | 
			
		||||
     *
 | 
			
		||||
     * FIXME 环境配置
 | 
			
		||||
     *
 | 
			
		||||
     * backendHost
 | 
			
		||||
     * - 线上环境:"https://epp.only4.work/"
 | 
			
		||||
     * - 开发环境:"http://localhost/"
 | 
			
		||||
     */
 | 
			
		||||
    backendHost: "https://epp-prod.only4.work/",
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,213 +1,34 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="container">
 | 
			
		||||
		<el-row :gutter="20">
 | 
			
		||||
			<el-col :span="8">
 | 
			
		||||
				<el-card shadow="hover" class="mgb20" style="height: 252px">
 | 
			
		||||
					<div class="user-info">
 | 
			
		||||
						<el-avatar :size="120" :src="imgurl" />
 | 
			
		||||
						<div class="user-info-cont">
 | 
			
		||||
							<div class="user-info-name">{{ name }}</div>
 | 
			
		||||
							<div>{{ role }}</div>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="user-info-list">
 | 
			
		||||
						上次登录时间:
 | 
			
		||||
						<span>2022-10-01</span>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="user-info-list">
 | 
			
		||||
						上次登录地点:
 | 
			
		||||
						<span>东莞</span>
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
				<el-card shadow="hover" style="height: 252px">
 | 
			
		||||
					<template #header>
 | 
			
		||||
						<div class="clearfix">
 | 
			
		||||
							<span>语言详情</span>
 | 
			
		||||
						</div>
 | 
			
		||||
					</template>
 | 
			
		||||
					Vue
 | 
			
		||||
					<el-progress :percentage="79.4" color="#42b983"></el-progress>
 | 
			
		||||
					TypeScript
 | 
			
		||||
					<el-progress :percentage="14" color="#f1e05a"></el-progress>
 | 
			
		||||
					CSS
 | 
			
		||||
					<el-progress :percentage="5.6"></el-progress>
 | 
			
		||||
					HTML
 | 
			
		||||
					<el-progress :percentage="1" color="#f56c6c"></el-progress>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
			<el-col :span="16">
 | 
			
		||||
				<el-row :gutter="20" class="mgb20">
 | 
			
		||||
					<el-col :span="8">
 | 
			
		||||
						<el-card shadow="hover" :body-style="{ padding: '0px' }">
 | 
			
		||||
							<div class="grid-content grid-con-1">
 | 
			
		||||
								<el-icon class="grid-con-icon"><User /></el-icon>
 | 
			
		||||
								<div class="grid-cont-right">
 | 
			
		||||
									<div class="grid-num">1234</div>
 | 
			
		||||
									<div>用户访问量</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						</el-card>
 | 
			
		||||
					</el-col>
 | 
			
		||||
					<el-col :span="8">
 | 
			
		||||
						<el-card shadow="hover" :body-style="{ padding: '0px' }">
 | 
			
		||||
							<div class="grid-content grid-con-2">
 | 
			
		||||
								<el-icon class="grid-con-icon"><ChatDotRound /></el-icon>
 | 
			
		||||
								<div class="grid-cont-right">
 | 
			
		||||
									<div class="grid-num">321</div>
 | 
			
		||||
									<div>系统消息</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						</el-card>
 | 
			
		||||
					</el-col>
 | 
			
		||||
					<el-col :span="8">
 | 
			
		||||
						<el-card shadow="hover" :body-style="{ padding: '0px' }">
 | 
			
		||||
							<div class="grid-content grid-con-3">
 | 
			
		||||
								<el-icon class="grid-con-icon"><Goods /></el-icon>
 | 
			
		||||
								<div class="grid-cont-right">
 | 
			
		||||
									<div class="grid-num">500</div>
 | 
			
		||||
									<div>商品数量</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						</el-card>
 | 
			
		||||
					</el-col>
 | 
			
		||||
				</el-row>
 | 
			
		||||
				<el-card shadow="hover" style="height: 403px">
 | 
			
		||||
					<template #header>
 | 
			
		||||
						<div class="clearfix">
 | 
			
		||||
							<span>预警列表</span>
 | 
			
		||||
							<el-button style="float: right; padding: 3px 0" text>添加</el-button>
 | 
			
		||||
						</div>
 | 
			
		||||
					</template>
 | 
			
		||||
 | 
			
		||||
					<el-table :show-header="false" :data="todoList" style="width: 100%">
 | 
			
		||||
						<el-table-column width="40">
 | 
			
		||||
							<template #default="scope">
 | 
			
		||||
								<el-checkbox v-model="scope.row.status"></el-checkbox>
 | 
			
		||||
							</template>
 | 
			
		||||
						</el-table-column>
 | 
			
		||||
						<el-table-column>
 | 
			
		||||
							<template #default="scope">
 | 
			
		||||
								<div
 | 
			
		||||
									class="todo-item"
 | 
			
		||||
									:class="{
 | 
			
		||||
										'todo-item-del': scope.row.status
 | 
			
		||||
									}"
 | 
			
		||||
								>
 | 
			
		||||
									{{ scope.row.title }}
 | 
			
		||||
								</div>
 | 
			
		||||
							</template>
 | 
			
		||||
						</el-table-column>
 | 
			
		||||
					</el-table>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
		</el-row>
 | 
			
		||||
	</div>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <el-card shadow="hover" class="mgb20" style="height: 252px">
 | 
			
		||||
            <div class="user-info">
 | 
			
		||||
                <el-avatar :size="120" :src="imgurl" />
 | 
			
		||||
                <div class="user-info-cont">
 | 
			
		||||
                    <div class="user-info-name">{{ name }}</div>
 | 
			
		||||
                    <div>{{ role }}</div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="user-info-list">
 | 
			
		||||
                上次登录时间:
 | 
			
		||||
                <span>2022-10-01</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="user-info-list">
 | 
			
		||||
                上次登录地点:
 | 
			
		||||
                <span>东莞</span>
 | 
			
		||||
            </div>
 | 
			
		||||
        </el-card>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts" name="dashboard">
 | 
			
		||||
import { ref, reactive } from 'vue';
 | 
			
		||||
import imgurl from '../assets/img/img.jpg';
 | 
			
		||||
 | 
			
		||||
const roleMap = {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
const name = localStorage.getItem('ms_username');
 | 
			
		||||
const role: string = name === 'admin' ? '超级管理员' : '普通用户';
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.el-row {
 | 
			
		||||
	margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-content {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	height: 100px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-cont-right {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	font-size: 14px;
 | 
			
		||||
	color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-num {
 | 
			
		||||
	font-size: 30px;
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-icon {
 | 
			
		||||
	font-size: 50px;
 | 
			
		||||
	width: 100px;
 | 
			
		||||
	height: 100px;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	line-height: 100px;
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-1 .grid-con-icon {
 | 
			
		||||
	background: rgb(45, 140, 240);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-1 .grid-num {
 | 
			
		||||
	color: rgb(45, 140, 240);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-2 .grid-con-icon {
 | 
			
		||||
	background: rgb(100, 213, 114);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-2 .grid-num {
 | 
			
		||||
	color: rgb(100, 213, 114);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-3 .grid-con-icon {
 | 
			
		||||
	background: rgb(242, 94, 67);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-con-3 .grid-num {
 | 
			
		||||
	color: rgb(242, 94, 67);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	padding-bottom: 20px;
 | 
			
		||||
	border-bottom: 2px solid #ccc;
 | 
			
		||||
	margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info-cont {
 | 
			
		||||
	padding-left: 50px;
 | 
			
		||||
	flex: 1;
 | 
			
		||||
	font-size: 14px;
 | 
			
		||||
	color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info-cont div:first-child {
 | 
			
		||||
	font-size: 30px;
 | 
			
		||||
	color: #222;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info-list {
 | 
			
		||||
	font-size: 14px;
 | 
			
		||||
	color: #999;
 | 
			
		||||
	line-height: 25px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-info-list span {
 | 
			
		||||
	margin-left: 70px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mgb20 {
 | 
			
		||||
	margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.todo-item {
 | 
			
		||||
	font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.todo-item-del {
 | 
			
		||||
	text-decoration: line-through;
 | 
			
		||||
	color: #999;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,10 @@ const submitForm = (formEl: FormInstance | undefined) => {
 | 
			
		||||
            if (!data) return;
 | 
			
		||||
 | 
			
		||||
            console.log("login data", data, data.userInfo);
 | 
			
		||||
 | 
			
		||||
            if (![1, 2].includes(data.userInfo?.roleId)) {
 | 
			
		||||
                ElMessage.error('您所在用户组无权登录当前系统');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            ElMessage.success('登录成功');
 | 
			
		||||
            localStorage.setItem('ms_username', data.userInfo?.username);
 | 
			
		||||
            localStorage.setItem('ms_realname', data.userInfo?.realname);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										191
									
								
								frontend/src/views/shop-order-setting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,191 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
        <manageList :list-func="shopOrderApi.getOrderList" :custom-edit-handle="editHandle"
 | 
			
		||||
            :export-func="shopOrderApi.exportOrderList" edit-permiss="shop-order-setting" />
 | 
			
		||||
 | 
			
		||||
        <!-- 新增 / 编辑弹出框 -->
 | 
			
		||||
        <el-dialog title="管理订单" v-model="visible" style="width: 60%; min-width: 280px;">
 | 
			
		||||
            <el-row>
 | 
			
		||||
                <el-col :span="12">
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单ID</span>
 | 
			
		||||
                        {{ orderDetail.id || "" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单状态</span>
 | 
			
		||||
                        <el-tag effect="plain" round>{{ orderDetail.orderStatus || "" }}</el-tag>
 | 
			
		||||
                        {{ orderDetail.orderStatusCode || "" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">下单用户ID</span>
 | 
			
		||||
                        {{ orderDetail.userId || "" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单价格</span>
 | 
			
		||||
                        {{ orderDetail.orderPrice ? ('¥' + orderDetail.orderPrice) : "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">下单时间</span>
 | 
			
		||||
                        {{ orderDetail.orderDate || "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单取消时间</span>
 | 
			
		||||
                        {{ orderDetail.cancelDate || "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单支付时间</span>
 | 
			
		||||
                        {{ orderDetail.payDate || "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单发货时间</span>
 | 
			
		||||
                        {{ orderDetail.shipDate || "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">订单送达时间</span>
 | 
			
		||||
                        {{ orderDetail.deliverDate || "-" }}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">运单号</span>
 | 
			
		||||
                        <template
 | 
			
		||||
                            v-if="orderDetail.orderStatusCode != 'Processing' && orderDetail.orderStatusCode != 'Shipped'">
 | 
			
		||||
                            {{ orderDetail.expressId || "-" }}
 | 
			
		||||
                        </template>
 | 
			
		||||
                        <el-input v-else v-model="shippingInfo.expressId" placeholder="Please input" />
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p class="line-height">
 | 
			
		||||
                        <span class="row-index">发货备注</span>
 | 
			
		||||
                        <template
 | 
			
		||||
                            v-if="orderDetail.orderStatusCode != 'Processing' && orderDetail.orderStatusCode != 'Shipped'">
 | 
			
		||||
                            {{ orderDetail.comment || "-" }}
 | 
			
		||||
                        </template>
 | 
			
		||||
                        <el-input v-else v-model="shippingInfo.comment" placeholder="Please input" />
 | 
			
		||||
                    </p>
 | 
			
		||||
                </el-col>
 | 
			
		||||
                <el-col :span="12">
 | 
			
		||||
                    <p style="margin-bottom: 20px;">该订单中包含如下商品</p>
 | 
			
		||||
                    <div style="max-height:50vh; overflow-y: scroll;">
 | 
			
		||||
                        <el-card class="box-card" v-for="i in orderItem" :key="i.goodId"
 | 
			
		||||
                            style="--el-card-padding: 10px; margin-bottom: 8px;">
 | 
			
		||||
                            <div style="display: grid; grid-template-columns: 50px 1fr 60px; gap: 15px;">
 | 
			
		||||
                                <img :src="i.good.picUrl" style="width: 60px; height: 60px;" />
 | 
			
		||||
                                <div style="place-self: center left;">
 | 
			
		||||
                                    <p>{{ i.good.goodsName }}</p>
 | 
			
		||||
                                    <p style="color: grey; font-size: 12px;">商品ID: {{ i.goodId }}</p>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div style="place-self: center; font-size: 16px;">{{ i.goodCount }} {{ i.good.unit }}</div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </el-card>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </el-col>
 | 
			
		||||
            </el-row>
 | 
			
		||||
            <!-- 订单状态:PENDING("Pending", "等待确认"), -->
 | 
			
		||||
            <!-- 订单状态:PROCESSING("Processing", "已支付,等待发货中"), -->
 | 
			
		||||
            <!-- 订单状态:SHIPPED("Shipped", "已发货,等待确认收货"), -->
 | 
			
		||||
            <!-- 订单状态:DELIVERED("Delivered", "已送达"), -->
 | 
			
		||||
            <!-- 订单状态:CANCELLED("Cancelled", "已取消"); -->
 | 
			
		||||
            <!-- 该订单已被取消 -->
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <span class="dialog-footer">
 | 
			
		||||
                    <el-button v-if="orderDetail.orderStatusCode == 'Processing'" type="danger"
 | 
			
		||||
                        @click="withdrawOrder">取消发货并退款</el-button>
 | 
			
		||||
                    <el-button
 | 
			
		||||
                        v-if="orderDetail.orderStatusCode == 'Processing' || orderDetail.orderStatusCode == 'Shipped'"
 | 
			
		||||
                        type="primary" @click="saveEdit">保存发货信息</el-button>
 | 
			
		||||
                    <el-button @click="visible = false">关 闭</el-button>
 | 
			
		||||
                </span>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import manageList from '../components/manage-list.vue';
 | 
			
		||||
import * as shopOrderApi from '../api/shop-order';
 | 
			
		||||
import { ref, reactive, onMounted, computed } from 'vue';
 | 
			
		||||
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
 | 
			
		||||
import { Delete, Edit, Search, Plus, Filter, Download } from '@element-plus/icons-vue';
 | 
			
		||||
 | 
			
		||||
const visible: any = ref(false);
 | 
			
		||||
 | 
			
		||||
const orderDetail = ref({} as any);
 | 
			
		||||
const orderItem = ref([] as any);
 | 
			
		||||
 | 
			
		||||
const shippingInfo = ref({} as any); // 发货信息
 | 
			
		||||
 | 
			
		||||
let completeCallback: Function = () => { };
 | 
			
		||||
 | 
			
		||||
const editHandle = async function (tabIndex: number, row: any, refreshFunc: Function) {
 | 
			
		||||
    console.log("tabIndex", tabIndex)
 | 
			
		||||
    console.log("orderDetail", row)
 | 
			
		||||
    orderDetail.value = row // 订单详情
 | 
			
		||||
 | 
			
		||||
    shippingInfo.value.expressId = row.expressId
 | 
			
		||||
    shippingInfo.value.comment = row.comment
 | 
			
		||||
 | 
			
		||||
    completeCallback = refreshFunc
 | 
			
		||||
    visible.value = true
 | 
			
		||||
 | 
			
		||||
    shopOrderApi.getOrderDetail({
 | 
			
		||||
        orderId: row.id
 | 
			
		||||
    }).then(function (data) {
 | 
			
		||||
        let orderGoods = {}
 | 
			
		||||
        data.goods.forEach((good: any) => {
 | 
			
		||||
            orderGoods[good.id] = good
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        orderItem.value = data.orderItem.map((item: any) => {
 | 
			
		||||
            item.good = orderGoods[item.goodId]
 | 
			
		||||
            return item
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        console.log("orderItem", orderItem.value)
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const saveEdit = function () {
 | 
			
		||||
    // 保存发货信息
 | 
			
		||||
    ElMessageBox.confirm('确定要进行发货操作吗?发货后订单将不可撤销。(用户点击收货前仍可以修改发货信息)', '提示', { type: 'warning' })
 | 
			
		||||
        .then(async () => {
 | 
			
		||||
            shopOrderApi.deliverOrder({
 | 
			
		||||
                orderId: orderDetail.value.id,
 | 
			
		||||
                ...shippingInfo.value
 | 
			
		||||
            }).then(function (data) {
 | 
			
		||||
                if (data) { // 如果出错则已经出提示了
 | 
			
		||||
                    ElMessage.success({ message: data })
 | 
			
		||||
                    visible.value = false
 | 
			
		||||
                    completeCallback()
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => { });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const withdrawOrder = function () {
 | 
			
		||||
    // 取消订单
 | 
			
		||||
    ElMessageBox.confirm('确定要取消此订单吗?该操作不可撤销。', '提示', { type: 'warning' })
 | 
			
		||||
        .then(async () => {
 | 
			
		||||
            shopOrderApi.withdrawOrder({
 | 
			
		||||
                orderId: orderDetail.value.id,
 | 
			
		||||
                ...shippingInfo.value
 | 
			
		||||
            }).then(function (data) {
 | 
			
		||||
                if (data) { // 如果出错则已经出提示了
 | 
			
		||||
                    ElMessage.success({ message: data })
 | 
			
		||||
                    visible.value = false
 | 
			
		||||
                    completeCallback()
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => { });
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
.line-height {
 | 
			
		||||
    line-height: 2.7em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.row-index {
 | 
			
		||||
    width: 110px;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,67 +1,63 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div>
 | 
			
		||||
		<el-row :gutter="20">
 | 
			
		||||
			<el-col :span="12">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<template #header>
 | 
			
		||||
						<div class="clearfix">
 | 
			
		||||
							<span>基础信息</span>
 | 
			
		||||
						</div>
 | 
			
		||||
					</template>
 | 
			
		||||
					<div class="info">
 | 
			
		||||
						<div class="info-image" @click="showDialog">
 | 
			
		||||
							<el-avatar :size="100" :src="avatarImg" />
 | 
			
		||||
							<span class="info-edit">
 | 
			
		||||
								<i class="el-icon-lx-camerafill"></i>
 | 
			
		||||
							</span>
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="info-name">{{ name }}</div>
 | 
			
		||||
						<!-- <div class="info-desc">不可能!我的代码怎么可能会有bug!</div> -->
 | 
			
		||||
					</div>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
			<el-col :span="12">
 | 
			
		||||
				<el-card shadow="hover">
 | 
			
		||||
					<template #header>
 | 
			
		||||
						<div class="clearfix">
 | 
			
		||||
							<span>账户编辑</span>
 | 
			
		||||
						</div>
 | 
			
		||||
					</template>
 | 
			
		||||
					<el-form label-width="90px">
 | 
			
		||||
						<el-form-item label="用户名:"> {{ name }} </el-form-item>
 | 
			
		||||
						<el-form-item label="旧密码:">
 | 
			
		||||
							<el-input type="password" v-model="form.old"></el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<el-form-item label="新密码:">
 | 
			
		||||
							<el-input type="password" v-model="form.new"></el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<el-form-item label="确认密码:">
 | 
			
		||||
							<el-input type="password" v-model="form.new1"></el-input>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
						<!-- <el-form-item label="个人简介:">
 | 
			
		||||
							<el-input v-model="form.desc"></el-input>
 | 
			
		||||
						</el-form-item> -->
 | 
			
		||||
						<el-form-item>
 | 
			
		||||
							<el-button type="primary" @click="onSubmit">保存</el-button>
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-form>
 | 
			
		||||
				</el-card>
 | 
			
		||||
			</el-col>
 | 
			
		||||
		</el-row>
 | 
			
		||||
		<el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
 | 
			
		||||
			<vue-cropper ref="cropper" :src="imgSrc" :ready="cropImage" :zoom="cropImage" :cropmove="cropImage"
 | 
			
		||||
				style="width: 100%; height: 400px"></vue-cropper>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-row :gutter="20">
 | 
			
		||||
            <el-col :span="12">
 | 
			
		||||
                <el-card shadow="hover">
 | 
			
		||||
                    <template #header>
 | 
			
		||||
                        <div class="clearfix">
 | 
			
		||||
                            <span>基础信息</span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </template>
 | 
			
		||||
                    <div class="info">
 | 
			
		||||
                        <div class="info-image" @click="showDialog">
 | 
			
		||||
                            <el-avatar :size="100" :src="avatarImg" />
 | 
			
		||||
                            <span class="info-edit">
 | 
			
		||||
                                <i class="el-icon-lx-camerafill"></i>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="info-name">{{ name }}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </el-card>
 | 
			
		||||
            </el-col>
 | 
			
		||||
            <el-col :span="12">
 | 
			
		||||
                <el-card shadow="hover">
 | 
			
		||||
                    <template #header>
 | 
			
		||||
                        <div class="clearfix">
 | 
			
		||||
                            <span>账户编辑</span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </template>
 | 
			
		||||
                    <el-form label-width="90px">
 | 
			
		||||
                        <el-form-item label="用户名:"> {{ name }} </el-form-item>
 | 
			
		||||
                        <el-form-item label="旧密码:">
 | 
			
		||||
                            <el-input type="password" v-model="form.old"></el-input>
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
                        <el-form-item label="新密码:">
 | 
			
		||||
                            <el-input type="password" v-model="form.new"></el-input>
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
                        <el-form-item label="确认密码:">
 | 
			
		||||
                            <el-input type="password" v-model="form.new1"></el-input>
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
                        <el-form-item>
 | 
			
		||||
                            <el-button type="primary" @click="onSubmit">保存</el-button>
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
                    </el-form>
 | 
			
		||||
                </el-card>
 | 
			
		||||
            </el-col>
 | 
			
		||||
        </el-row>
 | 
			
		||||
        <el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
 | 
			
		||||
            <vue-cropper ref="cropper" :src="imgSrc" :ready="cropImage" :zoom="cropImage" :cropmove="cropImage"
 | 
			
		||||
                style="width: 100%; height: 400px"></vue-cropper>
 | 
			
		||||
 | 
			
		||||
			<template #footer>
 | 
			
		||||
				<span class="dialog-footer">
 | 
			
		||||
					<el-button class="crop-demo-btn" type="primary">选择图片
 | 
			
		||||
						<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
 | 
			
		||||
					</el-button>
 | 
			
		||||
					<el-button type="primary" @click="saveAvatar">上传并保存</el-button>
 | 
			
		||||
				</span>
 | 
			
		||||
			</template>
 | 
			
		||||
		</el-dialog>
 | 
			
		||||
	</div>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <span class="dialog-footer">
 | 
			
		||||
                    <el-button class="crop-demo-btn" type="primary">选择图片
 | 
			
		||||
                        <input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
 | 
			
		||||
                    </el-button>
 | 
			
		||||
                    <el-button type="primary" @click="saveAvatar">上传并保存</el-button>
 | 
			
		||||
                </span>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts" name="user">
 | 
			
		||||
@@ -70,65 +66,52 @@ import VueCropper from 'vue-cropperjs';
 | 
			
		||||
import 'cropperjs/dist/cropper.css';
 | 
			
		||||
import avatar from '../assets/img/img.jpg';
 | 
			
		||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
 | 
			
		||||
import send_request from '../utils/send_request';
 | 
			
		||||
import * as userApi from '../api/user';
 | 
			
		||||
 | 
			
		||||
const name = localStorage.getItem('ms_username');
 | 
			
		||||
const user_id = localStorage.getItem('ms_user_id');
 | 
			
		||||
const form = reactive({
 | 
			
		||||
	user_id: user_id,
 | 
			
		||||
	old: '',
 | 
			
		||||
	new: '',
 | 
			
		||||
	new1: '',
 | 
			
		||||
	desc: ''
 | 
			
		||||
    user_id: user_id,
 | 
			
		||||
    old: '',
 | 
			
		||||
    new: '',
 | 
			
		||||
    new1: '',
 | 
			
		||||
    desc: ''
 | 
			
		||||
});
 | 
			
		||||
const onSubmit = async () => {
 | 
			
		||||
	if (form.old == '' || form.new == '' || form.new1 == '') {
 | 
			
		||||
		// 弹窗
 | 
			
		||||
		ElMessageBox.confirm('输入为空,请检查', '提示', {
 | 
			
		||||
			type: 'warning'
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	} else if (form.new != form.new1) {
 | 
			
		||||
		// 弹窗
 | 
			
		||||
		ElMessageBox.confirm('新密码2次输入的不相同', '提示', {
 | 
			
		||||
			type: 'warning'
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	} else if (form.new == form.old) {
 | 
			
		||||
		// 弹窗
 | 
			
		||||
		ElMessageBox.confirm('新、旧密码相同', '提示', {
 | 
			
		||||
			type: 'warning'
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
    if (form.old == '' || form.new == '' || form.new1 == '') {
 | 
			
		||||
        // 弹窗
 | 
			
		||||
        ElMessageBox.confirm('输入为空,请检查', '提示', {
 | 
			
		||||
            type: 'warning'
 | 
			
		||||
        })
 | 
			
		||||
        return
 | 
			
		||||
    } else if (form.new != form.new1) {
 | 
			
		||||
        // 弹窗
 | 
			
		||||
        ElMessageBox.confirm('新密码2次输入的不相同', '提示', {
 | 
			
		||||
            type: 'warning'
 | 
			
		||||
        })
 | 
			
		||||
        return
 | 
			
		||||
    } else if (form.new == form.old) {
 | 
			
		||||
        // 弹窗
 | 
			
		||||
        ElMessageBox.confirm('新、旧密码相同', '提示', {
 | 
			
		||||
            type: 'warning'
 | 
			
		||||
        })
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	ElMessageBox.confirm('确认要修改密码吗?', '提示', {
 | 
			
		||||
		type: 'warning'
 | 
			
		||||
	})
 | 
			
		||||
		.then(async () => {
 | 
			
		||||
			console.log("send_request v1/user/alterPSW")
 | 
			
		||||
 | 
			
		||||
			const loading = ElLoading.service({
 | 
			
		||||
				lock: true,
 | 
			
		||||
				text: '请稍候',
 | 
			
		||||
				background: 'rgba(0, 0, 0, 0.7)',
 | 
			
		||||
			});
 | 
			
		||||
			await send_request('v1/user/alterPSW', "POST", {
 | 
			
		||||
				"userId": form.user_id,
 | 
			
		||||
				"oldPSW": form.old,
 | 
			
		||||
				"newPSW": form.new
 | 
			
		||||
			}, (data: any) => {
 | 
			
		||||
				console.log(data);
 | 
			
		||||
				ElMessage.success('删除成功');
 | 
			
		||||
				// tableData.value.splice(index, 1);
 | 
			
		||||
			})
 | 
			
		||||
			loading.close();
 | 
			
		||||
 | 
			
		||||
		})
 | 
			
		||||
		.catch(() => {
 | 
			
		||||
			ElMessage.success('删除失败');
 | 
			
		||||
		});
 | 
			
		||||
	return;
 | 
			
		||||
    ElMessageBox.confirm('确认要修改密码吗?', '提示', {
 | 
			
		||||
        type: 'warning'
 | 
			
		||||
    }).then(async () => {
 | 
			
		||||
        userApi.updatePwd({
 | 
			
		||||
            oldpwd: form.old,
 | 
			
		||||
            newpwd: form.new,
 | 
			
		||||
        }).then((data) => {
 | 
			
		||||
            data && ElMessage.success(data);
 | 
			
		||||
        })
 | 
			
		||||
    }).catch((err) => {
 | 
			
		||||
        ElMessage.success('删除失败');
 | 
			
		||||
        console.log("err", err)
 | 
			
		||||
    });
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -139,92 +122,92 @@ const dialogVisible = ref(false);
 | 
			
		||||
const cropper: any = ref();
 | 
			
		||||
 | 
			
		||||
const showDialog = () => {
 | 
			
		||||
	dialogVisible.value = true;
 | 
			
		||||
	imgSrc.value = avatarImg.value;
 | 
			
		||||
    dialogVisible.value = true;
 | 
			
		||||
    imgSrc.value = avatarImg.value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const setImage = (e: any) => {
 | 
			
		||||
	const file = e.target.files[0];
 | 
			
		||||
	if (!file.type.includes('image/')) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	const reader = new FileReader();
 | 
			
		||||
	reader.onload = (event: any) => {
 | 
			
		||||
		dialogVisible.value = true;
 | 
			
		||||
		imgSrc.value = event.target.result;
 | 
			
		||||
		cropper.value && cropper.value.replace(event.target.result);
 | 
			
		||||
	};
 | 
			
		||||
	reader.readAsDataURL(file);
 | 
			
		||||
    const file = e.target.files[0];
 | 
			
		||||
    if (!file.type.includes('image/')) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const reader = new FileReader();
 | 
			
		||||
    reader.onload = (event: any) => {
 | 
			
		||||
        dialogVisible.value = true;
 | 
			
		||||
        imgSrc.value = event.target.result;
 | 
			
		||||
        cropper.value && cropper.value.replace(event.target.result);
 | 
			
		||||
    };
 | 
			
		||||
    reader.readAsDataURL(file);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cropImage = () => {
 | 
			
		||||
	cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
 | 
			
		||||
    cropImg.value = cropper.value.getCroppedCanvas().toDataURL();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const saveAvatar = () => {
 | 
			
		||||
	avatarImg.value = cropImg.value;
 | 
			
		||||
	dialogVisible.value = false;
 | 
			
		||||
    avatarImg.value = cropImg.value;
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.info {
 | 
			
		||||
	text-align: center;
 | 
			
		||||
	padding: 35px 0;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    padding: 35px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-image {
 | 
			
		||||
	position: relative;
 | 
			
		||||
	margin: auto;
 | 
			
		||||
	width: 100px;
 | 
			
		||||
	height: 100px;
 | 
			
		||||
	background: #f8f8f8;
 | 
			
		||||
	border: 1px solid #eee;
 | 
			
		||||
	border-radius: 50px;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
    width: 100px;
 | 
			
		||||
    height: 100px;
 | 
			
		||||
    background: #f8f8f8;
 | 
			
		||||
    border: 1px solid #eee;
 | 
			
		||||
    border-radius: 50px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-edit {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background: rgba(0, 0, 0, 0.5);
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	transition: opacity 0.3s ease;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    background: rgba(0, 0, 0, 0.5);
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transition: opacity 0.3s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-edit i {
 | 
			
		||||
	color: #eee;
 | 
			
		||||
	font-size: 25px;
 | 
			
		||||
    color: #eee;
 | 
			
		||||
    font-size: 25px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-image:hover .info-edit {
 | 
			
		||||
	opacity: 1;
 | 
			
		||||
    opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-name {
 | 
			
		||||
	margin: 15px 0 10px;
 | 
			
		||||
	font-size: 24px;
 | 
			
		||||
	font-weight: 500;
 | 
			
		||||
	color: #262626;
 | 
			
		||||
    margin: 15px 0 10px;
 | 
			
		||||
    font-size: 24px;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    color: #262626;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.crop-demo-btn {
 | 
			
		||||
	position: relative;
 | 
			
		||||
    position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.crop-input {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	width: 100px;
 | 
			
		||||
	height: 40px;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	opacity: 0;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    width: 100px;
 | 
			
		||||
    height: 40px;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,13 @@ server
 | 
			
		||||
    listen 80;
 | 
			
		||||
    listen 443 ssl http2;
 | 
			
		||||
 | 
			
		||||
    # 并发限制 限制当前站点最大并发数
 | 
			
		||||
    limit_conn perserver 50;
 | 
			
		||||
    # 单IP限制 限制单个IP访问最大并发数
 | 
			
		||||
    limit_conn perip 10;
 | 
			
		||||
    # 流量限制 限制每个请求的流量上限(单位:KB)
 | 
			
		||||
    limit_rate 8192k;
 | 
			
		||||
 | 
			
		||||
    location / {
 | 
			
		||||
        proxy_pass http://127.0.0.1:5203;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,14 @@ App({
 | 
			
		||||
  },
 | 
			
		||||
  globalData: {
 | 
			
		||||
    // debugMode: true, // 是否展示调试内容
 | 
			
		||||
    baseUrl: true ? // Api 请求域名 不带最后的 /
 | 
			
		||||
      "https://epp-prod.only4.work" :
 | 
			
		||||
      "http://localhost",
 | 
			
		||||
    /**
 | 
			
		||||
     * FIXME 环境配置
 | 
			
		||||
     *
 | 
			
		||||
     * baseUrl
 | 
			
		||||
     * - 线上环境:'https://epp.only4.work'
 | 
			
		||||
     * - 开发环境:'http://localhost'
 | 
			
		||||
     */
 | 
			
		||||
    baseUrl: "https://epp-prod.only4.work", // Api 请求域名 不带最后的 /
 | 
			
		||||
    userInfo: null
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -137,7 +137,7 @@ Page({
 | 
			
		||||
        filterList: filterList,
 | 
			
		||||
        filterActiveName: "全部",
 | 
			
		||||
        orderList: userOrder.orders.map(order => {
 | 
			
		||||
          order.displayDate = order.orderDate.replace("T", " ")
 | 
			
		||||
          order.displayDate = order.orderDate
 | 
			
		||||
          return order
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
@@ -153,7 +153,7 @@ Page({
 | 
			
		||||
      console.log("userOrder", userOrder)
 | 
			
		||||
      this.setData({
 | 
			
		||||
        orderList: userOrder.orders.map(order => {
 | 
			
		||||
          order.displayDate = order.orderDate.replace("T", " ")
 | 
			
		||||
          order.displayDate = order.orderDate
 | 
			
		||||
          return order
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
 
 | 
			
		||||
@@ -259,7 +259,7 @@ Page({
 | 
			
		||||
      this.setData({
 | 
			
		||||
        order: orderDetail.order,
 | 
			
		||||
        orderGoodList: orderGoodList,
 | 
			
		||||
        orderTime: orderDetail.order.orderDate.replace("T", " "),
 | 
			
		||||
        orderTime: orderDetail.order.orderDate,
 | 
			
		||||
        orderStatusCode: orderStatusCode,
 | 
			
		||||
        orderPrice: orderPrice,
 | 
			
		||||
      })
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
  "projectname": "weixin-miniprogram",
 | 
			
		||||
  "setting": {
 | 
			
		||||
    "compileHotReLoad": true,
 | 
			
		||||
    "urlCheck": true,
 | 
			
		||||
    "urlCheck": false,
 | 
			
		||||
    "bigPackageSizeSupport": true
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										167
									
								
								论文中数据字典.md
									
									
									
									
									
								
							
							
						
						@@ -1,26 +1,21 @@
 | 
			
		||||
> 使用 phpMyAdmin 导出,如果有修改,可以同步修改到论文正文
 | 
			
		||||
 | 
			
		||||
## apply1
 | 
			
		||||
## access_log
 | 
			
		||||
 | 
			
		||||
| 字段        | 类型        | 空   | 默认   | 注释                         |
 | 
			
		||||
| :---------- | :---------- | :--- | :----- | :--------------------------- |
 | 
			
		||||
| id *(主键)* | int         | 否   |        |                              |
 | 
			
		||||
| stu_id      | int         | 是   | *NULL* | 用户id                       |
 | 
			
		||||
| issue       | varchar(50) | 是   | *NULL* | 申请事由                     |
 | 
			
		||||
| transport   | varchar(20) | 是   | *NULL* | 出行方式                     |
 | 
			
		||||
| place       | varchar(50) | 是   | *NULL* | 目的地                       |
 | 
			
		||||
| start_time  | datetime    | 是   | *NULL* | 开始时间                     |
 | 
			
		||||
| end_time    | datetime    | 是   | *NULL* | 结束时间                     |
 | 
			
		||||
| state       | int         | 是   | 0      | 状态(0:审批中,1:通过,2:驳回) |
 | 
			
		||||
| reason      | varchar(20) | 是   | *NULL* | 驳回原因                     |
 | 
			
		||||
表注释: *人员进出记录表*
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
| 字段           | 类型              | 空   | 默认              | 注释                 |
 | 
			
		||||
| :------------- | :---------------- | :--- | :---------------- | :------------------- |
 | 
			
		||||
| id             | bigint            | 否   |                   | 雪花id               |
 | 
			
		||||
| time           | datetime          | 否   | CURRENT_TIMESTAMP | 进出时间             |
 | 
			
		||||
| user_id        | int               | 否   |                   | 用户id               |
 | 
			
		||||
| user_real_name | varchar(255)      | 是   | *NULL*            | 用户真实姓名         |
 | 
			
		||||
| gate_id        | bigint            | 否   |                   | 大门id               |
 | 
			
		||||
| type           | enum('IN', 'OUT') | 是   | *NULL*            | 类型(进门 OR 出门) |
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 10   | A        | 否   |      |
 | 
			
		||||
没有已定义的索引!
 | 
			
		||||
 | 
			
		||||
## community_gate
 | 
			
		||||
## gate
 | 
			
		||||
 | 
			
		||||
表注释: *社区大门*
 | 
			
		||||
 | 
			
		||||
@@ -32,38 +27,6 @@
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 0    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## count1
 | 
			
		||||
 | 
			
		||||
| 字段          | 类型     | 空   | 默认   | 注释     |
 | 
			
		||||
| :------------ | :------- | :--- | :----- | :------- |
 | 
			
		||||
| date *(主键)* | date     | 否   |        | 日期     |
 | 
			
		||||
| time          | datetime | 是   | *NULL* | 时间     |
 | 
			
		||||
| in_num        | int      | 是   | *NULL* | 入校人数 |
 | 
			
		||||
| out_num       | int      | 是   | *NULL* | 出校人数 |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | date | 0    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## feedback1
 | 
			
		||||
 | 
			
		||||
| 字段        | 类型         | 空   | 默认   | 注释       |
 | 
			
		||||
| :---------- | :----------- | :--- | :----- | :--------- |
 | 
			
		||||
| id *(主键)* | int          | 否   |        |            |
 | 
			
		||||
| title       | varchar(255) | 是   | *NULL* | 反馈标题   |
 | 
			
		||||
| content     | longtext     | 是   | *NULL* | 反馈内容   |
 | 
			
		||||
| time        | datetime     | 是   | *NULL* | 反馈时间   |
 | 
			
		||||
| user_id     | int          | 是   | *NULL* | 反馈用户id |
 | 
			
		||||
| reply       | varchar(255) | 是   | *NULL* | 回复       |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 5    | A        | 否   |      |
 | 
			
		||||
@@ -94,10 +57,10 @@
 | 
			
		||||
 | 
			
		||||
| 键名        | 类型  | 唯一 | 紧凑 | 字段        | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :---------- | :---- | :--- | :--- | :---------- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY     | BTREE | 是   | 否   | id          | 87   | A        | 否   |      |
 | 
			
		||||
| PRIMARY     | BTREE | 是   | 否   | id          | 89   | A        | 否   |      |
 | 
			
		||||
| category_id | BTREE | 否   | 否   | category_id | 8    | A        | 是   |      |
 | 
			
		||||
| brand_id    | BTREE | 否   | 否   | brand       | 67   | A        | 是   |      |
 | 
			
		||||
| sort_order  | BTREE | 否   | 否   | sort_order  | 25   | A        | 是   |      |
 | 
			
		||||
| brand_id    | BTREE | 否   | 否   | brand       | 69   | A        | 是   |      |
 | 
			
		||||
| sort_order  | BTREE | 否   | 否   | sort_order  | 27   | A        | 是   |      |
 | 
			
		||||
 | 
			
		||||
## goods_category
 | 
			
		||||
 | 
			
		||||
@@ -111,22 +74,7 @@
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 7    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## notice1
 | 
			
		||||
 | 
			
		||||
| 字段        | 类型         | 空   | 默认   | 注释 |
 | 
			
		||||
| :---------- | :----------- | :--- | :----- | :--- |
 | 
			
		||||
| id *(主键)* | int          | 否   |        |      |
 | 
			
		||||
| title       | varchar(255) | 是   | *NULL* | 标题 |
 | 
			
		||||
| content     | longtext     | 是   | *NULL* | 内容 |
 | 
			
		||||
| time        | date         | 是   | *NULL* | 时间 |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 5    | A        | 否   |      |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 8    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## order
 | 
			
		||||
 | 
			
		||||
@@ -138,13 +86,18 @@
 | 
			
		||||
| order_status | enum('Pending', 'Processing', 'Shipped', 'Delivered', 'Cancelled') | 否   |        | 订单状态     |
 | 
			
		||||
| order_price  | decimal(10,2)                                                | 否   |        | 订单总金额   |
 | 
			
		||||
| pay_date     | datetime                                                     | 是   | *NULL* | 订单支付时间 |
 | 
			
		||||
| cancel_date  | datetime                                                     | 是   | *NULL* | 订单取消时间 |
 | 
			
		||||
| ship_date    | datetime                                                     | 是   | *NULL* | 订单发货时间 |
 | 
			
		||||
| deliver_date | datetime                                                     | 是   | *NULL* | 订单送达时间 |
 | 
			
		||||
| express_id   | varchar(500)                                                 | 是   | *NULL* | 快递单号     |
 | 
			
		||||
| comment      | text                                                         | 是   | *NULL* | 发货备注     |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段    | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :------ | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id      | 4    | A        | 否   |      |
 | 
			
		||||
| id      | BTREE | 是   | 否   | id      | 4    | A        | 否   |      |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id      | 15   | A        | 否   |      |
 | 
			
		||||
| id      | BTREE | 是   | 否   | id      | 15   | A        | 否   |      |
 | 
			
		||||
| user_id | BTREE | 否   | 否   | user_id | 1    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## order_detail
 | 
			
		||||
@@ -161,9 +114,9 @@
 | 
			
		||||
 | 
			
		||||
| 键名     | 类型  | 唯一 | 紧凑 | 字段     | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------- | :---- | :--- | :--- | :------- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY  | BTREE | 是   | 否   | id       | 10   | A        | 否   |      |
 | 
			
		||||
| order_id | BTREE | 否   | 否   | order_id | 4    | A        | 否   |      |
 | 
			
		||||
| good_id  | BTREE | 否   | 否   | good_id  | 2    | A        | 否   |      |
 | 
			
		||||
| PRIMARY  | BTREE | 是   | 否   | id       | 21   | A        | 否   |      |
 | 
			
		||||
| order_id | BTREE | 否   | 否   | order_id | 15   | A        | 否   |      |
 | 
			
		||||
| good_id  | BTREE | 否   | 否   | good_id  | 9    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## report
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +133,20 @@
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 1    | A        | 否   |      |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 12   | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## role
 | 
			
		||||
 | 
			
		||||
| 字段        | 类型         | 空   | 默认 | 注释     |
 | 
			
		||||
| :---------- | :----------- | :--- | :--- | :------- |
 | 
			
		||||
| id *(主键)* | int          | 否   |      | role_id  |
 | 
			
		||||
| role_name   | varchar(255) | 否   |      | roleName |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 6    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## setting
 | 
			
		||||
 | 
			
		||||
@@ -198,42 +164,27 @@
 | 
			
		||||
 | 
			
		||||
## user
 | 
			
		||||
 | 
			
		||||
| 字段            | 类型         | 空   | 默认   | 注释                                                         |
 | 
			
		||||
| :-------------- | :----------- | :--- | :----- | :----------------------------------------------------------- |
 | 
			
		||||
| id *(主键)*     | int          | 否   |        |                                                              |
 | 
			
		||||
| username        | varchar(20)  | 否   |        | 用户名                                                       |
 | 
			
		||||
| password        | varchar(255) | 否   |        | 密码                                                         |
 | 
			
		||||
| realname        | varchar(20)  | 是   | *NULL* | 真实姓名                                                     |
 | 
			
		||||
| id_number       | varchar(18)  | 是   | *NULL* | 身份证号                                                     |
 | 
			
		||||
| phone_number    | varchar(11)  | 是   | *NULL* | 手机号                                                       |
 | 
			
		||||
| role            | int          | 否   |        | 角色 (0-超级管理员 1-工作人员 2-社区居民_房主 3-社区居民_家庭成员 4-社区居民_租客 5-访客) |
 | 
			
		||||
| building_id     | varchar(255) | 是   | *NULL* | 门栋号+单元号                                                |
 | 
			
		||||
| doorplate       | varchar(255) | 是   | *NULL* | 门牌号                                                       |
 | 
			
		||||
| permission      | int          | 否   | 0      | 进出权限 (0-无 1-继承(普通居民) 2-永久 3-限时)               |
 | 
			
		||||
| permission_time | datetime     | 是   | *NULL* | 进出权限失效时间                                             |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 1    | A        | 否   |      |
 | 
			
		||||
 | 
			
		||||
## visitor1
 | 
			
		||||
 | 
			
		||||
| 字段        | 类型         | 空   | 默认   | 注释                                |
 | 
			
		||||
| :---------- | :----------- | :--- | :----- | :---------------------------------- |
 | 
			
		||||
| id *(主键)* | int          | 否   |        |                                     |
 | 
			
		||||
| time        | datetime     | 是   | *NULL* | 预约时间                            |
 | 
			
		||||
| phone       | varchar(20)  | 是   | *NULL* | 预约用户id                          |
 | 
			
		||||
| issue       | varchar(255) | 是   | *NULL* | 预约事由                            |
 | 
			
		||||
| meet_name   | varchar(20)  | 是   | *NULL* | 会见人姓名                          |
 | 
			
		||||
| create_time | datetime     | 是   | *NULL* | 创建时间                            |
 | 
			
		||||
| state       | int          | 是   | 0      | 状态(0:审批中,1:成功,2:驳回) |
 | 
			
		||||
| 字段            | 类型         | 空   | 默认   | 注释                                           |
 | 
			
		||||
| :-------------- | :----------- | :--- | :----- | :--------------------------------------------- |
 | 
			
		||||
| id *(主键)*     | int          | 否   |        |                                                |
 | 
			
		||||
| username        | varchar(20)  | 否   |        | 用户名                                         |
 | 
			
		||||
| password        | varchar(255) | 否   |        | 密码                                           |
 | 
			
		||||
| realname        | varchar(20)  | 是   | *NULL* | 真实姓名                                       |
 | 
			
		||||
| id_number       | varchar(18)  | 是   | *NULL* | 身份证号                                       |
 | 
			
		||||
| phone_number    | varchar(20)  | 是   | *NULL* | 手机号                                         |
 | 
			
		||||
| role_id         | int          | 否   |        | 角色id                                         |
 | 
			
		||||
| building_id     | varchar(255) | 是   | *NULL* | 门栋号+单元号                                  |
 | 
			
		||||
| doorplate       | varchar(255) | 是   | *NULL* | 门牌号                                         |
 | 
			
		||||
| permission      | varchar(20)  | 否   | 0      | 进出权限 (0-无 1-继承(普通居民) 2-永久 3-限时) |
 | 
			
		||||
| permission_time | datetime     | 是   | *NULL* | 进出权限失效时间                               |
 | 
			
		||||
| wx_code         | varchar(255) | 是   | *NULL* | 微信登录授权码                                 |
 | 
			
		||||
 | 
			
		||||
### 索引
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 键名    | 类型  | 唯一 | 紧凑 | 字段 | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------ | :---- | :--- | :--- | :--- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY | BTREE | 是   | 否   | id   | 1    | A        | 否   |      |
 | 
			
		||||
| 键名     | 类型  | 唯一 | 紧凑 | 字段     | 基数 | 排序规则 | 空   | 注释 |
 | 
			
		||||
| :------- | :---- | :--- | :--- | :------- | :--- | :------- | :--- | :--- |
 | 
			
		||||
| PRIMARY  | BTREE | 是   | 否   | id       | 1    | A        | 否   |      |
 | 
			
		||||
| username | BTREE | 是   | 否   | username | 1    | A        | 否   |      |
 | 
			
		||||
| wx_code  | BTREE | 是   | 否   | wx_code  | 1    | A        | 是   |      |
 | 
			
		||||