Compare commits
No commits in common. "3c04019af4f29deff170ec5c77a74c88e8f90692" and "e230317fe9b42f756d4abdb0b33bc54bb42fbb57" have entirely different histories.
3c04019af4
...
e230317fe9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
target/
|
||||
uploads/
|
||||
201
LICENSE
201
LICENSE
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
36
README.en.md
36
README.en.md
@ -1,36 +0,0 @@
|
||||
# petstore-backend
|
||||
|
||||
#### Description
|
||||
宠伴生活馆
|
||||
|
||||
#### Software Architecture
|
||||
Software architecture description
|
||||
|
||||
#### Installation
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Instructions
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Contribution
|
||||
|
||||
1. Fork the repository
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit your code
|
||||
4. Create Pull Request
|
||||
|
||||
|
||||
#### Gitee Feature
|
||||
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
35
README.md
35
README.md
@ -1,37 +1,2 @@
|
||||
# petstore-backend
|
||||
|
||||
#### 介绍
|
||||
宠伴生活馆
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
|
||||
|
||||
#### 安装教程
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 参与贡献
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
|
||||
|
||||
#### 特技
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
|
||||
96
pom.xml
96
pom.xml
@ -1,96 +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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.petstore</groupId>
|
||||
<artifactId>petstore-backend</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>petstore-backend</name>
|
||||
<description>宠伴生活馆 后端服务</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.44</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<fork>true</fork>
|
||||
<compilerArgs>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
|
||||
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.44</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -1,30 +0,0 @@
|
||||
package com.petstore;
|
||||
|
||||
import com.petstore.service.ServiceTypeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
@SpringBootApplication
|
||||
@RequiredArgsConstructor
|
||||
public class PetstoreApplication {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(">>> working dir: " + System.getProperty("user.dir"));
|
||||
SpringApplication.run(PetstoreApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandLineRunner initRunner(ServiceTypeService serviceTypeService, JdbcTemplate jdbc) {
|
||||
return args -> {
|
||||
serviceTypeService.initDefaults();
|
||||
// appointment_id 改为允许 NULL(支持不挂预约直接填报告)
|
||||
jdbc.execute("ALTER TABLE t_report MODIFY COLUMN appointment_id BIGINT NULL");
|
||||
// 修复旧图片URL:/2026/xxx → /api/upload/image/2026/xxx
|
||||
jdbc.execute("UPDATE t_report SET before_photo = REPLACE(before_photo, 'http://localhost:8080/2026/', '/api/upload/image/2026/') WHERE before_photo LIKE 'http://localhost:8080/2026/%'");
|
||||
jdbc.execute("UPDATE t_report SET after_photo = REPLACE(after_photo, 'http://localhost:8080/2026/', '/api/upload/image/2026/') WHERE after_photo LIKE 'http://localhost:8080/2026/%'");
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
package com.petstore.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package com.petstore.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Value("${upload.path:uploads}")
|
||||
private String uploadPath;
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
// 硬编码绝对路径,确保能找到文件
|
||||
String uploadDir = "/Users/wac/Desktop/www/_src/petstore/backend/uploads/";
|
||||
System.out.println(">>> WebConfig uploadDir: " + uploadDir);
|
||||
System.out.println(">>> /2026 exists: " + new File(uploadDir + "2026/04/01/").exists());
|
||||
registry.addResourceHandler("/uploads/**")
|
||||
.addResourceLocations("file:" + uploadDir);
|
||||
registry.addResourceHandler("/2026/**")
|
||||
.addResourceLocations("file:" + uploadDir);
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package com.petstore.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class WechatConfig {
|
||||
// TODO: 替换为实际的微信开放平台 AppID 和 AppSecret
|
||||
@Value("${wechat.appid:YOUR_APPID}")
|
||||
private String appid;
|
||||
|
||||
@Value("${wechat.appsecret:YOUR_APPSECRET}")
|
||||
private String appsecret;
|
||||
|
||||
@Value("${wechat.redirect_uri:http://localhost:8080/api/wechat/callback}")
|
||||
private String redirectUri;
|
||||
|
||||
public String getAppid() { return appid; }
|
||||
public String getAppsecret() { return appsecret; }
|
||||
public String getRedirectUri() { return redirectUri; }
|
||||
|
||||
/**
|
||||
* 获取微信授权跳转地址
|
||||
*/
|
||||
public String getAuthorizeUrl() {
|
||||
return "https://open.weixin.qq.com/connect/qrconnect" +
|
||||
"?appid=" + appid +
|
||||
"&redirect_uri=" + redirectUri +
|
||||
"&response_type=code" +
|
||||
"&scope=snsapi_login" +
|
||||
"&state=petstore#wechat_redirect";
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.entity.Appointment;
|
||||
import com.petstore.service.AppointmentService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/appointment")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class AppointmentController {
|
||||
private final AppointmentService appointmentService;
|
||||
|
||||
/** 获取预约列表(员工查自己/老板查全店) */
|
||||
@GetMapping("/list")
|
||||
public Map<String, Object> list(
|
||||
@RequestParam(required = false) Long userId,
|
||||
@RequestParam(required = false) Long storeId,
|
||||
@RequestParam(required = false) String status) {
|
||||
|
||||
List<Appointment> appointments;
|
||||
if (storeId != null) {
|
||||
appointments = (status != null && !status.isEmpty())
|
||||
? appointmentService.getByStoreIdAndStatus(storeId, status)
|
||||
: appointmentService.getByStoreId(storeId);
|
||||
} else if (userId != null) {
|
||||
appointments = (status != null && !status.isEmpty())
|
||||
? appointmentService.getByUserIdAndStatus(userId, status)
|
||||
: appointmentService.getByUserId(userId);
|
||||
} else {
|
||||
return Map.of("code", 400, "message", "userId或storeId必填");
|
||||
}
|
||||
|
||||
return Map.of("code", 200, "data", appointments);
|
||||
}
|
||||
|
||||
/** 创建预约 */
|
||||
@PostMapping("/create")
|
||||
public Map<String, Object> create(@RequestBody Map<String, Object> params) {
|
||||
Appointment appointment = new Appointment();
|
||||
appointment.setPetName(params.get("petName").toString());
|
||||
appointment.setPetType(params.get("petType").toString());
|
||||
appointment.setServiceType(params.get("serviceType").toString());
|
||||
|
||||
String timeStr = params.get("appointmentTime").toString();
|
||||
appointment.setAppointmentTime(java.time.LocalDateTime.parse(timeStr));
|
||||
|
||||
appointment.setStoreId(Long.valueOf(params.get("storeId").toString()));
|
||||
appointment.setUserId(Long.valueOf(params.get("userId").toString()));
|
||||
appointment.setStatus("new");
|
||||
|
||||
if (params.containsKey("remark") && params.get("remark") != null) {
|
||||
appointment.setRemark(params.get("remark").toString());
|
||||
}
|
||||
|
||||
Appointment created = appointmentService.create(appointment);
|
||||
return Map.of("code", 200, "message", "创建成功", "data", created);
|
||||
}
|
||||
|
||||
/** 开始服务:状态变进行中 + 指定技师 */
|
||||
@PostMapping("/start")
|
||||
public Map<String, Object> start(@RequestBody Map<String, Object> params) {
|
||||
Long appointmentId = Long.valueOf(params.get("appointmentId").toString());
|
||||
Long staffUserId = Long.valueOf(params.get("staffUserId").toString());
|
||||
Appointment updated = appointmentService.startService(appointmentId, staffUserId);
|
||||
if (updated != null) {
|
||||
return Map.of("code", 200, "message", "已开始服务", "data", updated);
|
||||
}
|
||||
return Map.of("code", 404, "message", "预约不存在");
|
||||
}
|
||||
|
||||
/** 更新预约状态 */
|
||||
@PutMapping("/status")
|
||||
public Map<String, Object> updateStatus(@RequestParam Long id, @RequestParam String status) {
|
||||
Appointment updated = appointmentService.updateStatus(id, status);
|
||||
if (updated != null) {
|
||||
return Map.of("code", 200, "message", "更新成功", "data", updated);
|
||||
}
|
||||
return Map.of("code", 404, "message", "预约不存在");
|
||||
}
|
||||
}
|
||||
@ -1,114 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/upload")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class FileController {
|
||||
|
||||
@Value("${upload.path:uploads/}")
|
||||
private String uploadPath;
|
||||
|
||||
@GetMapping("/image/**")
|
||||
public ResponseEntity<Resource> getImage(HttpServletRequest request) throws IOException {
|
||||
String path = request.getRequestURI().replace("/api/upload/image", "");
|
||||
String basePath = uploadPath.endsWith("/") ? uploadPath : uploadPath + "/";
|
||||
File file = new File(basePath + path);
|
||||
if (!file.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
String contentType = Files.probeContentType(file.toPath());
|
||||
if (contentType == null) contentType = "image/jpeg";
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.body(new FileSystemResource(file));
|
||||
}
|
||||
|
||||
// 兼容旧路径:/2026/04/01/xxx.jpg
|
||||
@GetMapping("/legacy/**")
|
||||
public ResponseEntity<Resource> getLegacyImage(HttpServletRequest request) throws IOException {
|
||||
String path = request.getRequestURI().replace("/api/upload/legacy", "");
|
||||
String basePath = uploadPath.endsWith("/") ? uploadPath : uploadPath + "/";
|
||||
File file = new File(basePath + path);
|
||||
if (!file.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
String contentType = Files.probeContentType(file.toPath());
|
||||
if (contentType == null) contentType = "image/jpeg";
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.body(new FileSystemResource(file));
|
||||
}
|
||||
|
||||
@PostMapping("/image")
|
||||
public Map<String, Object> uploadImage(@RequestParam("file") MultipartFile file) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (file.isEmpty()) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "文件为空");
|
||||
return result;
|
||||
}
|
||||
|
||||
String contentType = file.getContentType();
|
||||
if (contentType == null || !contentType.startsWith("image/")) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "只能上传图片");
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建上传目录
|
||||
String datePath = LocalDate.now().toString().replace("-", "/");
|
||||
String dirPath = uploadPath.endsWith("/") ? uploadPath + datePath : uploadPath + "/" + datePath;
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists()) dir.mkdirs();
|
||||
|
||||
// 生成文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String ext = "";
|
||||
if (originalFilename != null && originalFilename.contains(".")) {
|
||||
ext = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
}
|
||||
String filename = UUID.randomUUID().toString().replace("-", "") + ext;
|
||||
|
||||
// 保存文件
|
||||
Path filePath = Paths.get(dirPath, filename);
|
||||
Files.write(filePath, file.getBytes());
|
||||
|
||||
// 返回访问URL(/api/upload/image/ + 日期路径 + 文件名)
|
||||
String url = "/api/upload/image/" + datePath + "/" + filename;
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "上传成功");
|
||||
result.put("data", Map.of("url", url));
|
||||
return result;
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
result.put("code", 500);
|
||||
result.put("message", "上传失败");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.entity.Report;
|
||||
import com.petstore.entity.Store;
|
||||
import com.petstore.service.ReportService;
|
||||
import com.petstore.service.StoreService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/report")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class ReportController {
|
||||
private final ReportService reportService;
|
||||
private final StoreService storeService;
|
||||
|
||||
@Value("${app.base-url:http://localhost:8080}")
|
||||
private String baseUrl;
|
||||
|
||||
private String fullUrl(String path) {
|
||||
if (path == null || path.isEmpty()) return path;
|
||||
if (path.startsWith("http")) return path;
|
||||
return baseUrl + path;
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Map<String, Object> create(@RequestBody Report report) {
|
||||
System.out.println(">>> Report create received: appointmentId=" + report.getAppointmentId() + ", userId=" + report.getUserId() + ", before=" + report.getBeforePhoto());
|
||||
Report created = reportService.create(report);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "提交成功");
|
||||
result.put("data", Map.of(
|
||||
"reportToken", created.getReportToken(),
|
||||
"reportId", created.getId()
|
||||
));
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public Map<String, Object> list(@RequestParam(required = false) Long storeId,
|
||||
@RequestParam(required = false) Long userId) {
|
||||
List<Report> reports = reportService.list(storeId, userId);
|
||||
// 附加技师名称,并补全图片URL
|
||||
List<Map<String, Object>> data = reports.stream().map(r -> {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("id", r.getId());
|
||||
item.put("appointmentId", r.getAppointmentId());
|
||||
item.put("petName", r.getPetName());
|
||||
item.put("serviceType", r.getServiceType());
|
||||
item.put("appointmentTime", r.getAppointmentTime());
|
||||
item.put("staffName", r.getStaffName());
|
||||
item.put("reportToken", r.getReportToken());
|
||||
item.put("createTime", r.getCreateTime());
|
||||
item.put("beforePhoto", fullUrl(r.getBeforePhoto()));
|
||||
item.put("afterPhoto", fullUrl(r.getAfterPhoto()));
|
||||
item.put("storeId", r.getStoreId());
|
||||
item.put("userId", r.getUserId());
|
||||
return item;
|
||||
}).collect(Collectors.toList());
|
||||
return Map.of("code", 200, "data", data);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
public Map<String, Object> getByAppointmentId(@RequestParam(required = false) Long appointmentId,
|
||||
@RequestParam(required = false) String token) {
|
||||
Report report = null;
|
||||
if (token != null && !token.isEmpty()) {
|
||||
report = reportService.getByToken(token);
|
||||
} else if (appointmentId != null) {
|
||||
report = reportService.getByAppointmentId(appointmentId);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (report != null) {
|
||||
// 附加店铺信息
|
||||
Store store = null;
|
||||
if (report.getStoreId() != null) {
|
||||
store = storeService.findById(report.getStoreId());
|
||||
}
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("id", report.getId());
|
||||
data.put("appointmentId", report.getAppointmentId());
|
||||
data.put("beforePhoto", report.getBeforePhoto());
|
||||
data.put("afterPhoto", report.getAfterPhoto());
|
||||
data.put("remark", report.getRemark());
|
||||
data.put("userId", report.getUserId());
|
||||
data.put("storeId", report.getStoreId());
|
||||
data.put("reportToken", report.getReportToken());
|
||||
data.put("petName", report.getPetName());
|
||||
data.put("serviceType", report.getServiceType());
|
||||
data.put("appointmentTime", report.getAppointmentTime());
|
||||
data.put("staffName", report.getStaffName());
|
||||
data.put("createTime", report.getCreateTime());
|
||||
if (store != null) {
|
||||
Map<String, Object> storeInfo = new HashMap<>();
|
||||
storeInfo.put("name", store.getName());
|
||||
storeInfo.put("logo", store.getLogo());
|
||||
storeInfo.put("phone", store.getPhone());
|
||||
storeInfo.put("address", store.getAddress());
|
||||
data.put("store", storeInfo);
|
||||
}
|
||||
result.put("code", 200);
|
||||
result.put("data", data);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "报告不存在");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.entity.ServiceType;
|
||||
import com.petstore.service.ServiceTypeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/service-type")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class ServiceTypeController {
|
||||
private final ServiceTypeService serviceTypeService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Map<String, Object> list(@RequestParam Long storeId) {
|
||||
List<ServiceType> list = serviceTypeService.getByStoreId(storeId);
|
||||
return Map.of("code", 200, "data", list);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Map<String, Object> create(@RequestBody Map<String, Object> params) {
|
||||
Long storeId = Long.valueOf(params.get("storeId").toString());
|
||||
String name = params.get("name").toString();
|
||||
ServiceType created = serviceTypeService.create(storeId, name);
|
||||
return Map.of("code", 200, "data", created);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
public Map<String, Object> update(@RequestBody Map<String, Object> params) {
|
||||
Long id = Long.valueOf(params.get("id").toString());
|
||||
String name = params.get("name").toString();
|
||||
ServiceType updated = serviceTypeService.update(id, name);
|
||||
return Map.of("code", 200, "data", updated);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
public Map<String, Object> delete(@RequestParam Long id) {
|
||||
serviceTypeService.delete(id);
|
||||
return Map.of("code", 200, "message", "删除成功");
|
||||
}
|
||||
|
||||
@PostMapping("/init")
|
||||
public Map<String, Object> init() {
|
||||
serviceTypeService.initDefaults();
|
||||
return Map.of("code", 200, "message", "初始化成功");
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/sms")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class SmsController {
|
||||
|
||||
// TODO: 接入真实的短信服务商(阿里云/腾讯云/华为云等)
|
||||
// 这里用演示模式,随机生成6位验证码
|
||||
|
||||
@PostMapping("/send")
|
||||
public Map<String, Object> send(@RequestBody Map<String, String> params) {
|
||||
String phone = params.get("phone");
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (phone == null || phone.length() != 11) {
|
||||
result.put("code", 400);
|
||||
result.put("message", "手机号格式不正确");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 演示:生成6位验证码
|
||||
String code = String.format("%06d", new Random().nextInt(999999));
|
||||
|
||||
// TODO: 调用真实短信服务商发送验证码
|
||||
// 阿里云示例: dysmsapi.aliyuncs.com
|
||||
// 腾讯云示例: sms.tencentcloudapi.com
|
||||
|
||||
System.out.println("【宠伴生活馆】验证码:" + code + ",您正在登录,5分钟内有效。");
|
||||
|
||||
result.put("code", 200);
|
||||
result.put("message", "发送成功");
|
||||
result.put("data", Map.of("code", code)); // 演示用,实际生产环境不应返回code
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.entity.Store;
|
||||
import com.petstore.service.StoreService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/store")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class StoreController {
|
||||
private final StoreService storeService;
|
||||
|
||||
@PostMapping("/register")
|
||||
public Map<String, Object> register(@RequestBody Store store) {
|
||||
Store created = storeService.create(store);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "注册成功");
|
||||
result.put("data", created);
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
public Map<String, Object> get(@RequestParam Long id) {
|
||||
Store store = storeService.findById(id);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (store != null) {
|
||||
result.put("code", 200);
|
||||
result.put("data", store);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "店铺不存在");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
public Map<String, Object> update(@RequestBody Store store) {
|
||||
Store updated = storeService.update(store);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("message", "更新成功");
|
||||
result.put("data", updated);
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/invite-code")
|
||||
public Map<String, Object> getByInviteCode(@RequestParam String code) {
|
||||
Store store = storeService.findByInviteCode(code);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if (store != null) {
|
||||
result.put("code", 200);
|
||||
result.put("data", store);
|
||||
} else {
|
||||
result.put("code", 404);
|
||||
result.put("message", "邀请码无效");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.entity.User;
|
||||
import com.petstore.service.UserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/user")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class UserController {
|
||||
private final UserService userService;
|
||||
|
||||
/** 老板注册店铺 */
|
||||
@PostMapping("/register-boss")
|
||||
public Map<String, Object> registerBoss(@RequestBody Map<String, String> params) {
|
||||
String storeName = params.get("storeName");
|
||||
String bossName = params.get("bossName");
|
||||
String phone = params.get("phone");
|
||||
String password = params.get("password");
|
||||
return userService.registerBoss(storeName, bossName, phone, password);
|
||||
}
|
||||
|
||||
/** 登录(老板/员工) */
|
||||
@PostMapping("/login")
|
||||
public Map<String, Object> login(@RequestBody Map<String, String> params) {
|
||||
String phone = params.get("phone");
|
||||
String code = params.get("code");
|
||||
return userService.login(phone, code);
|
||||
}
|
||||
|
||||
/** 员工注册(邀请码方式) */
|
||||
@PostMapping("/register-staff")
|
||||
public Map<String, Object> registerStaff(@RequestBody Map<String, String> params) {
|
||||
String phone = params.get("phone");
|
||||
String password = params.get("password");
|
||||
String name = params.get("name");
|
||||
String inviteCode = params.get("inviteCode");
|
||||
return userService.registerStaff(phone, password, name, inviteCode);
|
||||
}
|
||||
|
||||
/** 老板:创建员工 */
|
||||
@PostMapping("/create-staff")
|
||||
public Map<String, Object> createStaff(@RequestBody Map<String, Object> params) {
|
||||
Long storeId = Long.valueOf(params.get("storeId").toString());
|
||||
String name = params.get("name").toString();
|
||||
String phone = params.get("phone").toString();
|
||||
return userService.createStaff(storeId, name, phone);
|
||||
}
|
||||
|
||||
/** 老板:员工列表 */
|
||||
@GetMapping("/staff-list")
|
||||
public Map<String, Object> staffList(@RequestParam Long storeId) {
|
||||
List<User> list = userService.getStaffList(storeId);
|
||||
// 不返回密码
|
||||
list.forEach(u -> u.setPassword(null));
|
||||
return Map.of("code", 200, "data", list);
|
||||
}
|
||||
|
||||
/** 老板:删除员工 */
|
||||
@DeleteMapping("/staff")
|
||||
public Map<String, Object> deleteStaff(@RequestParam Long staffId) {
|
||||
userService.deleteStaff(staffId);
|
||||
return Map.of("code", 200, "message", "删除成功");
|
||||
}
|
||||
|
||||
/** 获取用户信息 */
|
||||
@GetMapping("/info")
|
||||
public Map<String, Object> info(@RequestParam Long userId) {
|
||||
User user = userService.findById(userId);
|
||||
if (user != null) user.setPassword(null);
|
||||
return Map.of("code", 200, "data", user);
|
||||
}
|
||||
|
||||
/** 更新用户信息(头像/姓名/手机号) */
|
||||
@PutMapping("/update")
|
||||
public Map<String, Object> updateUser(@RequestBody Map<String, Object> params) {
|
||||
return userService.updateUser(params);
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
package com.petstore.controller;
|
||||
|
||||
import com.petstore.config.WechatConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wechat")
|
||||
@RequiredArgsConstructor
|
||||
@CrossOrigin
|
||||
public class WechatController {
|
||||
private final WechatConfig wechatConfig;
|
||||
|
||||
/**
|
||||
* 获取微信授权跳转地址
|
||||
*/
|
||||
@GetMapping("/authorize")
|
||||
public Map<String, Object> getAuthorizeUrl() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("code", 200);
|
||||
result.put("data", wechatConfig.getAuthorizeUrl());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信授权回调
|
||||
* 通过 code 换取 access_token,返回用户信息
|
||||
*/
|
||||
@GetMapping("/callback")
|
||||
public Map<String, Object> callback(@RequestParam String code, @RequestParam String state) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
// TODO: 通过 code 调用微信接口换取 openid 和 access_token
|
||||
// https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
|
||||
|
||||
// 演示用:直接返回成功
|
||||
result.put("code", 200);
|
||||
result.put("message", "微信授权成功");
|
||||
result.put("data", Map.of(
|
||||
"openid", "demo_openid_" + code,
|
||||
"nickname", "微信用户",
|
||||
"avatar", ""
|
||||
));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package com.petstore.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "t_appointment")
|
||||
public class Appointment {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String petName;
|
||||
private String petType;
|
||||
private String serviceType;
|
||||
private LocalDateTime appointmentTime;
|
||||
|
||||
/** 状态: new/doing/done/cancel */
|
||||
private String status;
|
||||
|
||||
@Column(name = "store_id")
|
||||
private Long storeId;
|
||||
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
|
||||
/** 技师ID,开始服务时赋值 */
|
||||
@Column(name = "assigned_user_id")
|
||||
private Long assignedUserId;
|
||||
|
||||
private String remark;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
package com.petstore.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "t_report")
|
||||
public class Report {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("appointmentId")
|
||||
@Column(name = "appointment_id")
|
||||
private Long appointmentId;
|
||||
|
||||
@Column(name = "before_photo", columnDefinition = "TEXT")
|
||||
private String beforePhoto;
|
||||
|
||||
@Column(name = "after_photo", columnDefinition = "TEXT")
|
||||
private String afterPhoto;
|
||||
|
||||
private String remark;
|
||||
|
||||
@Column(name = "user_id")
|
||||
private Long userId;
|
||||
|
||||
@Column(name = "store_id")
|
||||
private Long storeId;
|
||||
|
||||
@Column(name = "report_token")
|
||||
private String reportToken;
|
||||
|
||||
private String petName;
|
||||
private String serviceType;
|
||||
private LocalDateTime appointmentTime;
|
||||
private String staffName;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
package com.petstore.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "t_service_type")
|
||||
public class ServiceType {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/** 店铺ID,NULL表示系统默认 */
|
||||
private Long storeId;
|
||||
|
||||
private String name;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package com.petstore.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "t_store")
|
||||
public class Store {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
private String logo;
|
||||
private String phone;
|
||||
private String address;
|
||||
/** 地图选点纬度(WGS84 / 各端与地图接口一致) */
|
||||
private Double latitude;
|
||||
/** 地图选点经度 */
|
||||
private Double longitude;
|
||||
private String intro;
|
||||
|
||||
@Column(name = "owner_id")
|
||||
private Long ownerId;
|
||||
|
||||
@Column(name = "invite_code")
|
||||
private String inviteCode;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
package com.petstore.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "t_user")
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
private String name;
|
||||
private String phone;
|
||||
private String avatar;
|
||||
|
||||
@Column(name = "store_id")
|
||||
private Long storeId;
|
||||
|
||||
/** 角色:boss / staff / customer */
|
||||
private String role;
|
||||
|
||||
@Column(name = "create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
package com.petstore.mapper;
|
||||
|
||||
import com.petstore.entity.Appointment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AppointmentMapper extends JpaRepository<Appointment, Long> {
|
||||
List<Appointment> findByUserId(Long userId);
|
||||
List<Appointment> findByUserIdAndStatus(Long userId, String status);
|
||||
List<Appointment> findByStoreId(Long storeId);
|
||||
List<Appointment> findByStoreIdAndStatus(Long storeId, String status);
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package com.petstore.mapper;
|
||||
|
||||
import com.petstore.entity.Report;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface ReportMapper extends JpaRepository<Report, Long> {
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.petstore.mapper;
|
||||
|
||||
import com.petstore.entity.ServiceType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ServiceTypeMapper extends JpaRepository<ServiceType, Long> {
|
||||
List<ServiceType> findByStoreIdOrStoreIdIsNull(Long storeId);
|
||||
List<ServiceType> findByStoreId(Long storeId);
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
package com.petstore.mapper;
|
||||
|
||||
import com.petstore.entity.Store;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface StoreMapper extends JpaRepository<Store, Long> {
|
||||
Store findByInviteCode(String inviteCode);
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package com.petstore.mapper;
|
||||
|
||||
import com.petstore.entity.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface UserMapper extends JpaRepository<User, Long> {
|
||||
User findByUsername(String username);
|
||||
User findByPhone(String phone);
|
||||
List<User> findByStoreId(Long storeId);
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
package com.petstore.service;
|
||||
|
||||
import com.petstore.entity.Appointment;
|
||||
import com.petstore.mapper.AppointmentMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppointmentService {
|
||||
private final AppointmentMapper appointmentMapper;
|
||||
|
||||
// 员工查看自己的预约
|
||||
public List<Appointment> getByUserId(Long userId) {
|
||||
return appointmentMapper.findByUserId(userId);
|
||||
}
|
||||
|
||||
// 老板查看本店所有预约
|
||||
public List<Appointment> getByStoreId(Long storeId) {
|
||||
return appointmentMapper.findByStoreId(storeId);
|
||||
}
|
||||
|
||||
// 员工按状态查
|
||||
public List<Appointment> getByUserIdAndStatus(Long userId, String status) {
|
||||
return appointmentMapper.findByUserIdAndStatus(userId, status);
|
||||
}
|
||||
|
||||
// 老板按状态查
|
||||
public List<Appointment> getByStoreIdAndStatus(Long storeId, String status) {
|
||||
return appointmentMapper.findByStoreIdAndStatus(storeId, status);
|
||||
}
|
||||
|
||||
public Appointment create(Appointment appointment) {
|
||||
appointment.setCreateTime(LocalDateTime.now());
|
||||
appointment.setUpdateTime(LocalDateTime.now());
|
||||
return appointmentMapper.save(appointment);
|
||||
}
|
||||
|
||||
public Appointment updateStatus(Long id, String status) {
|
||||
Appointment appointment = appointmentMapper.findById(id).orElse(null);
|
||||
if (appointment != null) {
|
||||
appointment.setStatus(status);
|
||||
appointment.setUpdateTime(LocalDateTime.now());
|
||||
return appointmentMapper.save(appointment);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 开始服务:状态变为进行中,同时指定技师为当前用户 */
|
||||
public Appointment startService(Long appointmentId, Long staffUserId) {
|
||||
Appointment appointment = appointmentMapper.findById(appointmentId).orElse(null);
|
||||
if (appointment != null) {
|
||||
appointment.setStatus("doing");
|
||||
appointment.setAssignedUserId(staffUserId);
|
||||
appointment.setUpdateTime(LocalDateTime.now());
|
||||
return appointmentMapper.save(appointment);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
package com.petstore.service;
|
||||
|
||||
import com.petstore.entity.Appointment;
|
||||
import com.petstore.entity.Report;
|
||||
import com.petstore.entity.User;
|
||||
import com.petstore.mapper.AppointmentMapper;
|
||||
import com.petstore.mapper.ReportMapper;
|
||||
import com.petstore.mapper.UserMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ReportService {
|
||||
private final ReportMapper reportMapper;
|
||||
private final AppointmentMapper appointmentMapper;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
public Report create(Report report) {
|
||||
// 生成唯一令牌
|
||||
report.setReportToken(UUID.randomUUID().toString().replace("-", ""));
|
||||
|
||||
// 填充冗余字段,并自动完成预约
|
||||
if (report.getAppointmentId() != null) {
|
||||
Appointment appt = appointmentMapper.findById(report.getAppointmentId()).orElse(null);
|
||||
if (appt != null) {
|
||||
report.setPetName(appt.getPetName());
|
||||
report.setServiceType(appt.getServiceType());
|
||||
report.setAppointmentTime(appt.getAppointmentTime());
|
||||
report.setStoreId(appt.getStoreId());
|
||||
// 技师取预约分配的技师(开始服务时指定的)
|
||||
if (appt.getAssignedUserId() != null) {
|
||||
User staff = userMapper.findById(appt.getAssignedUserId()).orElse(null);
|
||||
if (staff != null) {
|
||||
report.setUserId(staff.getId());
|
||||
report.setStaffName(staff.getName());
|
||||
}
|
||||
}
|
||||
// 填写完报告,自动标记预约为已完成
|
||||
appt.setStatus("done");
|
||||
appt.setUpdateTime(LocalDateTime.now());
|
||||
appointmentMapper.save(appt);
|
||||
}
|
||||
}
|
||||
// 如果预约没分配技师,则用当前操作人
|
||||
if (report.getUserId() != null && report.getStaffName() == null) {
|
||||
User staff = userMapper.findById(report.getUserId()).orElse(null);
|
||||
if (staff != null) {
|
||||
report.setStaffName(staff.getName());
|
||||
if (report.getStoreId() == null) {
|
||||
report.setStoreId(staff.getStoreId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report.setCreateTime(LocalDateTime.now());
|
||||
report.setUpdateTime(LocalDateTime.now());
|
||||
return reportMapper.save(report);
|
||||
}
|
||||
|
||||
public Report getByAppointmentId(Long appointmentId) {
|
||||
return reportMapper.findAll().stream()
|
||||
.filter(r -> r.getAppointmentId().equals(appointmentId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public Report getByToken(String token) {
|
||||
return reportMapper.findAll().stream()
|
||||
.filter(r -> token.equals(r.getReportToken()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public List<Report> list(Long storeId, Long userId) {
|
||||
return reportMapper.findAll().stream()
|
||||
.filter(r -> storeId == null || storeId.equals(r.getStoreId()))
|
||||
.filter(r -> userId == null || userId.equals(r.getUserId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
package com.petstore.service;
|
||||
|
||||
import com.petstore.entity.ServiceType;
|
||||
import com.petstore.mapper.ServiceTypeMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ServiceTypeService {
|
||||
private final ServiceTypeMapper serviceTypeMapper;
|
||||
|
||||
/** 获取服务类型(系统默认 + 当前店铺自定义) */
|
||||
public List<ServiceType> getByStoreId(Long storeId) {
|
||||
return serviceTypeMapper.findByStoreIdOrStoreIdIsNull(storeId);
|
||||
}
|
||||
|
||||
/** 老板新增服务类型 */
|
||||
public ServiceType create(Long storeId, String name) {
|
||||
ServiceType st = new ServiceType();
|
||||
st.setStoreId(storeId);
|
||||
st.setName(name);
|
||||
st.setCreateTime(LocalDateTime.now());
|
||||
return serviceTypeMapper.save(st);
|
||||
}
|
||||
|
||||
/** 老板编辑服务类型 */
|
||||
public ServiceType update(Long id, String name) {
|
||||
ServiceType st = serviceTypeMapper.findById(id).orElse(null);
|
||||
if (st != null) {
|
||||
st.setName(name);
|
||||
serviceTypeMapper.save(st);
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
/** 老板删除服务类型(仅能删除自己店铺的) */
|
||||
public void delete(Long id) {
|
||||
serviceTypeMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/** 初始化系统默认服务类型(如果不存在) */
|
||||
public void initDefaults() {
|
||||
List<ServiceType> defaults = serviceTypeMapper.findByStoreIdOrStoreIdIsNull(null);
|
||||
if (defaults.isEmpty()) {
|
||||
String[] names = {"洗澡", "美容", "洗澡+美容", "剪指甲", "驱虫"};
|
||||
for (String name : names) {
|
||||
ServiceType st = new ServiceType();
|
||||
st.setStoreId(null);
|
||||
st.setName(name);
|
||||
st.setCreateTime(LocalDateTime.now());
|
||||
serviceTypeMapper.save(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
package com.petstore.service;
|
||||
|
||||
import com.petstore.entity.Store;
|
||||
import com.petstore.mapper.StoreMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class StoreService {
|
||||
private final StoreMapper storeMapper;
|
||||
|
||||
public Store create(Store store) {
|
||||
store.setInviteCode(generateInviteCode());
|
||||
store.setCreateTime(LocalDateTime.now());
|
||||
store.setUpdateTime(LocalDateTime.now());
|
||||
return storeMapper.save(store);
|
||||
}
|
||||
|
||||
public Store findById(Long id) {
|
||||
return storeMapper.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
public Store findByInviteCode(String code) {
|
||||
return storeMapper.findByInviteCode(code);
|
||||
}
|
||||
|
||||
public Store update(Store store) {
|
||||
store.setUpdateTime(LocalDateTime.now());
|
||||
return storeMapper.save(store);
|
||||
}
|
||||
|
||||
private String generateInviteCode() {
|
||||
return UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase();
|
||||
}
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
package com.petstore.service;
|
||||
|
||||
import com.petstore.entity.Store;
|
||||
import com.petstore.entity.User;
|
||||
import com.petstore.mapper.StoreMapper;
|
||||
import com.petstore.mapper.UserMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserService {
|
||||
private final UserMapper userMapper;
|
||||
private final StoreMapper storeMapper;
|
||||
|
||||
public Map<String, Object> registerBoss(String storeName, String bossName, String phone, String password) {
|
||||
if (userMapper.findByPhone(phone) != null) {
|
||||
return Map.of("code", 400, "message", "手机号已注册");
|
||||
}
|
||||
|
||||
Store store = new Store();
|
||||
store.setName(storeName);
|
||||
store.setPhone(phone);
|
||||
store.setOwnerId(0L);
|
||||
store.setInviteCode(UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase());
|
||||
store.setCreateTime(LocalDateTime.now());
|
||||
store.setUpdateTime(LocalDateTime.now());
|
||||
store = storeMapper.save(store);
|
||||
|
||||
User boss = new User();
|
||||
boss.setUsername(phone);
|
||||
boss.setName(bossName);
|
||||
boss.setPhone(phone);
|
||||
boss.setPassword(password);
|
||||
boss.setStoreId(store.getId());
|
||||
boss.setRole("boss");
|
||||
boss.setCreateTime(LocalDateTime.now());
|
||||
boss.setUpdateTime(LocalDateTime.now());
|
||||
boss = userMapper.save(boss);
|
||||
|
||||
store.setOwnerId(boss.getId());
|
||||
storeMapper.save(store);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("user", boss);
|
||||
data.put("store", store);
|
||||
return Map.of("code", 200, "message", "注册成功", "data", data);
|
||||
}
|
||||
|
||||
public Map<String, Object> login(String phone, String code) {
|
||||
// 演示模式:验证码 123456 万能
|
||||
if (!"123456".equals(code)) {
|
||||
return Map.of("code", 401, "message", "验证码错误");
|
||||
}
|
||||
User user = userMapper.findByPhone(phone);
|
||||
if (user == null) {
|
||||
// 自动注册为 C 端用户 (customer)
|
||||
user = new User();
|
||||
user.setUsername(phone);
|
||||
user.setPhone(phone);
|
||||
user.setName("微信用户" + phone.substring(7));
|
||||
user.setRole("customer");
|
||||
user.setCreateTime(LocalDateTime.now());
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
user = userMapper.save(user);
|
||||
}
|
||||
Store store = null;
|
||||
if (user.getStoreId() != null) {
|
||||
store = storeMapper.findById(user.getStoreId()).orElse(null);
|
||||
}
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("user", user);
|
||||
data.put("store", store);
|
||||
return Map.of("code", 200, "message", "登录成功", "data", data);
|
||||
}
|
||||
|
||||
public Map<String, Object> registerStaff(String phone, String password, String name, String inviteCode) {
|
||||
if (userMapper.findByPhone(phone) != null) {
|
||||
return Map.of("code", 400, "message", "手机号已注册");
|
||||
}
|
||||
Store store = storeMapper.findByInviteCode(inviteCode);
|
||||
if (store == null) {
|
||||
return Map.of("code", 400, "message", "邀请码无效");
|
||||
}
|
||||
User staff = new User();
|
||||
staff.setUsername(phone);
|
||||
staff.setPhone(phone);
|
||||
staff.setPassword(password);
|
||||
staff.setName(name);
|
||||
staff.setStoreId(store.getId());
|
||||
staff.setRole("staff");
|
||||
staff.setCreateTime(LocalDateTime.now());
|
||||
staff.setUpdateTime(LocalDateTime.now());
|
||||
staff = userMapper.save(staff);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("user", staff);
|
||||
data.put("store", store);
|
||||
return Map.of("code", 200, "message", "注册成功", "data", data);
|
||||
}
|
||||
|
||||
public Map<String, Object> createStaff(Long storeId, String name, String phone) {
|
||||
if (storeId == null) {
|
||||
return Map.of("code", 400, "message", "店铺ID不能为空");
|
||||
}
|
||||
if (userMapper.findByPhone(phone) != null) {
|
||||
return Map.of("code", 400, "message", "手机号已存在");
|
||||
}
|
||||
String pwd = String.format("%06d", (int)(Math.random() * 999999));
|
||||
User staff = new User();
|
||||
staff.setUsername(phone);
|
||||
staff.setName(name);
|
||||
staff.setPhone(phone);
|
||||
staff.setPassword(pwd);
|
||||
staff.setStoreId(storeId);
|
||||
staff.setRole("staff");
|
||||
staff.setCreateTime(LocalDateTime.now());
|
||||
staff.setUpdateTime(LocalDateTime.now());
|
||||
staff = userMapper.save(staff);
|
||||
return Map.of("code", 200, "message", "创建成功,初始密码:" + pwd, "data", staff);
|
||||
}
|
||||
|
||||
public List<User> getStaffList(Long storeId) {
|
||||
return userMapper.findByStoreId(storeId);
|
||||
}
|
||||
|
||||
public void deleteStaff(Long staffId) {
|
||||
userMapper.deleteById(staffId);
|
||||
}
|
||||
|
||||
public User findById(Long id) {
|
||||
return userMapper.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
public Map<String, Object> updateUser(Map<String, Object> params) {
|
||||
Long userId = Long.valueOf(params.get("id").toString());
|
||||
User user = userMapper.findById(userId).orElse(null);
|
||||
if (user == null) {
|
||||
return Map.of("code", 404, "message", "用户不存在");
|
||||
}
|
||||
if (params.containsKey("name") && params.get("name") != null) {
|
||||
user.setName(params.get("name").toString());
|
||||
}
|
||||
if (params.containsKey("phone") && params.get("phone") != null) {
|
||||
String newPhone = params.get("phone").toString();
|
||||
// 验证码校验
|
||||
String code = params.get("code") != null ? params.get("code").toString() : "";
|
||||
if (!"123456".equals(code)) {
|
||||
return Map.of("code", 400, "message", "验证码错误");
|
||||
}
|
||||
// 检查手机号是否被占用
|
||||
User existing = userMapper.findByPhone(newPhone);
|
||||
if (existing != null && !existing.getId().equals(userId)) {
|
||||
return Map.of("code", 400, "message", "手机号已被占用");
|
||||
}
|
||||
user.setPhone(newPhone);
|
||||
}
|
||||
if (params.containsKey("avatar") && params.get("avatar") != null) {
|
||||
user.setAvatar(params.get("avatar").toString());
|
||||
}
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
userMapper.save(user);
|
||||
user.setPassword(null);
|
||||
return Map.of("code", 200, "message", "更新成功", "data", user);
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
spring:
|
||||
application:
|
||||
name: petstore-backend
|
||||
datasource:
|
||||
url: jdbc:mysql://192.144.152.238:3306/petstore?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true
|
||||
username: root
|
||||
password: Wabjtam123@
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
hikari:
|
||||
max-lifetime: 1800000 # 30分钟,必须小于MySQL的wait_timeout(默认8小时)
|
||||
connection-test-query: SELECT 1
|
||||
validation-timeout: 3000
|
||||
idle-timeout: 600000 # 10分钟
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQLDialect
|
||||
format_sql: true
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 10MB
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
context-path:
|
||||
|
||||
upload:
|
||||
path: uploads
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.petstore: debug
|
||||
|
||||
# 微信登录配置(需替换为实际值)
|
||||
wechat:
|
||||
appid: YOUR_APPID
|
||||
appsecret: YOUR_APPSECRET
|
||||
redirect_uri: http://localhost:8080/api/wechat/callback
|
||||
Loading…
Reference in New Issue
Block a user