Compare commits

..

No commits in common. 'main' and 'dev' have entirely different histories.
main ... dev

@ -1,83 +1,2 @@
# Guangzhou Smart Tourism Project (广州智游)
## 项目简介
广州智游是一个面向城市文旅场景的智慧旅游综合平台,包含三个子系统:
1. **Guangzhou Smart Tourism Service**:后端服务系统,提供统一的业务接口、数据处理、权限校验、推荐服务等核心能力。
2. **Guangzhou-Smart-Tourism-Admin-Console**:运营后台管理系统,用于景区内容管理、商户管理、订单统计、活动发布、用户管理等功能。
3. **Guangzhou-Smart-Tourism-Mobile-App**:移动端客户端,为游客提供景区信息查询、路线规划、智能导览、在线购票、活动浏览等便捷服务。
项目采用前后端分离架构,通过统一 API 网关和微服务化设计,使系统具备高扩展性、高性能及良好的用户体验。
---
## 系统结构
```
Guangzhou Smart Tourism
├── Guangzhou Smart Tourism Service # 后端服务
├── Guangzhou-Smart-Tourism-Admin-Console # 管理后台Web
└── Guangzhou-Smart-Tourism-Mobile-App # 移动端App
```
---
## 技术栈
### 1. Guangzhou Smart Tourism Service后端
* Spring Boot
* MyBatis-Plus
* MySQL
* Redis
* JWT/Token
### 2. Guangzhou-Smart-Tourism-Admin-Console后台管理
* Vue3
* Vite
* Element Plus
* Axios
### 3. Guangzhou-Smart-Tourism-Mobile-App移动端
* Uni-app
* H5 + App 多端适配
* 基于后端 RESTful API
---
## 环境与配置
## 系统要求
* JDK 17+(后端)
* Node.js 18+(前端)
* MySQL 8.0+
* Redis 6.0+
* Maven 3.8+
## 部署说明
系统采用单体部署方式,适用于开发环境与中小规模生产环境。
### 部署流程
1. **后端服务部署**
* 使用 `Maven` 进行打包生成可执行 `jar` 文件。
* 使用 `Java -jar` 方式运行后端服务。
* 需提前准备 MySQL 与 Redis并在配置文件中完成连接参数配置。
2. **后台管理系统部署**
* 使用 `npm install` 安装依赖。
* 使用 `npm run dev` 进入开发模式运行后台管理系统。
3. **移动端部署**
* 若使用 H5 模式,可直接构建并通过 `vite preview` 或其他本地静态资源服务运行。
* 若为 AppAndroid通过 HBuilderX 打包生成 APK 并安装使用,无需服务器部署静态资源。
# Guangzhou_Smart_Travel

1
doc

@ -0,0 +1 @@
undefined

Binary file not shown.

Binary file not shown.

@ -0,0 +1 @@
undefined

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

@ -0,0 +1 @@
undefined

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 KiB

1
src

@ -0,0 +1 @@
undefined

@ -1,33 +0,0 @@
.cursor
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

@ -1 +0,0 @@
# Guangzhou-Smart-Tourism-Service

@ -1,175 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>SpringBootTemplate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootModel</name>
<description>SpringBootModel</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.2</spring-boot.version>
</properties>
<dependencies>
<!-- Spring Boot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mysql-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version> <!-- 推荐最新版本 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.18</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<!-- 阿里云OSS -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<!-- mybatis-plus jsqlparser -->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- OpenAI Java SDK -->
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>3.5.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.SpringBootModelApplication</mainClass>
<jvmArguments>
--add-opens java.base/java.lang.invoke=ALL-UNNAMED
</jvmArguments>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -1,13 +0,0 @@
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootModelApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootModelApplication.class, args);
}
}

@ -1,9 +0,0 @@
package com.example.common.constant;
public class JwtClaimsConstant {
public static final String ID = "id";
}

@ -1,45 +0,0 @@
package com.example.common.constant;
/**
*
*/
public class MessageConstant {
// 通用异常
public static final String SYSTEM_ERROR = "系统错误";
public static final String UNKNOWN_ERROR = "未知错误";
public static final String PARAMS_ERROR = "参数错误";
public static final String DATA_NOT_FOUND = "数据不存在";
public static final String OPERATION_FAILED = "操作失败";
public static final String DELETE_FAILED = "删除失败";
public static final String UPDATE_FAILED = "更新失败";
public static final String SAVE_FAILED = "保存失败";
public static final String EMAIL_NOT_FOUND = "邮箱不存在";
public static final String VERIFY_CODE_ERROR = "验证码错误";
// 用户相关异常
public static final String PASSWORD_ERROR = "密码错误";
public static final String ACCOUNT_NOT_FOUND = "账号不存在";
public static final String ACCOUNT_LOCKED = "账号被锁定";
public static final String USER_NOT_LOGIN = "用户未登录";
public static final String LOGIN_FAILED = "登录失败";
public static final String ALREADY_EXIST = "账号已存在";
public static final String PHONE_ALREADY_EXISTS = "手机号已存在";
public static final String PASSWORD_EDIT_FAILED = "密码修改失败";
public static final String USERNAME_EXISTS = "用户名已存在";
// 文件相关异常
public static final String UPLOAD_FAILED = "文件上传失败";
public static final String FILE_TYPE_ERROR = "文件类型错误";
public static final String FILE_SIZE_ERROR = "文件大小超限";
// 权限相关异常
public static final String NO_PERMISSION = "没有权限";
public static final String TOKEN_INVALID = "令牌无效";
public static final String TOKEN_EXPIRED = "令牌已过期";
// 业务操作异常
public static final String OPERATION_NOT_ALLOWED = "不允许的操作";
public static final String STATUS_ERROR = "状态错误";
public static final String DATA_CONFLICT = "数据冲突";
public static final String VERIFY_CODE_EXPIRED = "验证码已过期";
public static final String EMAIL_EXISTS = "邮箱已存在";
}

@ -1,42 +0,0 @@
package com.example.common.constant;
public class SystemConstants {
public static final String TRAVEL_SYSTEM_PROMPT = """
广AI使广
广
-
-
- 宿
- 线
-
-
-
广
广
1. 广
2.
3. 宿
4.
5. 广
6.
广使
md
200
-
-
- 广
-
-
""";
}

@ -1,20 +0,0 @@
package com.example.common.context;
// ThreadLocal工具类
public class BaseContext {
//提供ThreadLocal对象
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
//根据键获取值
public static void setCurrentId(int id) {
threadLocal.set(id);
}
//存储键值对
public static Integer getCurrentId() {
return threadLocal.get();
}
//清除ThreadLocal 防止内存泄漏
public static void removeCurrentId() {
threadLocal.remove();
}
}

@ -1,44 +0,0 @@
package com.example.common.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum CollectionType implements IEnum<String> {
ATTRACTION("attraction", "景点"),
HOTEL("hotel", "酒店"),
FOOD("food", "美食");
private final String value;
private final String desc;
/**
* 使value
*/
@JsonValue
@Override
public String getValue() {
return value;
}
/**
* value
*/
@JsonCreator
public static CollectionType fromValue(String value) {
if (value == null || value.trim().isEmpty()) {
return null;
}
for (CollectionType type : CollectionType.values()) {
if (type.value.equalsIgnoreCase(value.trim())) {
return type;
}
}
throw new IllegalArgumentException("无效的收藏类型: " + value + "。可用的类型为: attraction, hotel, food");
}
}

@ -1,15 +0,0 @@
package com.example.common.exception;
/**
*
*/
public class BaseException extends RuntimeException {
public BaseException() {
}
public BaseException(String msg) {
super(msg);
}
}

@ -1,52 +0,0 @@
package com.example.common.json;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
*
* :jacksonJavajsonjsonJava
* JSONJava [JSONJava]
* JavaJSON [JavaJSON]
*/
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}

@ -1,17 +0,0 @@
package com.example.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "sky.alioss") //配置属性类读取配置文件配置项封装成java对象 修改一sky.alioss配置属性
@Data
public class AliOssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}

@ -1,25 +0,0 @@
package com.example.common.properties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Jwt
*/
@Component
@ConfigurationProperties(prefix = "template.jwt")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JwtProperties {
private String secretKey;
private long ttl;
private String tokenName;
}

@ -1,37 +0,0 @@
package com.example.common.result;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
*
* @param <T>
*/
@Data //自动生成getter/setter/equals/hashCode/toString方法
@AllArgsConstructor //自动生成全参数构造方法
@NoArgsConstructor //自动生成无参构造方法
@ApiModel(description = "分页结果")
@Builder
public class PageResult<T> {
@ApiModelProperty("当前页码")
private long pageNum;
@ApiModelProperty("每页大小")
private long pageSize;
@ApiModelProperty("总记录数")
private long total;
@ApiModelProperty("总页数")
private long totalPages;
@ApiModelProperty("数据列表")
private List<T> records;
}

@ -1,45 +0,0 @@
package com.example.common.result;
import lombok.Data;
import java.io.Serializable;
/**
*
* @param <T>
*/
@Data
public class Result<T> implements Serializable {
private Integer code; //编码,200成功,500失败
private String msg; //错误信息
private T data; //数据
public static <T> Result<T> success() {
Result<T> result = new Result<T>();
result.code = 200;
return result;
}
public static <T> Result<T> success(T object) {
Result<T> result = new Result<T>();
result.data = object;
result.code = 200;
return result;
}
public static <T> Result<T> error(String msg) {
Result result = new Result();
result.msg = msg;
result.code = 500;
return result;
}
public static <T> Result<T> error(Integer code ,String msg) {
Result result = new Result();
result.msg = msg;
result.code = code;
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save