commit
19ea60d6b9
100 changed files with 46650 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||
|
/mvnw text eol=lf |
||||
|
*.cmd text eol=crlf |
||||
@ -0,0 +1,33 @@ |
|||||
|
HELP.md |
||||
|
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/ |
||||
@ -0,0 +1,81 @@ |
|||||
|
-- 数据库索引创建脚本 |
||||
|
-- 此脚本用于优化应用性能,为常用查询字段创建索引 |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 用户相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- users表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_users_userId ON users(userId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_users_phoneNumber ON users(phoneNumber); |
||||
|
CREATE INDEX IF NOT EXISTS idx_users_type ON users(type); |
||||
|
CREATE INDEX IF NOT EXISTS idx_users_level ON users(level); |
||||
|
CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 管理员相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- managers表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_managers_id ON managers(id); |
||||
|
CREATE INDEX IF NOT EXISTS idx_managers_userName ON managers(userName); |
||||
|
CREATE INDEX IF NOT EXISTS idx_managers_managerId ON managers(managerId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_managers_organization ON managers(organization); |
||||
|
CREATE INDEX IF NOT EXISTS idx_managers_managerdepartment ON managers(managerdepartment); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 用户管理相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- usermanagements表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_usermanagements_userId ON usermanagements(userId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_usermanagements_managerId ON usermanagements(managerId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_usermanagements_userName ON usermanagements(userName); |
||||
|
CREATE INDEX IF NOT EXISTS idx_usermanagements_organization ON usermanagements(organization); |
||||
|
CREATE INDEX IF NOT EXISTS idx_usermanagements_managerdepartment ON usermanagements(managerdepartment); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 产品相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- products表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_products_sellerId ON products(sellerId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_products_created_at ON products(created_at); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 购物车相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- cart_items表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_cart_items_userId ON cart_items(userId); |
||||
|
CREATE INDEX IF NOT EXISTS idx_cart_items_productId ON cart_items(productId); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 企业相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- enterprise表索引 (假设存在) |
||||
|
CREATE INDEX IF NOT EXISTS idx_enterprise_id ON enterprise(id); |
||||
|
CREATE INDEX IF NOT EXISTS idx_enterprise_name ON enterprise(name); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 联系方式相关表索引 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- contacts表索引 |
||||
|
CREATE INDEX IF NOT EXISTS idx_contacts_userId ON contacts(userId); |
||||
|
|
||||
|
-- ============================================ |
||||
|
-- 注意事项 |
||||
|
-- ============================================ |
||||
|
-- 1. 此脚本使用IF NOT EXISTS语法,可重复执行而不会报错 |
||||
|
-- 2. 索引创建会占用额外的磁盘空间,提高写操作开销,但显著提升查询性能 |
||||
|
-- 3. 建议在低峰期执行此脚本 |
||||
|
-- 4. 执行后建议监控应用性能,确认优化效果 |
||||
|
-- 5. 对于MySQL数据库,索引创建命令可能略有不同 |
||||
|
-- ============================================ |
||||
|
|
||||
|
-- MySQL版本的部分索引创建语法示例(仅供参考) |
||||
|
-- ALTER TABLE users ADD INDEX idx_users_userId (userId); |
||||
|
-- ALTER TABLE users ADD INDEX idx_users_phoneNumber (phoneNumber); |
||||
|
-- 以此类推... |
||||
@ -0,0 +1,224 @@ |
|||||
|
# Spring Boot应用部署到Tomcat 10.1.48指南(含性能优化) |
||||
|
|
||||
|
## 准备工作 |
||||
|
|
||||
|
1. **确认构建产物**: |
||||
|
- 已生成WAR文件:`web-0.0.1-SNAPSHOT.war`,位于`target`目录下 |
||||
|
- 确认包含最新性能优化:SQL查询优化、分页功能、二级缓存配置 |
||||
|
|
||||
|
2. **Tomcat环境要求**: |
||||
|
- Tomcat版本:10.1.48(Jakarta EE 10兼容) |
||||
|
- JDK版本:17或更高(与项目`pom.xml`中配置的Java版本一致) |
||||
|
- 数据库:需创建优化索引(详见数据库索引优化部分) |
||||
|
|
||||
|
## 部署步骤 |
||||
|
|
||||
|
### 1. 准备部署文件 |
||||
|
|
||||
|
```bash |
||||
|
# 将WAR文件重命名为DL.war(与context-path一致) |
||||
|
# 注意:在Windows命令提示符中使用 |
||||
|
copy target\web-0.0.1-SNAPSHOT.war target\DL.war |
||||
|
|
||||
|
# 或者在PowerShell中使用 |
||||
|
# Copy-Item -Path "target\web-0.0.1-SNAPSHOT.war" -Destination "target\DL.war" |
||||
|
|
||||
|
# 在Linux/Mac终端中使用(注意转义括号) |
||||
|
# cp d:\java\project\web\(8)\web\target\web-0.0.1-SNAPSHOT.war d:\java\project\web\(8)\web\target\DL.war |
||||
|
# 或者使用相对路径避免路径转义问题 |
||||
|
# cd d:\java\project\web(8)\web && cp target\web-0.0.1-SNAPSHOT.war target\DL.war |
||||
|
``` |
||||
|
|
||||
|
### 2. 上传WAR文件到服务器 |
||||
|
|
||||
|
使用SFTP或SCP工具将`DL.war`文件上传到服务器的Tomcat目录: |
||||
|
|
||||
|
```bash |
||||
|
# 示例:使用scp上传(注意处理路径中的括号) |
||||
|
# 方法1:转义括号 |
||||
|
scp d:\java\project\web\(8)\web\target\DL.war user@your-server:/opt/tomcat/webapps/ |
||||
|
|
||||
|
# 方法2:使用相对路径(推荐) |
||||
|
cd d:\java\project\web(8)\web |
||||
|
scp target\DL.war user@your-server:/opt/tomcat/webapps/ |
||||
|
|
||||
|
# 方法3:使用引号包裹路径(在某些终端中有效) |
||||
|
scp "d:\java\project\web(8)\web\target\DL.war" user@your-server:/opt/tomcat/webapps/ |
||||
|
``` |
||||
|
|
||||
|
### 3. 确保Tomcat目录权限正确 |
||||
|
|
||||
|
```bash |
||||
|
# 登录服务器后执行 |
||||
|
cd /opt/tomcat |
||||
|
# 确保tomcat用户对webapps目录有写权限 |
||||
|
chown -R tomcat:tomcat webapps/ |
||||
|
chmod -R 755 webapps/ |
||||
|
``` |
||||
|
|
||||
|
### 4. 配置Tomcat(可选但推荐) |
||||
|
|
||||
|
#### 4.1 配置context.xml(解决可能的内存泄漏问题) |
||||
|
|
||||
|
编辑`/opt/tomcat/conf/context.xml`文件,添加以下配置: |
||||
|
|
||||
|
```xml |
||||
|
<Context antiResourceLocking="true" antiJARLocking="true"> |
||||
|
<!-- 现有配置保持不变 --> |
||||
|
<WatchedResource>WEB-INF/web.xml</WatchedResource> |
||||
|
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> |
||||
|
</Context> |
||||
|
``` |
||||
|
|
||||
|
#### 4.2 调整Tomcat内存配置 |
||||
|
|
||||
|
编辑`/opt/tomcat/bin/setenv.sh`(如果不存在则创建): |
||||
|
|
||||
|
```bash |
||||
|
#!/bin/bash |
||||
|
# 为Tomcat设置适当的内存 |
||||
|
JAVA_OPTS="-Xms512m -Xmx1024m -XX:MaxPermSize=256m" |
||||
|
# 添加Tomcat 10兼容性参数 |
||||
|
JAVA_OPTS="$JAVA_OPTS --add-opens=java.base/java.lang=ALL-UNNAMED" |
||||
|
``` |
||||
|
|
||||
|
给脚本添加执行权限: |
||||
|
```bash |
||||
|
chmod +x /opt/tomcat/bin/setenv.sh |
||||
|
``` |
||||
|
|
||||
|
### 5. 启动或重启Tomcat |
||||
|
|
||||
|
```bash |
||||
|
# 切换到Tomcat的bin目录 |
||||
|
cd /opt/tomcat/bin |
||||
|
|
||||
|
# 停止Tomcat(如果正在运行) |
||||
|
./shutdown.sh |
||||
|
|
||||
|
# 等待Tomcat完全停止(约30秒) |
||||
|
|
||||
|
# 启动Tomcat |
||||
|
./startup.sh |
||||
|
``` |
||||
|
|
||||
|
### 6. 验证部署 |
||||
|
|
||||
|
1. **检查Tomcat日志**: |
||||
|
```bash |
||||
|
tail -f /opt/tomcat/logs/catalina.out |
||||
|
``` |
||||
|
|
||||
|
2. **访问应用**: |
||||
|
- 应用应该可以通过以下URL访问:`http://your-server-ip:8080/DL` |
||||
|
- 登录页面:`http://your-server-ip:8080/DL/loginmm.html` |
||||
|
|
||||
|
## 常见问题排查 |
||||
|
|
||||
|
### 1. 端口冲突 |
||||
|
|
||||
|
如果Tomcat的8080端口已被占用,修改`/opt/tomcat/conf/server.xml`中的端口配置: |
||||
|
|
||||
|
```xml |
||||
|
<Connector port="8080" protocol="HTTP/1.1" |
||||
|
connectionTimeout="20000" |
||||
|
redirectPort="8443" /> |
||||
|
``` |
||||
|
|
||||
|
### 2. 数据库连接问题 |
||||
|
|
||||
|
确保数据库服务器允许来自Tomcat服务器IP的连接。检查应用配置中的数据库连接URL是否正确。 |
||||
|
|
||||
|
### 3. 类加载问题(Tomcat 10特有) |
||||
|
|
||||
|
Tomcat 10使用Jakarta EE,所有`javax.*`包已改为`jakarta.*`。如果出现类找不到的错误: |
||||
|
|
||||
|
- 检查是否有冲突的JAR包在WEB-INF/lib中 |
||||
|
- 确保使用的是支持Jakarta EE的依赖版本 |
||||
|
|
||||
|
### 4. 内存溢出 |
||||
|
|
||||
|
如果出现内存溢出错误,增加Tomcat的内存分配,修改`setenv.sh`文件: |
||||
|
|
||||
|
```bash |
||||
|
JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MaxPermSize=512m" |
||||
|
``` |
||||
|
|
||||
|
## 数据库索引优化(重要) |
||||
|
|
||||
|
在部署新版本前,请在数据库服务器上执行以下索引创建脚本,以提升查询性能: |
||||
|
|
||||
|
```sql |
||||
|
-- 执行CREATE_OPTIMIZATION_INDEXES.sql文件中的脚本 |
||||
|
-- 在服务器上执行: |
||||
|
source /path/to/CREATE_OPTIMIZATION_INDEXES.sql |
||||
|
|
||||
|
-- 或直接复制脚本内容执行 |
||||
|
|
||||
|
-- 1. 为managers表创建索引 |
||||
|
CREATE INDEX idx_managers_enterprise_id ON managers(enterprise_id); |
||||
|
CREATE INDEX idx_managers_user_name ON managers(user_name); |
||||
|
|
||||
|
-- 2. 为users表创建索引 |
||||
|
CREATE INDEX idx_users_user_id ON users(user_id); |
||||
|
CREATE INDEX idx_users_user_name ON users(user_name); |
||||
|
CREATE INDEX idx_users_status ON users(status); |
||||
|
|
||||
|
-- 3. 为usermanagements表创建索引 |
||||
|
CREATE INDEX idx_usermanagements_user_id ON usermanagements(user_id); |
||||
|
CREATE INDEX idx_usermanagements_role_id ON usermanagements(role_id); |
||||
|
CREATE INDEX idx_usermanagements_permission_level ON usermanagements(permission_level); |
||||
|
``` |
||||
|
|
||||
|
## 应用更新流程 |
||||
|
|
||||
|
1. **执行数据库索引优化**:按照上方数据库索引优化部分执行索引创建脚本 |
||||
|
2. **停止Tomcat**:`./shutdown.sh` |
||||
|
3. **备份旧数据**:`cp -r /opt/tomcat/webapps/DL /path/to/backup/` |
||||
|
4. **删除旧的WAR文件和解压目录**:`rm -rf /opt/tomcat/webapps/DL*` |
||||
|
5. **上传新的WAR文件** |
||||
|
6. **启动Tomcat**:`./startup.sh` |
||||
|
7. **监控日志确认部署成功**:`tail -f /opt/tomcat/logs/catalina.out` |
||||
|
|
||||
|
## 性能优化验证 |
||||
|
|
||||
|
部署完成后,请执行以下验证步骤确认性能优化效果: |
||||
|
|
||||
|
1. **验证分页功能**: |
||||
|
- 访问负责人管理页面,确认列表显示已启用分页 |
||||
|
- 验证翻页功能正常,数据加载速度提升 |
||||
|
|
||||
|
2. **验证SQL查询性能**: |
||||
|
- 执行常用查询操作,确认响应时间明显改善 |
||||
|
- 监控数据库慢查询日志,检查是否有新的慢查询 |
||||
|
|
||||
|
3. **验证缓存效果**: |
||||
|
- 连续访问相同数据页面,确认第二次访问速度更快 |
||||
|
|
||||
|
## 回滚方案 |
||||
|
|
||||
|
如遇部署问题,请按以下步骤回滚: |
||||
|
|
||||
|
1. 停止Tomcat:`./shutdown.sh` |
||||
|
2. 删除新部署文件:`rm -rf /opt/tomcat/webapps/DL*` |
||||
|
3. 恢复备份:`cp -r /path/to/backup/DL /opt/tomcat/webapps/` |
||||
|
4. 恢复数据库索引(如需要) |
||||
|
5. 启动Tomcat:`./startup.sh` |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **备份**:部署前请备份现有应用数据和配置 |
||||
|
2. **维护窗口**:选择低流量时段进行部署 |
||||
|
3. **监控**:部署后密切监控应用性能和日志 |
||||
|
4. **权限**:确保Tomcat用户对所有必要目录有正确权限 |
||||
|
5. **性能监控**:部署后持续监控系统性能指标,必要时进行进一步优化 |
||||
|
6. **索引维护**:定期检查数据库索引使用情况和碎片 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
部署时间:2024 |
||||
|
版本:2.0(包含性能优化) |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
> 详细性能优化说明请参考:PERFORMANCE_OPTIMIZATION_GUIDE.md |
||||
Binary file not shown.
@ -0,0 +1,184 @@ |
|||||
|
# Spring Boot应用最新部署指南(性能优化版) |
||||
|
|
||||
|
## 版本信息 |
||||
|
- **版本**: 2.0 |
||||
|
- **日期**: 2024 |
||||
|
- **更新内容**: 包含数据库性能优化、SQL查询优化、分页功能和缓存配置 |
||||
|
|
||||
|
## 一、优化内容概述 |
||||
|
|
||||
|
### 1.1 已完成的性能优化 |
||||
|
|
||||
|
#### SQL查询优化 |
||||
|
- 将`SELECT *`查询替换为显式字段列表,减少数据传输量 |
||||
|
- 优化复杂JOIN查询,减少不必要的表连接 |
||||
|
|
||||
|
#### 分页功能实现 |
||||
|
- 新增`selectAllManagersWithPagination`方法实现分页查询 |
||||
|
- 添加`getManagersCount`方法获取总数用于分页计算 |
||||
|
|
||||
|
#### 缓存配置 |
||||
|
- 为ManagersMapper添加LRU二级缓存配置 |
||||
|
- 提升重复查询性能 |
||||
|
|
||||
|
#### 数据库索引 |
||||
|
- 为关键字段创建索引,提升查询性能 |
||||
|
- 详细索引脚本位于`CREATE_OPTIMIZATION_INDEXES.sql` |
||||
|
|
||||
|
## 二、部署前准备 |
||||
|
|
||||
|
### 2.1 确认构建产物 |
||||
|
- **WAR文件**: `target\web-0.0.1-SNAPSHOT.war` |
||||
|
- **索引脚本**: `CREATE_OPTIMIZATION_INDEXES.sql` |
||||
|
- **验证文件**: `src\main\resources\mapper`目录下的优化后的XML文件 |
||||
|
|
||||
|
### 2.2 环境要求 |
||||
|
- **Tomcat**: 10.1.48(Jakarta EE 10兼容) |
||||
|
- **JDK**: 17或更高 |
||||
|
- **数据库**: 支持索引创建的关系型数据库 |
||||
|
|
||||
|
## 三、部署流程 |
||||
|
|
||||
|
### 3.1 本地准备部署文件 |
||||
|
|
||||
|
```bash |
||||
|
# 1. 清理并构建项目 |
||||
|
mvn clean package -DskipTests |
||||
|
|
||||
|
# 2. 重命名WAR文件 |
||||
|
copy target\web-0.0.1-SNAPSHOT.war target\DL.war |
||||
|
``` |
||||
|
|
||||
|
### 3.2 数据库索引优化(关键步骤) |
||||
|
|
||||
|
在数据库服务器上执行索引创建脚本: |
||||
|
|
||||
|
```sql |
||||
|
-- 执行CREATE_OPTIMIZATION_INDEXES.sql文件 |
||||
|
-- 或直接执行以下索引创建语句 |
||||
|
|
||||
|
-- 为managers表创建索引 |
||||
|
CREATE INDEX idx_managers_enterprise_id ON managers(enterprise_id); |
||||
|
CREATE INDEX idx_managers_user_name ON managers(user_name); |
||||
|
|
||||
|
-- 为users表创建索引 |
||||
|
CREATE INDEX idx_users_user_id ON users(user_id); |
||||
|
CREATE INDEX idx_users_user_name ON users(user_name); |
||||
|
CREATE INDEX idx_users_status ON users(status); |
||||
|
|
||||
|
-- 为usermanagements表创建索引 |
||||
|
CREATE INDEX idx_usermanagements_user_id ON usermanagements(user_id); |
||||
|
CREATE INDEX idx_usermanagements_role_id ON usermanagements(role_id); |
||||
|
CREATE INDEX idx_usermanagements_permission_level ON usermanagements(permission_level); |
||||
|
``` |
||||
|
|
||||
|
### 3.3 上传部署文件 |
||||
|
|
||||
|
使用SFTP或SCP上传文件到服务器: |
||||
|
|
||||
|
```bash |
||||
|
# 上传WAR文件 |
||||
|
scp target\DL.war user@your-server:/opt/tomcat/webapps/ |
||||
|
|
||||
|
# 上传索引脚本(用于备份) |
||||
|
scp CREATE_OPTIMIZATION_INDEXES.sql user@your-server:/opt/tomcat/ |
||||
|
``` |
||||
|
|
||||
|
### 3.4 服务器部署操作 |
||||
|
|
||||
|
登录服务器后执行: |
||||
|
|
||||
|
```bash |
||||
|
# 1. 停止Tomcat |
||||
|
cd /opt/tomcat/bin |
||||
|
./shutdown.sh |
||||
|
|
||||
|
# 2. 等待Tomcat完全停止(约30秒) |
||||
|
|
||||
|
# 3. 备份旧应用 |
||||
|
cp -r /opt/tomcat/webapps/DL /opt/tomcat/backup/ |
||||
|
|
||||
|
# 4. 删除旧部署文件 |
||||
|
rm -rf /opt/tomcat/webapps/DL* |
||||
|
|
||||
|
# 5. 确保权限正确 |
||||
|
chown -R tomcat:tomcat /opt/tomcat/webapps/ |
||||
|
chmod -R 755 /opt/tomcat/webapps/ |
||||
|
|
||||
|
# 6. 启动Tomcat |
||||
|
./startup.sh |
||||
|
|
||||
|
# 7. 监控部署日志 |
||||
|
tail -f /opt/tomcat/logs/catalina.out |
||||
|
``` |
||||
|
|
||||
|
## 四、部署后验证 |
||||
|
|
||||
|
### 4.1 功能验证 |
||||
|
- **访问应用**: `http://your-server-ip:8080/DL` |
||||
|
- **登录验证**: 确认可以正常登录 |
||||
|
- **数据操作**: 验证增删改查功能正常 |
||||
|
|
||||
|
### 4.2 性能优化验证 |
||||
|
|
||||
|
#### 分页功能验证 |
||||
|
- 访问负责人管理页面 |
||||
|
- 确认列表显示已启用分页 |
||||
|
- 验证翻页功能正常工作 |
||||
|
- 检查数据加载速度是否提升 |
||||
|
|
||||
|
#### SQL查询性能验证 |
||||
|
- 执行常用查询操作 |
||||
|
- 确认响应时间明显改善 |
||||
|
- 监控数据库慢查询日志 |
||||
|
|
||||
|
#### 缓存效果验证 |
||||
|
- 连续访问相同数据页面 |
||||
|
- 确认第二次及后续访问速度更快 |
||||
|
|
||||
|
## 五、回滚方案 |
||||
|
|
||||
|
如遇部署问题,请按以下步骤回滚: |
||||
|
|
||||
|
```bash |
||||
|
# 1. 停止Tomcat |
||||
|
cd /opt/tomcat/bin |
||||
|
./shutdown.sh |
||||
|
|
||||
|
# 2. 删除新部署文件 |
||||
|
rm -rf /opt/tomcat/webapps/DL* |
||||
|
|
||||
|
# 3. 恢复备份 |
||||
|
cp -r /opt/tomcat/backup/DL /opt/tomcat/webapps/ |
||||
|
|
||||
|
# 4. 启动Tomcat |
||||
|
./startup.sh |
||||
|
``` |
||||
|
|
||||
|
## 六、批处理部署脚本 |
||||
|
|
||||
|
项目中提供了Windows批处理脚本`deploy_with_optimization.bat`,可以帮助准备部署文件。在项目根目录执行: |
||||
|
|
||||
|
```bash |
||||
|
# 运行批处理脚本 |
||||
|
.\deploy_with_optimization.bat |
||||
|
``` |
||||
|
|
||||
|
## 七、注意事项 |
||||
|
|
||||
|
1. **备份**: 部署前务必备份应用数据和数据库 |
||||
|
2. **维护窗口**: 选择低流量时段进行部署 |
||||
|
3. **索引优化**: 必须执行数据库索引创建脚本 |
||||
|
4. **性能监控**: 部署后持续监控系统性能 |
||||
|
5. **日志检查**: 定期检查应用日志,及时发现问题 |
||||
|
6. **权限问题**: 确保Tomcat用户对所有必要目录有正确权限 |
||||
|
|
||||
|
## 八、相关文档 |
||||
|
|
||||
|
- **性能优化详细说明**: `PERFORMANCE_OPTIMIZATION_GUIDE.md` |
||||
|
- **Mapper XML部署指南**: `MAPPER_XML_DEPLOYMENT_GUIDE.txt` |
||||
|
- **数据库索引脚本**: `CREATE_OPTIMIZATION_INDEXES.sql` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
> 部署完成后,请务必执行性能优化验证步骤,确保所有优化措施生效。 |
||||
@ -0,0 +1,146 @@ |
|||||
|
# Mapper和Service代码更新部署指南 |
||||
|
|
||||
|
## 构建状态确认 |
||||
|
|
||||
|
✅ 所有Mapper和Service Java文件已成功编译为class文件 |
||||
|
|
||||
|
### Mapper文件(最后编译时间:2025/11/6 13:50) |
||||
|
- 位置:`target\classes\com\example\web\mapper` |
||||
|
- 文件数量:20个class文件 |
||||
|
- 包含:Cart_itemsMapper、EnterpriseMapper、ManagersMapper等所有必要的Mapper接口实现 |
||||
|
|
||||
|
### Service文件(最后编译时间:2025/11/6 13:50) |
||||
|
- 位置:`target\classes\com\example\web\service` |
||||
|
- 文件数量:11个class文件 |
||||
|
- 包含:CustomerService、EnterpriseService、LoginService等所有Service实现类 |
||||
|
|
||||
|
## 部署方案 |
||||
|
|
||||
|
### 方案一:完整WAR包部署(推荐) |
||||
|
这种方法最安全、最可靠,确保所有组件版本一致。 |
||||
|
|
||||
|
1. **准备WAR文件** |
||||
|
```bash |
||||
|
# 确保WAR文件已生成 |
||||
|
ls -la target/DL.war |
||||
|
``` |
||||
|
|
||||
|
2. **上传WAR文件到服务器** |
||||
|
```bash |
||||
|
# 使用SCP上传文件 |
||||
|
scp target/DL.war user@server:/path/to/tomcat/webapps/ |
||||
|
``` |
||||
|
|
||||
|
3. **设置文件权限** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo chown tomcat:tomcat /path/to/tomcat/webapps/DL.war |
||||
|
sudo chmod 644 /path/to/tomcat/webapps/DL.war |
||||
|
``` |
||||
|
|
||||
|
4. **重启Tomcat服务** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo systemctl restart tomcat |
||||
|
# 或者 |
||||
|
sudo service tomcat restart |
||||
|
# 或者直接使用Tomcat的脚本 |
||||
|
/path/to/tomcat/bin/shutdown.sh |
||||
|
/path/to/tomcat/bin/startup.sh |
||||
|
``` |
||||
|
|
||||
|
### 方案二:仅更新Mapper和Service的class文件(风险较高) |
||||
|
如果只修改了Mapper和Service代码,可以只更新这些class文件,但要注意版本兼容性问题。 |
||||
|
|
||||
|
1. **在服务器上定位目标目录** |
||||
|
```bash |
||||
|
# 在服务器上执行,找到应用部署目录 |
||||
|
cd /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/ |
||||
|
``` |
||||
|
|
||||
|
2. **备份当前文件** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
mkdir -p ~/backup/mapper ~/backup/service |
||||
|
cp -r mapper/* ~/backup/mapper/ |
||||
|
cp -r service/* ~/backup/service/ |
||||
|
``` |
||||
|
|
||||
|
3. **上传新的class文件** |
||||
|
```bash |
||||
|
# 上传mapper文件 |
||||
|
scp target/classes/com/example/web/mapper/*.class user@server:/path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/mapper/ |
||||
|
|
||||
|
# 上传service文件 |
||||
|
scp target/classes/com/example/web/service/*.class user@server:/path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/service/ |
||||
|
``` |
||||
|
|
||||
|
4. **设置文件权限** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo chown -R tomcat:tomcat /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/mapper/ |
||||
|
sudo chown -R tomcat:tomcat /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/service/ |
||||
|
sudo chmod 644 /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/mapper/*.class |
||||
|
sudo chmod 644 /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/service/*.class |
||||
|
``` |
||||
|
|
||||
|
5. **重载应用(可选)** |
||||
|
- 方法1:重启Tomcat(最可靠) |
||||
|
```bash |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
- 方法2:使用Tomcat Manager或JMX热重载(风险较高) |
||||
|
|
||||
|
## 验证部署 |
||||
|
|
||||
|
1. **检查Tomcat日志** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
tail -f /path/to/tomcat/logs/catalina.out |
||||
|
``` |
||||
|
|
||||
|
2. **测试应用功能** |
||||
|
- 访问应用的关键功能 |
||||
|
- 执行涉及更新的Mapper和Service的操作 |
||||
|
|
||||
|
## 回滚方案 |
||||
|
|
||||
|
如果遇到问题,按照以下步骤回滚: |
||||
|
|
||||
|
1. **方案一回滚** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo rm -f /path/to/tomcat/webapps/DL.war |
||||
|
sudo rm -rf /path/to/tomcat/webapps/DL/ |
||||
|
# 上传之前的备份WAR文件 |
||||
|
scp backup/DL.war user@server:/path/to/tomcat/webapps/ |
||||
|
sudo chown tomcat:tomcat /path/to/tomcat/webapps/DL.war |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
|
||||
|
2. **方案二回滚** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
cp -r ~/backup/mapper/* /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/mapper/ |
||||
|
cp -r ~/backup/service/* /path/to/tomcat/webapps/DL/WEB-INF/classes/com/example/web/service/ |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **版本兼容性**:确保Mapper和Service的修改与其他组件兼容 |
||||
|
2. **事务一致性**:特别注意涉及多个Mapper的事务操作 |
||||
|
3. **数据库变更**:如果Mapper修改涉及数据库结构变更,请先执行数据库迁移 |
||||
|
4. **缓存清理**:如有必要,清除相关缓存 |
||||
|
5. **生产环境建议**:在生产环境中,强烈推荐使用方案一进行完整部署 |
||||
|
|
||||
|
## 后续维护建议 |
||||
|
|
||||
|
1. **建立部署文档**:记录每次部署的变更内容 |
||||
|
2. **制定回滚计划**:为每次更新准备回滚方案 |
||||
|
3. **监控应用性能**:部署后密切关注应用性能指标 |
||||
|
4. **测试完整性**:执行完整的功能测试套件 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
此指南由自动化工具生成,最后更新时间:2025/11/6 13:51 |
||||
@ -0,0 +1,163 @@ |
|||||
|
# MyBatis Mapper XML文件部署指南(含性能优化) |
||||
|
|
||||
|
## 文件状态确认 |
||||
|
|
||||
|
✅ 所有MyBatis Mapper XML映射文件已成功复制到构建目录 |
||||
|
|
||||
|
### Mapper XML文件(最后修改时间与源代码一致) |
||||
|
- 源文件位置:`src\main\resources\mapper` |
||||
|
- 构建后位置:`target\classes\mapper` |
||||
|
- 文件数量:16个XML文件 |
||||
|
- 包含:Cart_itemsMapper.xml、EnterpriseMapper.xml、ManagersMapper.xml等所有必要的MyBatis映射文件 |
||||
|
|
||||
|
## 部署方案 |
||||
|
|
||||
|
### 方案一:完整WAR包部署(推荐) |
||||
|
这种方法最安全、最可靠,确保所有组件版本一致。 |
||||
|
|
||||
|
1. **准备WAR文件** |
||||
|
```bash |
||||
|
# 确保WAR文件已生成 |
||||
|
ls -la target/DL.war |
||||
|
``` |
||||
|
|
||||
|
2. **上传WAR文件到服务器** |
||||
|
```bash |
||||
|
# 使用SCP上传文件 |
||||
|
scp target/DL.war user@server:/path/to/tomcat/webapps/ |
||||
|
``` |
||||
|
|
||||
|
3. **设置文件权限** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo chown tomcat:tomcat /path/to/tomcat/webapps/DL.war |
||||
|
sudo chmod 644 /path/to/tomcat/webapps/DL.war |
||||
|
``` |
||||
|
|
||||
|
4. **重启Tomcat服务** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo systemctl restart tomcat |
||||
|
# 或者 |
||||
|
sudo service tomcat restart |
||||
|
# 或者直接使用Tomcat的脚本 |
||||
|
/path/to/tomcat/bin/shutdown.sh |
||||
|
/path/to/tomcat/bin/startup.sh |
||||
|
``` |
||||
|
|
||||
|
### 方案二:仅更新Mapper XML文件(中等风险) |
||||
|
如果只修改了Mapper XML文件,可以只更新这些文件,但要注意版本兼容性问题。 |
||||
|
|
||||
|
1. **在服务器上定位目标目录** |
||||
|
```bash |
||||
|
# 在服务器上执行,找到应用部署目录 |
||||
|
cd /path/to/tomcat/webapps/DL/WEB-INF/classes/mapper/ |
||||
|
``` |
||||
|
|
||||
|
2. **备份当前文件** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
mkdir -p ~/backup/mapper_xml |
||||
|
cp -r * ~/backup/mapper_xml/ |
||||
|
``` |
||||
|
|
||||
|
3. **上传新的XML文件** |
||||
|
```bash |
||||
|
# 上传所有XML文件 |
||||
|
scp target/classes/mapper/*.xml user@server:/path/to/tomcat/webapps/DL/WEB-INF/classes/mapper/ |
||||
|
``` |
||||
|
|
||||
|
4. **设置文件权限** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo chown -R tomcat:tomcat /path/to/tomcat/webapps/DL/WEB-INF/classes/mapper/ |
||||
|
sudo chmod 644 /path/to/tomcat/webapps/DL/WEB-INF/classes/mapper/*.xml |
||||
|
``` |
||||
|
|
||||
|
5. **重载应用** |
||||
|
- 方法1:重启Tomcat(最可靠) |
||||
|
```bash |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
- 方法2:使用Tomcat Manager重新加载应用(较快) |
||||
|
```bash |
||||
|
# 使用curl命令重新加载应用 |
||||
|
curl -u username:password "http://localhost:8080/manager/text/reload?path=/DL" |
||||
|
``` |
||||
|
|
||||
|
## 性能优化内容 |
||||
|
|
||||
|
1. **SQL查询优化**: |
||||
|
- 将SELECT *查询替换为显式字段列表 |
||||
|
- 移除不必要的连接操作 |
||||
|
|
||||
|
2. **分页功能**: |
||||
|
- 添加selectAllManagersWithPagination方法实现分页查询 |
||||
|
- 新增getManagersCount方法获取总数 |
||||
|
|
||||
|
3. **二级缓存配置**: |
||||
|
- 为ManagersMapper添加LRU二级缓存 |
||||
|
|
||||
|
4. **数据库索引**: |
||||
|
- 为关键字段创建索引,提升查询性能 |
||||
|
- 详细索引创建脚本请参考CREATE_OPTIMIZATION_INDEXES.sql |
||||
|
|
||||
|
## 验证部署 |
||||
|
|
||||
|
1. **检查Tomcat日志** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
tail -f /path/to/tomcat/logs/catalina.out |
||||
|
``` |
||||
|
|
||||
|
2. **测试数据库操作** |
||||
|
- 访问负责人管理页面,验证分页功能是否正常 |
||||
|
- 测试数据查询操作,确认响应速度提升 |
||||
|
- 检查应用日志,确保没有错误 |
||||
|
- 监控数据库性能,确认索引正常使用 |
||||
|
|
||||
|
## 回滚方案 |
||||
|
|
||||
|
如果遇到问题,按照以下步骤回滚: |
||||
|
|
||||
|
1. **方案一回滚** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
sudo rm -f /path/to/tomcat/webapps/DL.war |
||||
|
sudo rm -rf /path/to/tomcat/webapps/DL/ |
||||
|
# 上传之前的备份WAR文件 |
||||
|
scp backup/DL.war user@server:/path/to/tomcat/webapps/ |
||||
|
sudo chown tomcat:tomcat /path/to/tomcat/webapps/DL.war |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
|
||||
|
2. **方案二回滚** |
||||
|
```bash |
||||
|
# 在服务器上执行 |
||||
|
cp -r ~/backup/mapper_xml/* /path/to/tomcat/webapps/DL/WEB-INF/classes/mapper/ |
||||
|
sudo systemctl restart tomcat |
||||
|
``` |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **版本兼容性**:确保Mapper XML的修改与对应的Java接口兼容 |
||||
|
2. **SQL语法检查**:部署前确认XML中的SQL语句语法正确 |
||||
|
3. **数据库结构**:如果SQL修改涉及表结构变更,请先执行数据库迁移 |
||||
|
4. **缓存清理**:MyBatis可能缓存映射文件,重启Tomcat可以确保清除缓存 |
||||
|
5. **事务一致性**:特别注意涉及多个Mapper的事务操作 |
||||
|
6. **参数类型**:确保XML中定义的参数类型与Java代码中的参数类型匹配 |
||||
|
7. **数据库备份**:确保在部署前备份数据库 |
||||
|
8. **索引优化**:部署新版本后务必执行数据库索引优化脚本 |
||||
|
9. **分页验证**:验证分页功能是否正常工作 |
||||
|
10. **性能监控**:持续监控数据库查询性能,必要时进行进一步优化 |
||||
|
|
||||
|
## 后续维护建议 |
||||
|
|
||||
|
1. **版本控制**:对Mapper XML文件进行版本控制,记录每次变更 |
||||
|
2. **自动化部署**:考虑使用CI/CD工具自动化部署过程 |
||||
|
3. **监控查询性能**:部署后监控查询性能,特别是对于复杂的SQL语句 |
||||
|
4. **备份策略**:建立定期备份策略,包括数据库和应用配置 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
此指南由自动化工具生成,最后更新时间:2025/11/6 |
||||
@ -0,0 +1,280 @@ |
|||||
|
# 数据库性能优化指南 |
||||
|
|
||||
|
## 问题分析 |
||||
|
|
||||
|
根据对Mapper XML文件的检查,发现以下可能导致数据返回慢的主要问题: |
||||
|
|
||||
|
### 1. 使用 SELECT * 查询所有字段 |
||||
|
- **问题**:`SELECT *` 查询会返回表中的所有列,增加网络传输量和处理时间 |
||||
|
- **影响文件**:ManagersMapper.xml中的多个查询 |
||||
|
|
||||
|
### 2. 复杂的JOIN和嵌套WHERE条件 |
||||
|
- **问题**:复杂的JOIN操作和多层嵌套条件会增加数据库解析和执行时间 |
||||
|
- **影响文件**:UsersMapper.xml中的`getAuthorizedCustomers`和`getAuthorizedUserIds`查询 |
||||
|
|
||||
|
### 3. 可能缺少必要的索引 |
||||
|
- **问题**:频繁用于查询条件的字段可能缺少索引,导致全表扫描 |
||||
|
- **影响字段**:userId, phoneNumber, type, level, managerId等 |
||||
|
|
||||
|
### 4. 未使用分页查询 |
||||
|
- **问题**:查询大量数据时未使用分页,一次性返回过多数据 |
||||
|
- **影响文件**:selectAllManagers等查询 |
||||
|
|
||||
|
## 优化方案 |
||||
|
|
||||
|
### 1. 优化SQL查询语句 |
||||
|
|
||||
|
#### 1.1 替换 SELECT * 为具体字段 |
||||
|
|
||||
|
**修改前** (ManagersMapper.xml): |
||||
|
```xml |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT * FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
``` |
||||
|
|
||||
|
**修改后**: |
||||
|
```xml |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
``` |
||||
|
|
||||
|
对其他使用 `SELECT *` 的查询也进行类似修改。 |
||||
|
|
||||
|
#### 1.2 优化复杂的JOIN查询 |
||||
|
|
||||
|
**修改建议** (UsersMapper.xml): |
||||
|
- 将复杂的嵌套条件拆分为更简单的部分 |
||||
|
- 使用子查询代替部分复杂JOIN |
||||
|
- 考虑使用临时表缓存中间结果 |
||||
|
|
||||
|
#### 1.3 添加分页查询 |
||||
|
|
||||
|
**修改前**: |
||||
|
```xml |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT * FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
``` |
||||
|
|
||||
|
**修改后**: |
||||
|
```xml |
||||
|
<select id="selectAllManagersWithPagination" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
ORDER BY userName |
||||
|
LIMIT #{limit} OFFSET #{offset} |
||||
|
</select> |
||||
|
``` |
||||
|
|
||||
|
同时在Mapper接口中添加对应的方法。 |
||||
|
|
||||
|
### 2. 添加必要的数据库索引 |
||||
|
|
||||
|
建议在以下字段上添加索引: |
||||
|
|
||||
|
```sql |
||||
|
-- 在users表上添加索引 |
||||
|
CREATE INDEX idx_users_userId ON users(userId); |
||||
|
CREATE INDEX idx_users_phoneNumber ON users(phoneNumber); |
||||
|
CREATE INDEX idx_users_type ON users(type); |
||||
|
CREATE INDEX idx_users_level ON users(level); |
||||
|
CREATE INDEX idx_users_created_at ON users(created_at); |
||||
|
|
||||
|
-- 在managers表上添加索引 |
||||
|
CREATE INDEX idx_managers_id ON managers(id); |
||||
|
CREATE INDEX idx_managers_userName ON managers(userName); |
||||
|
CREATE INDEX idx_managers_managerId ON managers(managerId); |
||||
|
|
||||
|
-- 在usermanagements表上添加索引 |
||||
|
CREATE INDEX idx_usermanagements_userId ON usermanagements(userId); |
||||
|
CREATE INDEX idx_usermanagements_managerId ON usermanagements(managerId); |
||||
|
CREATE INDEX idx_usermanagements_userName ON usermanagements(userName); |
||||
|
CREATE INDEX idx_usermanagements_organization ON usermanagements(organization); |
||||
|
CREATE INDEX idx_usermanagements_managerdepartment ON usermanagements(managerdepartment); |
||||
|
``` |
||||
|
|
||||
|
### 3. 添加缓存机制 |
||||
|
|
||||
|
#### 3.1 在MyBatis中添加二级缓存 |
||||
|
|
||||
|
在Mapper XML文件中添加缓存配置: |
||||
|
|
||||
|
```xml |
||||
|
<mapper namespace="com.example.web.mapper.ManagersMapper"> |
||||
|
<!-- 添加二级缓存 --> |
||||
|
<cache |
||||
|
eviction="LRU" |
||||
|
flushInterval="60000" |
||||
|
size="512" |
||||
|
readOnly="true"/> |
||||
|
|
||||
|
<!-- 现有映射内容 --> |
||||
|
<!-- ... --> |
||||
|
</mapper> |
||||
|
``` |
||||
|
|
||||
|
#### 3.2 在Service层添加本地缓存 |
||||
|
|
||||
|
在Service类中使用Guava Cache或Caffeine等本地缓存库。 |
||||
|
|
||||
|
### 4. 优化结果集映射 |
||||
|
|
||||
|
#### 4.1 优化ResultMap定义 |
||||
|
|
||||
|
确保ResultMap只映射必要的字段,避免不必要的映射。 |
||||
|
|
||||
|
#### 4.2 使用Constructor Args映射 |
||||
|
|
||||
|
对于频繁使用的DTO,可以考虑使用构造函数参数映射,提高性能。 |
||||
|
|
||||
|
## 具体优化实施 |
||||
|
|
||||
|
### 优化ManagersMapper.xml |
||||
|
|
||||
|
```xml |
||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.ManagersMapper"> |
||||
|
|
||||
|
<!-- 添加二级缓存 --> |
||||
|
<cache |
||||
|
eviction="LRU" |
||||
|
flushInterval="60000" |
||||
|
size="512" |
||||
|
readOnly="true"/> |
||||
|
|
||||
|
<resultMap id="managersMap" type="com.example.web.entity.Managers"> |
||||
|
<id column="manager_id" property="manager_id"/> |
||||
|
<result column="id" property="id"/> |
||||
|
<result column="managerId" property="managerId"/> |
||||
|
<result column="managercompany" property="managercompany"/> |
||||
|
<result column="managerdepartment" property="managerdepartment"/> |
||||
|
<result column="organization" property="organization"/> |
||||
|
<result column="role" property="role"/> |
||||
|
<result column="root" property="root"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result column="userName" property="userName"/> |
||||
|
<result column="assistant" property="assistant"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 在 ManagersMapper.xml 中添加 --> |
||||
|
<select id="selectByUserNameAndManagerId" parameterType="map" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
WHERE userName = #{userName} AND managerId = #{managerId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据企业ID查询负责人信息 --> |
||||
|
<select id="selectManagersByEnterpriseId" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有负责人信息 --> |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
|
||||
|
<!-- 分页查询负责人信息 --> |
||||
|
<select id="selectAllManagersWithPagination" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
ORDER BY userName |
||||
|
LIMIT #{limit} OFFSET #{offset} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据负责人姓名查询 --> |
||||
|
<select id="selectByUserName" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE userName = #{userName} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 插入负责人信息 --> |
||||
|
<insert id="insertManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
INSERT INTO managers ( |
||||
|
id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, |
||||
|
userName, assistant |
||||
|
) VALUES ( |
||||
|
#{id}, #{managerId}, #{managercompany}, #{managerdepartment}, |
||||
|
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at}, |
||||
|
#{userName}, #{assistant} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 更新负责人信息 --> |
||||
|
<update id="updateManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
UPDATE managers |
||||
|
SET |
||||
|
managercompany = #{managercompany}, |
||||
|
managerdepartment = #{managerdepartment}, |
||||
|
organization = #{organization}, |
||||
|
role = #{role}, |
||||
|
userName = #{userName}, |
||||
|
assistant = #{assistant}, |
||||
|
updated_at = #{updated_at} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
</mapper> |
||||
|
``` |
||||
|
|
||||
|
### 优化UsersMapper接口添加分页方法 |
||||
|
|
||||
|
在UsersMapper.java中添加分页查询方法: |
||||
|
|
||||
|
```java |
||||
|
// 分页查询授权客户 |
||||
|
List<UserProductCartDTO> getAuthorizedCustomersWithPagination(Map<String, Object> params); |
||||
|
|
||||
|
// 获取授权客户总数 |
||||
|
int getAuthorizedCustomersCount(Map<String, Object> params); |
||||
|
``` |
||||
|
|
||||
|
## 验证优化效果 |
||||
|
|
||||
|
优化后,建议通过以下方式验证性能改进: |
||||
|
|
||||
|
1. **使用EXPLAIN分析SQL执行计划** |
||||
|
```sql |
||||
|
EXPLAIN SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE userName = 'someName'; |
||||
|
``` |
||||
|
|
||||
|
2. **添加性能监控日志** |
||||
|
在Service层添加方法执行时间记录。 |
||||
|
|
||||
|
3. **压力测试** |
||||
|
使用JMeter等工具进行压力测试,比较优化前后的响应时间。 |
||||
|
|
||||
|
## 额外建议 |
||||
|
|
||||
|
1. **考虑读写分离** |
||||
|
对于高并发场景,考虑实现数据库读写分离。 |
||||
|
|
||||
|
2. **使用数据库连接池** |
||||
|
确保使用高效的连接池管理数据库连接。 |
||||
|
|
||||
|
3. **定期清理和优化数据库** |
||||
|
定期执行VACUUM(PostgreSQL)或OPTIMIZE TABLE(MySQL)等操作。 |
||||
|
|
||||
|
4. **考虑使用NoSQL缓存热点数据** |
||||
|
对于频繁访问的数据,可以考虑使用Redis等NoSQL数据库进行缓存。 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
此优化指南由自动化工具生成,建议根据实际情况进行调整和测试。 |
||||
@ -0,0 +1,118 @@ |
|||||
|
# TOMCAT 10.1.48 DEPLOYMENT STEPS |
||||
|
|
||||
|
## PREREQUISITES |
||||
|
1. Tomcat 10.1.48 installed at /opt/tomcat |
||||
|
2. JDK 17 or higher installed on the server |
||||
|
3. Generated DL.war file in target directory |
||||
|
|
||||
|
## DEPLOYMENT STEPS |
||||
|
|
||||
|
### 1. Prepare Deployment File |
||||
|
The DL.war file has been successfully created and is ready for deployment. |
||||
|
|
||||
|
### 2. Upload WAR File to Server |
||||
|
|
||||
|
```bash |
||||
|
# From Windows using WinSCP or FileZilla: |
||||
|
# - Connect to your server |
||||
|
# - Upload d:\java\project\web(8)\web\target\DL.war to /opt/tomcat/webapps/ |
||||
|
|
||||
|
# Or from command line using scp (open Command Prompt as Administrator): |
||||
|
scp "d:\java\project\web(8)\web\target\DL.war" user@your-server:/opt/tomcat/webapps/ |
||||
|
``` |
||||
|
|
||||
|
### 3. Set Permissions on Server |
||||
|
|
||||
|
Connect to your server via SSH and run: |
||||
|
|
||||
|
```bash |
||||
|
cd /opt/tomcat |
||||
|
sudo chown -R tomcat:tomcat webapps/ |
||||
|
sudo chmod -R 755 webapps/ |
||||
|
``` |
||||
|
|
||||
|
### 4. Configure Tomcat (Recommended) |
||||
|
|
||||
|
```bash |
||||
|
# Edit context.xml to prevent resource locking issues |
||||
|
sudo nano /opt/tomcat/conf/context.xml |
||||
|
|
||||
|
# Add antiResourceLocking and antiJARLocking attributes to Context element |
||||
|
<Context antiResourceLocking="true" antiJARLocking="true"> |
||||
|
<!-- keep existing configuration --> |
||||
|
</Context> |
||||
|
|
||||
|
# Save and exit (Ctrl+O, Enter, Ctrl+X) |
||||
|
|
||||
|
# Create setenv.sh for memory optimization |
||||
|
sudo nano /opt/tomcat/bin/setenv.sh |
||||
|
|
||||
|
# Add these lines: |
||||
|
#!/bin/bash |
||||
|
JAVA_OPTS="-Xms512m -Xmx1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" |
||||
|
JAVA_OPTS="$JAVA_OPTS --add-opens=java.base/java.lang=ALL-UNNAMED" |
||||
|
|
||||
|
# Save and exit |
||||
|
|
||||
|
# Make it executable |
||||
|
sudo chmod +x /opt/tomcat/bin/setenv.sh |
||||
|
``` |
||||
|
|
||||
|
### 5. Restart Tomcat |
||||
|
|
||||
|
```bash |
||||
|
cd /opt/tomcat/bin |
||||
|
|
||||
|
# Stop Tomcat |
||||
|
sudo ./shutdown.sh |
||||
|
|
||||
|
# Wait for Tomcat to stop completely |
||||
|
sleep 30 |
||||
|
|
||||
|
# Start Tomcat |
||||
|
sudo ./startup.sh |
||||
|
``` |
||||
|
|
||||
|
### 6. Verify Deployment |
||||
|
|
||||
|
```bash |
||||
|
# Monitor Tomcat logs |
||||
|
tail -f /opt/tomcat/logs/catalina.out |
||||
|
|
||||
|
# Access the application in a browser |
||||
|
# http://your-server-ip:8080/DL |
||||
|
# http://your-server-ip:8080/DL/loginmm.html (for login page) |
||||
|
``` |
||||
|
|
||||
|
## TROUBLESHOOTING |
||||
|
|
||||
|
1. **Application not accessible**: |
||||
|
- Check if Tomcat is running: `ps aux | grep tomcat` |
||||
|
- Verify WAR file was deployed: `ls -la /opt/tomcat/webapps/` |
||||
|
- Look for errors in logs: `cat /opt/tomcat/logs/catalina.out` |
||||
|
|
||||
|
2. **Database connection issues**: |
||||
|
- Ensure database server is reachable from Tomcat server |
||||
|
- Verify database credentials in application.yaml |
||||
|
|
||||
|
3. **Port conflicts**: |
||||
|
- If port 8080 is in use, change it in server.xml: |
||||
|
`sudo nano /opt/tomcat/conf/server.xml` |
||||
|
Find and modify: `<Connector port="8080" ...` |
||||
|
|
||||
|
4. **Tomcat 10 compatibility issues**: |
||||
|
- Tomcat 10 uses Jakarta EE (jakarta.* packages instead of javax.*) |
||||
|
- Ensure all dependencies are compatible with Jakarta EE |
||||
|
|
||||
|
## UPDATING THE APPLICATION |
||||
|
|
||||
|
1. Stop Tomcat: `sudo /opt/tomcat/bin/shutdown.sh` |
||||
|
2. Remove old deployment: `sudo rm -rf /opt/tomcat/webapps/DL*` |
||||
|
3. Upload new DL.war file |
||||
|
4. Start Tomcat: `sudo /opt/tomcat/bin/startup.sh` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
DEPLOYMENT GUIDE CREATED: 2024 |
||||
|
Tomcat Version: 10.1.48 |
||||
|
Application Context: DL |
||||
@ -0,0 +1,123 @@ |
|||||
|
# 更新部署指南:Controller类文件更新 |
||||
|
|
||||
|
## 已完成的工作 |
||||
|
|
||||
|
✅ **Controller代码编译完成**: |
||||
|
- 所有更新后的Controller代码已成功编译成class文件 |
||||
|
- 生成时间:2025/11/6 13:41 |
||||
|
- 所有8个Controller类文件均已更新: |
||||
|
- CustomerController.class |
||||
|
- EnterpriseController.class |
||||
|
- LoginController.class |
||||
|
- PoolCustomerController.class |
||||
|
- SupplyCustomerController.class |
||||
|
- SupplyCustomerRecycleController.class |
||||
|
- SupplyEnterpriseController.class |
||||
|
- SupplyPoolCustomerController.class |
||||
|
|
||||
|
✅ **WAR文件已准备就绪**: |
||||
|
- 已更新的WAR文件:`target\DL.war` |
||||
|
|
||||
|
## 更新部署步骤 |
||||
|
|
||||
|
### 方法1:直接部署整个WAR文件(推荐) |
||||
|
|
||||
|
1. **上传新的WAR文件到服务器**: |
||||
|
```bash |
||||
|
# 使用scp命令上传 |
||||
|
scp "d:\java\project\web(8)\web\target\DL.war" user@your-server:/opt/tomcat/webapps/ |
||||
|
``` |
||||
|
|
||||
|
2. **设置正确权限**: |
||||
|
```bash |
||||
|
cd /opt/tomcat |
||||
|
sudo chown -R tomcat:tomcat webapps/ |
||||
|
sudo chmod -R 755 webapps/ |
||||
|
``` |
||||
|
|
||||
|
3. **重启Tomcat以加载新代码**: |
||||
|
```bash |
||||
|
cd /opt/tomcat/bin |
||||
|
sudo ./shutdown.sh |
||||
|
sleep 30 |
||||
|
sudo ./startup.sh |
||||
|
``` |
||||
|
|
||||
|
### 方法2:只更新Controller的class文件(可选,风险较高) |
||||
|
|
||||
|
如果只想更新controller的class文件而不重新部署整个WAR: |
||||
|
|
||||
|
1. **找出Tomcat中已解压的应用目录**: |
||||
|
```bash |
||||
|
cd /opt/tomcat/webapps/DL/WEB-INF/classes/com/example/web/controller |
||||
|
``` |
||||
|
|
||||
|
2. **备份当前的controller文件**: |
||||
|
```bash |
||||
|
mkdir -p backup |
||||
|
cp *.class backup/ |
||||
|
``` |
||||
|
|
||||
|
3. **上传新的controller class文件**: |
||||
|
```bash |
||||
|
# 本地准备命令 |
||||
|
# 创建临时目录复制所有controller文件 |
||||
|
mkdir -p temp_controller |
||||
|
cp target\classes\com\example\web\controller\*.class temp_controller\ |
||||
|
|
||||
|
# 然后将整个目录上传 |
||||
|
scp -r temp_controller user@your-server:/opt/tomcat/webapps/DL/WEB-INF/classes/com/example/web/ |
||||
|
|
||||
|
# 服务器上执行 |
||||
|
cd /opt/tomcat/webapps/DL/WEB-INF/classes/com/example/web/ |
||||
|
mv temp_controller/* controller/ |
||||
|
rmdir temp_controller |
||||
|
``` |
||||
|
|
||||
|
4. **设置权限**: |
||||
|
```bash |
||||
|
sudo chown tomcat:tomcat controller/*.class |
||||
|
sudo chmod 644 controller/*.class |
||||
|
``` |
||||
|
|
||||
|
5. **重启Tomcat**(即使只更新class文件,为确保线程安全也建议重启): |
||||
|
```bash |
||||
|
cd /opt/tomcat/bin |
||||
|
sudo ./shutdown.sh |
||||
|
sleep 30 |
||||
|
sudo ./startup.sh |
||||
|
``` |
||||
|
|
||||
|
## 验证部署 |
||||
|
|
||||
|
1. **检查Tomcat日志确认部署成功**: |
||||
|
```bash |
||||
|
tail -f /opt/tomcat/logs/catalina.out |
||||
|
``` |
||||
|
|
||||
|
2. **验证应用是否正常运行**: |
||||
|
- 访问:http://服务器IP:8080/DL |
||||
|
- 尝试使用更新的Controller功能 |
||||
|
|
||||
|
## 回滚方案 |
||||
|
|
||||
|
如果更新出现问题,可以快速回滚: |
||||
|
|
||||
|
1. **方法1回滚**:删除新WAR文件,恢复旧WAR文件 |
||||
|
```bash |
||||
|
cd /opt/tomcat/webapps |
||||
|
sudo rm -rf DL.war DL/ |
||||
|
sudo cp backup/DL.war . |
||||
|
sudo ./bin/startup.sh |
||||
|
``` |
||||
|
|
||||
|
2. **方法2回滚**: |
||||
|
```bash |
||||
|
cd /opt/tomcat/webapps/DL/WEB-INF/classes/com/example/web/controller |
||||
|
cp backup/*.class . |
||||
|
sudo ./opt/tomcat/bin/startup.sh |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**注意**:推荐使用方法1完整部署WAR文件,以确保所有依赖关系正确加载,避免潜在的类加载问题。 |
||||
@ -0,0 +1,47 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
rem ================================================== |
||||
|
rem 性能优化部署脚本 |
||||
|
rem 此脚本用于部署数据库索引和更新Mapper XML文件 |
||||
|
rem ================================================== |
||||
|
|
||||
|
echo 开始部署性能优化更改... |
||||
|
|
||||
|
rem 1. 编译项目,确保最新的Mapper XML文件被打包 |
||||
|
echo 正在编译项目... |
||||
|
mvn clean package -DskipTests |
||||
|
|
||||
|
if %ERRORLEVEL% NEQ 0 ( |
||||
|
echo 编译失败,请检查错误信息! |
||||
|
pause |
||||
|
exit /b 1 |
||||
|
) |
||||
|
|
||||
|
rem 2. 提示用户执行数据库索引脚本 |
||||
|
echo. |
||||
|
echo ================================================== |
||||
|
echo 请在数据库中执行以下脚本创建必要的索引: |
||||
|
echo CREATE_OPTIMIZATION_INDEXES.sql |
||||
|
echo ================================================== |
||||
|
echo. |
||||
|
pause |
||||
|
|
||||
|
rem 3. 部署更新后的WAR文件 |
||||
|
echo. |
||||
|
echo 正在复制WAR文件到部署目录... |
||||
|
copy target\web-0.0.1-SNAPSHOT.war DL.war |
||||
|
|
||||
|
if %ERRORLEVEL% NEQ 0 ( |
||||
|
echo WAR文件复制失败! |
||||
|
pause |
||||
|
exit /b 1 |
||||
|
) |
||||
|
|
||||
|
echo 部署完成!请按照以下步骤进行: |
||||
|
echo 1. 将DL.war文件上传到Tomcat的webapps目录 |
||||
|
echo 2. 重启Tomcat服务器 |
||||
|
echo 3. 验证应用性能是否有所改善 |
||||
|
|
||||
|
echo. |
||||
|
echo 性能优化部署脚本执行完毕! |
||||
|
pause |
||||
@ -0,0 +1,59 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
cls |
||||
|
|
||||
|
echo Spring Boot应用部署到Tomcat 10.1.48 |
||||
|
==================================== |
||||
|
|
||||
|
:: 简单版本,避免复杂路径操作 |
||||
|
set "SOURCE_WAR=target\web-0.0.1-SNAPSHOT.war" |
||||
|
set "TARGET_WAR=target\DL.war" |
||||
|
|
||||
|
:: 检查源文件是否存在 |
||||
|
if not exist "%SOURCE_WAR%" ( |
||||
|
echo 错误: 找不到源WAR文件 |
||||
|
echo 请先运行 'mvn clean package -DskipTests' 构建项目 |
||||
|
pause |
||||
|
exit /b 1 |
||||
|
) |
||||
|
|
||||
|
:: 复制文件(使用基本copy命令) |
||||
|
echo 正在准备部署文件... |
||||
|
copy "%SOURCE_WAR%" "%TARGET_WAR%" |
||||
|
|
||||
|
:: 检查复制是否成功 |
||||
|
if exist "%TARGET_WAR%" ( |
||||
|
echo 文件准备成功! |
||||
|
|
||||
|
echo. |
||||
|
echo ====== Tomcat部署步骤 ====== |
||||
|
echo 1. 上传文件: |
||||
|
echo 请将 "%TARGET_WAR%" 上传到服务器的 /opt/tomcat/webapps/ 目录 |
||||
|
echo 推荐使用WinSCP或FileZilla进行上传 |
||||
|
echo. |
||||
|
echo 2. 设置服务器权限: |
||||
|
echo 连接到服务器后执行以下命令: |
||||
|
echo cd /opt/tomcat |
||||
|
echo sudo chown -R tomcat:tomcat webapps/ |
||||
|
echo sudo chmod -R 755 webapps/ |
||||
|
echo. |
||||
|
echo 3. 重启Tomcat: |
||||
|
echo cd /opt/tomcat/bin |
||||
|
echo sudo ./shutdown.sh |
||||
|
echo sleep 30 |
||||
|
echo sudo ./startup.sh |
||||
|
echo. |
||||
|
echo 4. 验证部署: |
||||
|
echo 访问: http://服务器IP:8080/DL |
||||
|
echo 查看日志: tail -f /opt/tomcat/logs/catalina.out |
||||
|
echo. |
||||
|
echo 重要说明: |
||||
|
echo - 确保服务器上的Tomcat版本为10.1.48 |
||||
|
echo - 确保数据库连接信息正确 |
||||
|
echo - 如有问题,请查看Tomcat日志文件 |
||||
|
) else ( |
||||
|
echo 错误: 文件准备失败 |
||||
|
) |
||||
|
|
||||
|
echo. |
||||
|
pause |
||||
@ -0,0 +1,56 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
# Spring Boot应用部署到Tomcat 10.1.48脚本 |
||||
|
# 避免路径中的括号导致的bash语法错误 |
||||
|
|
||||
|
echo "===== Spring Boot应用部署到Tomcat 10.1.48 =====" |
||||
|
|
||||
|
# 进入项目目录(使用相对路径避免括号问题) |
||||
|
cd "$(dirname "$0")" |
||||
|
PROJECT_DIR="$(pwd)" |
||||
|
WAR_SOURCE="${PROJECT_DIR}/target/web-0.0.1-SNAPSHOT.war" |
||||
|
WAR_TARGET="${PROJECT_DIR}/target/DL.war" |
||||
|
|
||||
|
echo "项目目录: $PROJECT_DIR" |
||||
|
echo "源WAR文件: $WAR_SOURCE" |
||||
|
echo "目标WAR文件: $WAR_TARGET" |
||||
|
|
||||
|
# 检查源WAR文件是否存在 |
||||
|
if [ ! -f "$WAR_SOURCE" ]; then |
||||
|
echo "错误: 找不到源WAR文件 $WAR_SOURCE" |
||||
|
echo "请先运行 'mvn clean package -DskipTests' 构建项目" |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
# 复制并重命名WAR文件 |
||||
|
echo "正在复制并重命名WAR文件..." |
||||
|
cp "$WAR_SOURCE" "$WAR_TARGET" |
||||
|
|
||||
|
if [ $? -eq 0 ]; then |
||||
|
echo "WAR文件重命名成功!" |
||||
|
echo " |
||||
|
部署步骤: |
||||
|
1. 上传WAR文件到服务器:" |
||||
|
echo " scp "$WAR_TARGET" user@your-server:/opt/tomcat/webapps/" |
||||
|
echo " |
||||
|
2. 在服务器上设置权限:" |
||||
|
echo " cd /opt/tomcat" |
||||
|
echo " sudo chown -R tomcat:tomcat webapps/" |
||||
|
echo " sudo chmod -R 755 webapps/" |
||||
|
echo " |
||||
|
3. 重启Tomcat:" |
||||
|
echo " cd /opt/tomcat/bin" |
||||
|
echo " sudo ./shutdown.sh" |
||||
|
echo " sleep 30" |
||||
|
echo " sudo ./startup.sh" |
||||
|
echo " |
||||
|
4. 验证部署:" |
||||
|
echo " 访问 http://your-server-ip:8080/DL" |
||||
|
echo " 查看日志: tail -f /opt/tomcat/logs/catalina.out" |
||||
|
else |
||||
|
echo "错误: WAR文件复制失败" |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
echo " |
||||
|
===== 部署准备完成 =====" |
||||
@ -0,0 +1,69 @@ |
|||||
|
@echo off |
||||
|
|
||||
|
rem ==================================================== |
||||
|
rem 部署脚本 - 包含性能优化部署步骤 |
||||
|
rem 版本:2.0 |
||||
|
rem 日期:2024 |
||||
|
rem ==================================================== |
||||
|
|
||||
|
echo 开始Spring Boot应用部署流程(含性能优化)... |
||||
|
|
||||
|
rem 1. 设置变量 |
||||
|
set "WAR_FILE=target\web-0.0.1-SNAPSHOT.war" |
||||
|
set "DEPLOY_WAR=target\DL.war" |
||||
|
set "BACKUP_DIR=d:\java\project\web(8)\web\backup" |
||||
|
set "INDEX_SCRIPT=CREATE_OPTIMIZATION_INDEXES.sql" |
||||
|
|
||||
|
rem 2. 检查WAR文件是否存在 |
||||
|
if not exist "%WAR_FILE%" ( |
||||
|
echo 错误:WAR文件不存在,请先执行 mvn clean package -DskipTests |
||||
|
pause |
||||
|
exit /b 1 |
||||
|
) |
||||
|
|
||||
|
echo 找到WAR文件:%WAR_FILE% |
||||
|
|
||||
|
rem 3. 创建备份目录 |
||||
|
if not exist "%BACKUP_DIR%" mkdir "%BACKUP_DIR%" |
||||
|
echo 创建备份目录:%BACKUP_DIR% |
||||
|
|
||||
|
rem 4. 重命名WAR文件 |
||||
|
copy "%WAR_FILE%" "%DEPLOY_WAR%" > nul |
||||
|
if %errorlevel% neq 0 ( |
||||
|
echo 错误:重命名WAR文件失败 |
||||
|
pause |
||||
|
exit /b 1 |
||||
|
) |
||||
|
echo 已将WAR文件重命名为:%DEPLOY_WAR% |
||||
|
|
||||
|
rem 5. 复制索引脚本到备份目录 |
||||
|
if exist "%INDEX_SCRIPT%" ( |
||||
|
copy "%INDEX_SCRIPT%" "%BACKUP_DIR%\%INDEX_SCRIPT%" > nul |
||||
|
echo 已复制数据库索引脚本到备份目录 |
||||
|
) |
||||
|
|
||||
|
rem 6. 提示数据库索引优化步骤 |
||||
|
echo. |
||||
|
echo ==================================== |
||||
|
echo 数据库索引优化(重要) |
||||
|
echo ==================================== |
||||
|
echo 请在数据库服务器上执行以下操作: |
||||
|
echo 1. 登录数据库服务器 |
||||
|
echo 2. 执行索引创建脚本: |
||||
|
echo source %BACKUP_DIR%\%INDEX_SCRIPT% |
||||
|
echo 或直接复制脚本内容执行 |
||||
|
|
||||
|
echo. |
||||
|
echo ==================================== |
||||
|
echo 部署准备完成! |
||||
|
echo ==================================== |
||||
|
echo 部署文件:%DEPLOY_WAR% |
||||
|
echo 备份位置:%BACKUP_DIR% |
||||
|
echo. |
||||
|
echo 下一步操作: |
||||
|
echo 1. 上传 %DEPLOY_WAR% 到Tomcat服务器的webapps目录 |
||||
|
echo 2. 在数据库服务器上执行索引优化脚本 |
||||
|
echo 3. 重启Tomcat服务器 |
||||
|
echo 4. 验证性能优化效果 |
||||
|
echo. |
||||
|
pause |
||||
@ -0,0 +1,295 @@ |
|||||
|
#!/bin/sh |
||||
|
# ---------------------------------------------------------------------------- |
||||
|
# Licensed to the Apache Software Foundation (ASF) under one |
||||
|
# or more contributor license agreements. See the NOTICE file |
||||
|
# distributed with this work for additional information |
||||
|
# regarding copyright ownership. The ASF licenses this file |
||||
|
# to you 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. |
||||
|
# ---------------------------------------------------------------------------- |
||||
|
|
||||
|
# ---------------------------------------------------------------------------- |
||||
|
# Apache Maven Wrapper startup batch script, version 3.3.4 |
||||
|
# |
||||
|
# Optional ENV vars |
||||
|
# ----------------- |
||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source |
||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution |
||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven |
||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output |
||||
|
# ---------------------------------------------------------------------------- |
||||
|
|
||||
|
set -euf |
||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x |
||||
|
|
||||
|
# OS specific support. |
||||
|
native_path() { printf %s\\n "$1"; } |
||||
|
case "$(uname)" in |
||||
|
CYGWIN* | MINGW*) |
||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" |
||||
|
native_path() { cygpath --path --windows "$1"; } |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
# set JAVACMD and JAVACCMD |
||||
|
set_java_home() { |
||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched |
||||
|
if [ -n "${JAVA_HOME-}" ]; then |
||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then |
||||
|
# IBM's JDK on AIX uses strange locations for the executables |
||||
|
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac" |
||||
|
else |
||||
|
JAVACMD="$JAVA_HOME/bin/java" |
||||
|
JAVACCMD="$JAVA_HOME/bin/javac" |
||||
|
|
||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then |
||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 |
||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
else |
||||
|
JAVACMD="$( |
||||
|
'set' +e |
||||
|
'unset' -f command 2>/dev/null |
||||
|
'command' -v java |
||||
|
)" || : |
||||
|
JAVACCMD="$( |
||||
|
'set' +e |
||||
|
'unset' -f command 2>/dev/null |
||||
|
'command' -v javac |
||||
|
)" || : |
||||
|
|
||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then |
||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 |
||||
|
return 1 |
||||
|
fi |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# hash string like Java String::hashCode |
||||
|
hash_string() { |
||||
|
str="${1:-}" h=0 |
||||
|
while [ -n "$str" ]; do |
||||
|
char="${str%"${str#?}"}" |
||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) |
||||
|
str="${str#?}" |
||||
|
done |
||||
|
printf %x\\n $h |
||||
|
} |
||||
|
|
||||
|
verbose() { :; } |
||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } |
||||
|
|
||||
|
die() { |
||||
|
printf %s\\n "$1" >&2 |
||||
|
exit 1 |
||||
|
} |
||||
|
|
||||
|
trim() { |
||||
|
# MWRAPPER-139: |
||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. |
||||
|
# Needed for removing poorly interpreted newline sequences when running in more |
||||
|
# exotic environments such as mingw bash on Windows. |
||||
|
printf "%s" "${1}" | tr -d '[:space:]' |
||||
|
} |
||||
|
|
||||
|
scriptDir="$(dirname "$0")" |
||||
|
scriptName="$(basename "$0")" |
||||
|
|
||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties |
||||
|
while IFS="=" read -r key value; do |
||||
|
case "${key-}" in |
||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;; |
||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; |
||||
|
esac |
||||
|
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" |
||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" |
||||
|
|
||||
|
case "${distributionUrl##*/}" in |
||||
|
maven-mvnd-*bin.*) |
||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ |
||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in |
||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; |
||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;; |
||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;; |
||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;; |
||||
|
*) |
||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 |
||||
|
distributionPlatform=linux-amd64 |
||||
|
;; |
||||
|
esac |
||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" |
||||
|
;; |
||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; |
||||
|
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; |
||||
|
esac |
||||
|
|
||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME |
||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> |
||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" |
||||
|
distributionUrlName="${distributionUrl##*/}" |
||||
|
distributionUrlNameMain="${distributionUrlName%.*}" |
||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}" |
||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" |
||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" |
||||
|
|
||||
|
exec_maven() { |
||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : |
||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" |
||||
|
} |
||||
|
|
||||
|
if [ -d "$MAVEN_HOME" ]; then |
||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME" |
||||
|
exec_maven "$@" |
||||
|
fi |
||||
|
|
||||
|
case "${distributionUrl-}" in |
||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; |
||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; |
||||
|
esac |
||||
|
|
||||
|
# prepare tmp dir |
||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then |
||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } |
||||
|
trap clean HUP INT TERM EXIT |
||||
|
else |
||||
|
die "cannot create temp dir" |
||||
|
fi |
||||
|
|
||||
|
mkdir -p -- "${MAVEN_HOME%/*}" |
||||
|
|
||||
|
# Download and Install Apache Maven |
||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." |
||||
|
verbose "Downloading from: $distributionUrl" |
||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" |
||||
|
|
||||
|
# select .zip or .tar.gz |
||||
|
if ! command -v unzip >/dev/null; then |
||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz" |
||||
|
distributionUrlName="${distributionUrl##*/}" |
||||
|
fi |
||||
|
|
||||
|
# verbose opt |
||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' |
||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v |
||||
|
|
||||
|
# normalize http auth |
||||
|
case "${MVNW_PASSWORD:+has-password}" in |
||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; |
||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; |
||||
|
esac |
||||
|
|
||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then |
||||
|
verbose "Found wget ... using wget" |
||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" |
||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then |
||||
|
verbose "Found curl ... using curl" |
||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" |
||||
|
elif set_java_home; then |
||||
|
verbose "Falling back to use Java to download" |
||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" |
||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" |
||||
|
cat >"$javaSource" <<-END |
||||
|
public class Downloader extends java.net.Authenticator |
||||
|
{ |
||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication() |
||||
|
{ |
||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); |
||||
|
} |
||||
|
public static void main( String[] args ) throws Exception |
||||
|
{ |
||||
|
setDefault( new Downloader() ); |
||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); |
||||
|
} |
||||
|
} |
||||
|
END |
||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java |
||||
|
verbose " - Compiling Downloader.java ..." |
||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" |
||||
|
verbose " - Running Downloader.java ..." |
||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" |
||||
|
fi |
||||
|
|
||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file |
||||
|
if [ -n "${distributionSha256Sum-}" ]; then |
||||
|
distributionSha256Result=false |
||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then |
||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2 |
||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 |
||||
|
exit 1 |
||||
|
elif command -v sha256sum >/dev/null; then |
||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then |
||||
|
distributionSha256Result=true |
||||
|
fi |
||||
|
elif command -v shasum >/dev/null; then |
||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then |
||||
|
distributionSha256Result=true |
||||
|
fi |
||||
|
else |
||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 |
||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
if [ $distributionSha256Result = false ]; then |
||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 |
||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
# unzip and move |
||||
|
if command -v unzip >/dev/null; then |
||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" |
||||
|
else |
||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" |
||||
|
fi |
||||
|
|
||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name) |
||||
|
actualDistributionDir="" |
||||
|
|
||||
|
# First try the expected directory name (for regular distributions) |
||||
|
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then |
||||
|
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then |
||||
|
actualDistributionDir="$distributionUrlNameMain" |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
# If not found, search for any directory with the Maven executable (for snapshots) |
||||
|
if [ -z "$actualDistributionDir" ]; then |
||||
|
# enable globbing to iterate over items |
||||
|
set +f |
||||
|
for dir in "$TMP_DOWNLOAD_DIR"/*; do |
||||
|
if [ -d "$dir" ]; then |
||||
|
if [ -f "$dir/bin/$MVN_CMD" ]; then |
||||
|
actualDistributionDir="$(basename "$dir")" |
||||
|
break |
||||
|
fi |
||||
|
fi |
||||
|
done |
||||
|
set -f |
||||
|
fi |
||||
|
|
||||
|
if [ -z "$actualDistributionDir" ]; then |
||||
|
verbose "Contents of $TMP_DOWNLOAD_DIR:" |
||||
|
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" |
||||
|
die "Could not find Maven distribution directory in extracted archive" |
||||
|
fi |
||||
|
|
||||
|
verbose "Found extracted Maven distribution directory: $actualDistributionDir" |
||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" |
||||
|
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" |
||||
|
|
||||
|
clean || : |
||||
|
exec_maven "$@" |
||||
@ -0,0 +1,189 @@ |
|||||
|
<# : batch portion |
||||
|
@REM ---------------------------------------------------------------------------- |
||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one |
||||
|
@REM or more contributor license agreements. See the NOTICE file |
||||
|
@REM distributed with this work for additional information |
||||
|
@REM regarding copyright ownership. The ASF licenses this file |
||||
|
@REM to you under the Apache License, Version 2.0 (the |
||||
|
@REM "License"); you may not use this file except in compliance |
||||
|
@REM with the License. You may obtain a copy of the License at |
||||
|
@REM |
||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
@REM |
||||
|
@REM Unless required by applicable law or agreed to in writing, |
||||
|
@REM software distributed under the License is distributed on an |
||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
||||
|
@REM KIND, either express or implied. See the License for the |
||||
|
@REM specific language governing permissions and limitations |
||||
|
@REM under the License. |
||||
|
@REM ---------------------------------------------------------------------------- |
||||
|
|
||||
|
@REM ---------------------------------------------------------------------------- |
||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.4 |
||||
|
@REM |
||||
|
@REM Optional ENV vars |
||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution |
||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven |
||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output |
||||
|
@REM ---------------------------------------------------------------------------- |
||||
|
|
||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) |
||||
|
@SET __MVNW_CMD__= |
||||
|
@SET __MVNW_ERROR__= |
||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% |
||||
|
@SET PSModulePath= |
||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( |
||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) |
||||
|
) |
||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% |
||||
|
@SET __MVNW_PSMODULEP_SAVE= |
||||
|
@SET __MVNW_ARG0_NAME__= |
||||
|
@SET MVNW_USERNAME= |
||||
|
@SET MVNW_PASSWORD= |
||||
|
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) |
||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1 |
||||
|
@GOTO :EOF |
||||
|
: end batch / begin powershell #> |
||||
|
|
||||
|
$ErrorActionPreference = "Stop" |
||||
|
if ($env:MVNW_VERBOSE -eq "true") { |
||||
|
$VerbosePreference = "Continue" |
||||
|
} |
||||
|
|
||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties |
||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl |
||||
|
if (!$distributionUrl) { |
||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" |
||||
|
} |
||||
|
|
||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { |
||||
|
"maven-mvnd-*" { |
||||
|
$USE_MVND = $true |
||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" |
||||
|
$MVN_CMD = "mvnd.cmd" |
||||
|
break |
||||
|
} |
||||
|
default { |
||||
|
$USE_MVND = $false |
||||
|
$MVN_CMD = $script -replace '^mvnw','mvn' |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME |
||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash> |
||||
|
if ($env:MVNW_REPOURL) { |
||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } |
||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" |
||||
|
} |
||||
|
$distributionUrlName = $distributionUrl -replace '^.*/','' |
||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' |
||||
|
|
||||
|
$MAVEN_M2_PATH = "$HOME/.m2" |
||||
|
if ($env:MAVEN_USER_HOME) { |
||||
|
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" |
||||
|
} |
||||
|
|
||||
|
if (-not (Test-Path -Path $MAVEN_M2_PATH)) { |
||||
|
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null |
||||
|
} |
||||
|
|
||||
|
$MAVEN_WRAPPER_DISTS = $null |
||||
|
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { |
||||
|
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" |
||||
|
} else { |
||||
|
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" |
||||
|
} |
||||
|
|
||||
|
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" |
||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' |
||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" |
||||
|
|
||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { |
||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" |
||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" |
||||
|
exit $? |
||||
|
} |
||||
|
|
||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { |
||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" |
||||
|
} |
||||
|
|
||||
|
# prepare tmp dir |
||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile |
||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" |
||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null |
||||
|
trap { |
||||
|
if ($TMP_DOWNLOAD_DIR.Exists) { |
||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } |
||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null |
||||
|
|
||||
|
# Download and Install Apache Maven |
||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." |
||||
|
Write-Verbose "Downloading from: $distributionUrl" |
||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" |
||||
|
|
||||
|
$webclient = New-Object System.Net.WebClient |
||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { |
||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) |
||||
|
} |
||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null |
||||
|
|
||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file |
||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum |
||||
|
if ($distributionSha256Sum) { |
||||
|
if ($USE_MVND) { |
||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." |
||||
|
} |
||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash |
||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { |
||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# unzip and move |
||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null |
||||
|
|
||||
|
# Find the actual extracted directory name (handles snapshots where filename != directory name) |
||||
|
$actualDistributionDir = "" |
||||
|
|
||||
|
# First try the expected directory name (for regular distributions) |
||||
|
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" |
||||
|
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" |
||||
|
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { |
||||
|
$actualDistributionDir = $distributionUrlNameMain |
||||
|
} |
||||
|
|
||||
|
# If not found, search for any directory with the Maven executable (for snapshots) |
||||
|
if (!$actualDistributionDir) { |
||||
|
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { |
||||
|
$testPath = Join-Path $_.FullName "bin/$MVN_CMD" |
||||
|
if (Test-Path -Path $testPath -PathType Leaf) { |
||||
|
$actualDistributionDir = $_.Name |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!$actualDistributionDir) { |
||||
|
Write-Error "Could not find Maven distribution directory in extracted archive" |
||||
|
} |
||||
|
|
||||
|
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" |
||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null |
||||
|
try { |
||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null |
||||
|
} catch { |
||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { |
||||
|
Write-Error "fail to move MAVEN_HOME" |
||||
|
} |
||||
|
} finally { |
||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } |
||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } |
||||
|
} |
||||
|
|
||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" |
||||
@ -0,0 +1,153 @@ |
|||||
|
<?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> |
||||
|
<parent> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-parent</artifactId> |
||||
|
<version>3.4.10</version> |
||||
|
<relativePath/> <!-- lookup parent from repository --> |
||||
|
</parent> |
||||
|
<groupId>com.example</groupId> |
||||
|
<artifactId>web</artifactId> |
||||
|
<version>0.0.1-SNAPSHOT</version> |
||||
|
<packaging>war</packaging> |
||||
|
<name>web</name> |
||||
|
<description>web</description> |
||||
|
|
||||
|
<properties> |
||||
|
<java.version>17</java.version> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>me.paulschwarz</groupId> |
||||
|
<artifactId>spring-dotenv</artifactId> |
||||
|
<version>4.0.0</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-devtools</artifactId> |
||||
|
<scope>runtime</scope> |
||||
|
<optional>true</optional> |
||||
|
</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.24</version> <!-- 使用最新稳定版 --> |
||||
|
<optional>true</optional> |
||||
|
</dependency> |
||||
|
|
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-tomcat</artifactId> |
||||
|
<scope>provided</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||
|
<scope>test</scope> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- MyBatis Spring Boot Starter --> |
||||
|
<dependency> |
||||
|
<groupId>org.mybatis.spring.boot</groupId> |
||||
|
<artifactId>mybatis-spring-boot-starter</artifactId> |
||||
|
<version>3.0.4</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- Druid 连接池 --> |
||||
|
<dependency> |
||||
|
<groupId>com.alibaba</groupId> |
||||
|
<artifactId>druid-spring-boot-starter</artifactId> |
||||
|
<version>1.2.20</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- SpringDoc OpenAPI --> |
||||
|
<dependency> |
||||
|
<groupId>org.springdoc</groupId> |
||||
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> |
||||
|
<version>2.1.0</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- 配置处理器 --> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-configuration-processor</artifactId> |
||||
|
<optional>true</optional> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- AOP 依赖 --> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-aop</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
<!-- .env 文件支持 --> |
||||
|
<dependency> |
||||
|
<groupId>me.paulschwarz</groupId> |
||||
|
<artifactId>spring-dotenv</artifactId> |
||||
|
<version>4.0.0</version> |
||||
|
</dependency> |
||||
|
|
||||
|
<dependency> |
||||
|
<groupId>org.hibernate.validator</groupId> |
||||
|
<artifactId>hibernate-validator</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-starter-websocket</artifactId> |
||||
|
</dependency> |
||||
|
|
||||
|
</dependencies> |
||||
|
|
||||
|
<build> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||
|
<version>3.13.0</version> |
||||
|
<configuration> |
||||
|
<annotationProcessorPaths> |
||||
|
<path> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
</path> |
||||
|
</annotationProcessorPaths> |
||||
|
</configuration> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<groupId>org.springframework.boot</groupId> |
||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||
|
<version>3.4.10</version> |
||||
|
<configuration> |
||||
|
<excludes> |
||||
|
<exclude> |
||||
|
<groupId>org.projectlombok</groupId> |
||||
|
<artifactId>lombok</artifactId> |
||||
|
</exclude> |
||||
|
</excludes> |
||||
|
</configuration> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
</build> |
||||
|
|
||||
|
</project> |
||||
@ -0,0 +1,13 @@ |
|||||
|
package com.example.web; |
||||
|
|
||||
|
import org.springframework.boot.builder.SpringApplicationBuilder; |
||||
|
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
||||
|
|
||||
|
public class ServletInitializer extends SpringBootServletInitializer { |
||||
|
|
||||
|
@Override |
||||
|
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { |
||||
|
return application.sources(WebApplication.class); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.example.web; |
||||
|
|
||||
|
import me.paulschwarz.springdotenv.DotenvPropertySource; |
||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
import org.springframework.context.annotation.PropertySource; |
||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
|
|
||||
|
@SpringBootApplication |
||||
|
@MapperScan("com.example.web.mapper") |
||||
|
@EnableScheduling//定时任务
|
||||
|
/*@PropertySource(value = "classpath:.env", factory = DotenvPropertySource.class)*/ |
||||
|
public class WebApplication { |
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication.run(WebApplication.class, args); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// DataSource.java
|
||||
|
package com.example.web.annotation; |
||||
|
|
||||
|
import java.lang.annotation.*; |
||||
|
|
||||
|
@Target({ElementType.METHOD, ElementType.TYPE}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
@Documented |
||||
|
public @interface DataSource { |
||||
|
// 数据源名称,对应配置中的"primary"和"wechat"
|
||||
|
String value() default "primary"; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
package com.example.web.aspect; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.config.DynamicDataSource; |
||||
|
import org.aspectj.lang.ProceedingJoinPoint; |
||||
|
import org.aspectj.lang.annotation.Around; |
||||
|
import org.aspectj.lang.annotation.Aspect; |
||||
|
import org.aspectj.lang.annotation.Pointcut; |
||||
|
import org.aspectj.lang.reflect.MethodSignature; |
||||
|
import org.springframework.core.annotation.AnnotationUtils; |
||||
|
import org.springframework.core.annotation.Order; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.lang.reflect.Method; |
||||
|
|
||||
|
@Aspect |
||||
|
@Component |
||||
|
@Order(1) // 设置Order为1,确保在事务切面之前执行
|
||||
|
public class DataSourceAspect { |
||||
|
|
||||
|
// 拦截所有标注了 @DataSource 注解的类或方法
|
||||
|
@Pointcut("@annotation(com.example.web.annotation.DataSource) || @within(com.example.web.annotation.DataSource)") |
||||
|
public void dataSourcePointCut() {} |
||||
|
|
||||
|
@Around("dataSourcePointCut()") |
||||
|
public Object around(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
|
// 获取目标方法和类上的 @DataSource 注解
|
||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); |
||||
|
Method method = signature.getMethod(); |
||||
|
DataSource methodAnnotation = method.getAnnotation(DataSource.class); |
||||
|
DataSource classAnnotation = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), DataSource.class); |
||||
|
|
||||
|
// 方法注解优先于类注解
|
||||
|
String dataSourceKey = methodAnnotation != null ? methodAnnotation.value() : |
||||
|
(classAnnotation != null ? classAnnotation.value() : "primary"); |
||||
|
|
||||
|
try { |
||||
|
// 切换数据源
|
||||
|
DynamicDataSource.setDataSourceKey(dataSourceKey); |
||||
|
// 执行目标方法
|
||||
|
System.out.println("切换到数据源: " + dataSourceKey); |
||||
|
return joinPoint.proceed(); |
||||
|
} finally { |
||||
|
// 清除数据源,避免线程池复用导致的问题
|
||||
|
DynamicDataSource.clearDataSourceKey(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.boot.jdbc.DataSourceBuilder; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.context.annotation.Primary; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Configuration |
||||
|
public class DataSourceConfig { |
||||
|
|
||||
|
// 主数据源(userlogin)
|
||||
|
@Bean(name = "primaryDataSource") |
||||
|
@ConfigurationProperties(prefix = "spring.datasource.primary") |
||||
|
public DataSource primaryDataSource() { |
||||
|
return DataSourceBuilder.create().build(); |
||||
|
} |
||||
|
|
||||
|
// 第二个数据源(wechat_app)
|
||||
|
@Bean(name = "wechatDataSource") |
||||
|
@ConfigurationProperties(prefix = "spring.datasource.wechat") |
||||
|
public DataSource wechatDataSource() { |
||||
|
return DataSourceBuilder.create().build(); |
||||
|
} |
||||
|
|
||||
|
// 动态数据源配置
|
||||
|
@Primary |
||||
|
@Bean(name = "dynamicDataSource") |
||||
|
public DataSource dynamicDataSource() { |
||||
|
DynamicDataSource dynamicDataSource = new DynamicDataSource(); |
||||
|
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource()); |
||||
|
Map<Object, Object> dataSources = new HashMap<>(); |
||||
|
dataSources.put("primary", primaryDataSource()); |
||||
|
dataSources.put("wechat", wechatDataSource()); |
||||
|
dynamicDataSource.setTargetDataSources(dataSources); |
||||
|
return dynamicDataSource; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* 数据源上下文持有者 |
||||
|
*/ |
||||
|
@Component |
||||
|
public class DataSourceContextHolder { |
||||
|
|
||||
|
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); |
||||
|
|
||||
|
/** |
||||
|
* 设置数据源 |
||||
|
*/ |
||||
|
public static void setDataSource(String dataSource) { |
||||
|
CONTEXT_HOLDER.set(dataSource); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取数据源 |
||||
|
*/ |
||||
|
public static String getDataSource() { |
||||
|
return CONTEXT_HOLDER.get(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 清除数据源 |
||||
|
*/ |
||||
|
public static void clearDataSource() { |
||||
|
CONTEXT_HOLDER.remove(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// DynamicDataSource.java
|
||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; |
||||
|
|
||||
|
public class DynamicDataSource extends AbstractRoutingDataSource { |
||||
|
|
||||
|
// 线程本地变量:存储当前线程使用的数据源名称(保证线程安全)
|
||||
|
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); |
||||
|
|
||||
|
// 设置数据源(供AOP切面调用,切换数据源)
|
||||
|
public static void setDataSourceKey(String dataSourceKey) { |
||||
|
contextHolder.set(dataSourceKey); |
||||
|
} |
||||
|
|
||||
|
// 清除数据源(线程结束时调用,避免线程池复用导致的数据源混乱)
|
||||
|
public static void clearDataSourceKey() { |
||||
|
contextHolder.remove(); |
||||
|
} |
||||
|
|
||||
|
// 路由方法:返回当前线程的数据源名称(Spring会根据此方法选择对应的数据源)
|
||||
|
@Override |
||||
|
protected Object determineCurrentLookupKey() { |
||||
|
return contextHolder.get(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.apache.ibatis.session.SqlSessionFactory; |
||||
|
import org.mybatis.spring.SqlSessionFactoryBean; |
||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; |
||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
||||
|
import org.springframework.transaction.PlatformTransactionManager; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
|
||||
|
@Configuration |
||||
|
@MapperScan("com.example.web.mapper") |
||||
|
public class MyBatisConfig { |
||||
|
|
||||
|
private final DataSource dynamicDataSource; |
||||
|
|
||||
|
public MyBatisConfig(DataSource dynamicDataSource) { |
||||
|
this.dynamicDataSource = dynamicDataSource; |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public SqlSessionFactory sqlSessionFactory() throws Exception { |
||||
|
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); |
||||
|
// 设置动态数据源
|
||||
|
factoryBean.setDataSource(dynamicDataSource); |
||||
|
// 设置Mapper XML文件路径
|
||||
|
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() |
||||
|
.getResources("classpath:mapper/*.xml")); |
||||
|
return factoryBean.getObject(); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public PlatformTransactionManager transactionManager() { |
||||
|
// 使用动态数据源作为事务管理器的数据源
|
||||
|
return new DataSourceTransactionManager(dynamicDataSource); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.springframework.boot.web.servlet.ServletContextInitializer; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
|
|
||||
|
import jakarta.servlet.ServletContext; |
||||
|
import jakarta.servlet.ServletException; |
||||
|
|
||||
|
/** |
||||
|
* Tomcat 10兼容性配置类 |
||||
|
* 提供Tomcat 10兼容性支持,避免过滤器重复注册问题 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
public class TomcatCompatibilityConfig { |
||||
|
|
||||
|
/** |
||||
|
* 配置Servlet上下文参数,确保Tomcat 10兼容性 |
||||
|
*/ |
||||
|
@Bean |
||||
|
@ConditionalOnMissingBean |
||||
|
public ServletContextInitializer servletContextInitializer() { |
||||
|
return new ServletContextInitializer() { |
||||
|
@Override |
||||
|
public void onStartup(ServletContext servletContext) throws ServletException { |
||||
|
// 允许反斜杠处理
|
||||
|
servletContext.setInitParameter("org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH", "true"); |
||||
|
// 禁用严格的Servlet合规性检查
|
||||
|
servletContext.setInitParameter("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false"); |
||||
|
// 允许编码斜杠
|
||||
|
servletContext.setInitParameter("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); |
||||
|
// 添加multipart配置
|
||||
|
servletContext.setInitParameter("multipart.enabled", "true"); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
package com.example.web.config; |
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.cors.CorsConfiguration; |
||||
|
import org.springframework.web.cors.CorsConfigurationSource; |
||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
@Configuration |
||||
|
public class WebConfig implements WebMvcConfigurer { |
||||
|
|
||||
|
@Override |
||||
|
public void addCorsMappings(CorsRegistry registry) { |
||||
|
registry.addMapping("/**") |
||||
|
.allowedOrigins("*") // 允许所有域名访问,生产环境建议指定具体域名
|
||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") |
||||
|
.allowedHeaders("*") |
||||
|
.allowCredentials(false) |
||||
|
.maxAge(3600); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public CorsConfigurationSource corsConfigurationSource() { |
||||
|
CorsConfiguration configuration = new CorsConfiguration(); |
||||
|
configuration.setAllowedOrigins(Arrays.asList("*")); |
||||
|
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); |
||||
|
configuration.setAllowedHeaders(Arrays.asList("*")); |
||||
|
configuration.setAllowCredentials(false); |
||||
|
|
||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
||||
|
source.registerCorsConfiguration("/**", configuration); |
||||
|
return source; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,932 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UnifiedCustomerDTO; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.mapper.UsersManagementsMapper; |
||||
|
import com.example.web.service.CustomerService; |
||||
|
import com.example.web.service.PoolCustomerService; |
||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
|
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
/** |
||||
|
* 销售端客户管理控制器 |
||||
|
* 主要负责销售员的客户查询、更新、权限验证等操作 |
||||
|
* 路由前缀:/pool |
||||
|
*/ |
||||
|
@RestController |
||||
|
@RequestMapping("/pool") |
||||
|
@CrossOrigin(origins = "*") |
||||
|
public class CustomerController { |
||||
|
// 核心业务服务注入
|
||||
|
@Autowired |
||||
|
private CustomerService customerService; |
||||
|
|
||||
|
@Autowired |
||||
|
private PoolCustomerService poolCustomerService; |
||||
|
|
||||
|
@Autowired |
||||
|
private UsersManagementsMapper usersManagementsMapper; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 根据公司ID查询客户详情 - 优先处理wechat数据源 |
||||
|
* GET /pool/customers/{id} |
||||
|
*/ |
||||
|
@GetMapping("/customers/{id}") |
||||
|
public ResponseEntity<Map<String, Object>> getById(@PathVariable String id, HttpServletRequest request) { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🔍 查询客户: " + id); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 从URL参数中获取ManagerAuthInfo
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
|
||||
|
if (authInfo == null) { |
||||
|
System.out.println("❌ 未找到用户认证信息"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
System.out.println("✅ 获取到用户认证信息: " + authInfo.getUserName()); |
||||
|
|
||||
|
// 🎯 重构:完全基于数据存在性判断,彻底消除对ID格式的依赖
|
||||
|
System.out.println("🎯 开始查询双数据源(优先wechat)..."); |
||||
|
|
||||
|
// 1. 首先尝试查询wechat数据源
|
||||
|
System.out.println("📊 优先查询 WECHAT 数据源..."); |
||||
|
UserProductCartDTO userInfo = poolCustomerService.getPublicSeaCustomerInfo(id); |
||||
|
|
||||
|
if (userInfo != null) { |
||||
|
System.out.println("✅ 在wechat数据源中找到客户基础信息"); |
||||
|
|
||||
|
// 使用统一的公海池判断逻辑
|
||||
|
boolean isPublicSea = poolCustomerService.isPublicSeaCustomerPublic(userInfo, authInfo); |
||||
|
System.out.println("📊 公海池判断结果: " + isPublicSea); |
||||
|
|
||||
|
if (isPublicSea) { |
||||
|
System.out.println("🎯 识别为公海池客户,返回 WECHAT 数据源数据"); |
||||
|
UnifiedCustomerDTO customer = convertToUnifiedDTOForPublicSea(userInfo, request); |
||||
|
customer.setDataSource("wechat"); |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} |
||||
|
|
||||
|
// 如果不是公海池客户,检查权限并返回wechat数据源的非公海池客户
|
||||
|
System.out.println("📊 处理 WECHAT 数据源非公海池客户..."); |
||||
|
boolean hasPermission = customerService.hasPermissionToViewWechatCustomer(userInfo, authInfo); |
||||
|
|
||||
|
if (hasPermission) { |
||||
|
System.out.println("✅ 有权限查看非公海池客户,返回 WECHAT 数据源数据"); |
||||
|
UnifiedCustomerDTO customer = convertToUnifiedDTOForPublicSea(userInfo, request); |
||||
|
customer.setDataSource("wechat"); |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
System.out.println("❌ 无权限查看wechat数据源的非公海池客户"); |
||||
|
// 继续查询默认数据源
|
||||
|
} |
||||
|
} else { |
||||
|
System.out.println("ℹ️ 在wechat数据源中未找到客户"); |
||||
|
} |
||||
|
|
||||
|
// 2. 如果wechat数据源没找到或无权限,再尝试查询默认数据源
|
||||
|
System.out.println("📊 查询 DEFAULT 数据源..."); |
||||
|
UnifiedCustomerDTO defaultCustomer = customerService.getCustomerById(id, authInfo); |
||||
|
|
||||
|
if (defaultCustomer != null) { |
||||
|
System.out.println("✅ 在默认数据源中找到客户"); |
||||
|
response.put("success", true); |
||||
|
response.put("data", defaultCustomer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} |
||||
|
|
||||
|
// 3. 如果两个数据源都没找到
|
||||
|
System.out.println("❌ 未在任何数据源中找到客户信息"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "未找到对应的客户信息"); |
||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 服务器错误: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 从请求中获取ManagerAuthInfo - 增强版本,严格区分销售端和采购端 |
||||
|
*/ |
||||
|
private ManagerAuthInfo getManagerAuthInfoFromRequest(HttpServletRequest request, boolean isSupplySide) { |
||||
|
String managerId = request.getParameter("managerId"); |
||||
|
String managercompany = request.getParameter("company"); |
||||
|
String managerdepartment = request.getParameter("department"); |
||||
|
String organization = request.getParameter("organization"); |
||||
|
String role = request.getParameter("role"); |
||||
|
String userName = request.getParameter("userName"); |
||||
|
String assistant = request.getParameter("assistant"); |
||||
|
|
||||
|
// URL解码参数
|
||||
|
try { |
||||
|
if (managerId != null) managerId = java.net.URLDecoder.decode(managerId, "UTF-8"); |
||||
|
if (managercompany != null) managercompany = java.net.URLDecoder.decode(managercompany, "UTF-8"); |
||||
|
if (managerdepartment != null) managerdepartment = java.net.URLDecoder.decode(managerdepartment, "UTF-8"); |
||||
|
if (organization != null) organization = java.net.URLDecoder.decode(organization, "UTF-8"); |
||||
|
if (role != null) role = java.net.URLDecoder.decode(role, "UTF-8"); |
||||
|
if (userName != null) userName = java.net.URLDecoder.decode(userName, "UTF-8"); |
||||
|
if (assistant != null) assistant = java.net.URLDecoder.decode(assistant, "UTF-8"); |
||||
|
} catch (java.io.UnsupportedEncodingException e) { |
||||
|
System.err.println("URL解码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 检查必要参数
|
||||
|
if (userName == null || userName.trim().isEmpty()) { |
||||
|
System.out.println("❌ 用户名为空,无法获取认证信息"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 部门检查
|
||||
|
if (managerdepartment == null) { |
||||
|
System.out.println("❌ 部门信息为空"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 智能判断实际端类型:根据部门信息自动调整isSupplySide值
|
||||
|
boolean actualIsSupplySide = isSupplySide; |
||||
|
if (managerdepartment.contains("销售")) { |
||||
|
actualIsSupplySide = false; // 销售部门自动判定为销售端
|
||||
|
System.out.println("🔄 部门包含'销售',自动调整为销售端"); |
||||
|
} else if (managerdepartment.contains("采购")) { |
||||
|
actualIsSupplySide = true; // 采购部门自动判定为采购端
|
||||
|
System.out.println("🔄 部门包含'采购',自动调整为采购端"); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🔍 认证信息检查,实际端类型: " + (actualIsSupplySide ? "采购端" : "销售端") + |
||||
|
",部门: '" + managerdepartment + "'"); |
||||
|
System.out.println("✅ 认证信息检查通过"); |
||||
|
|
||||
|
// 验证公司信息一致性
|
||||
|
if (managercompany == null || managercompany.trim().isEmpty()) { |
||||
|
System.out.println("❌ 公司信息为空"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
ManagerAuthInfo authInfo = new ManagerAuthInfo( |
||||
|
managerId != null ? managerId : "", |
||||
|
managercompany != null ? managercompany : "", |
||||
|
managerdepartment != null ? managerdepartment : "", |
||||
|
organization != null ? organization : "", |
||||
|
role != null ? role : "", |
||||
|
userName, |
||||
|
assistant != null ? assistant : ""); |
||||
|
|
||||
|
// 设置实际的端类型
|
||||
|
try { |
||||
|
// 尝试通过反射或setter方法设置supplySide属性
|
||||
|
java.lang.reflect.Field field = authInfo.getClass().getDeclaredField("supplySide"); |
||||
|
field.setAccessible(true); |
||||
|
field.set(authInfo, actualIsSupplySide); |
||||
|
} catch (Exception e) { |
||||
|
System.out.println("ℹ️ 无法设置supplySide属性: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🎯 认证信息详情: " + |
||||
|
"系统类型=" + (actualIsSupplySide ? "采购端" : "销售端") + |
||||
|
", 公司=" + authInfo.getManagercompany() + |
||||
|
", 部门=" + authInfo.getManagerdepartment() + |
||||
|
", 组织=" + authInfo.getOrganization() + |
||||
|
", 角色=" + authInfo.getRole() + |
||||
|
", 负责人=" + authInfo.getUserName() + |
||||
|
", 协助人=" + authInfo.getAssistant()); |
||||
|
|
||||
|
return authInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找选中的购物车项 - 修复版本 |
||||
|
* 优先使用前端传递的选中ID,如果没有则使用第一个 |
||||
|
*/ |
||||
|
private UserProductCartDTO.CartItem findSelectedCartItem(UserProductCartDTO userInfo, String targetCartItemId) { |
||||
|
if (userInfo.getCartItems() == null || userInfo.getCartItems().isEmpty()) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 🔥 关键修复:优先使用前端传递的选中购物车项ID
|
||||
|
if (targetCartItemId != null && !targetCartItemId.trim().isEmpty()) { |
||||
|
for (UserProductCartDTO.CartItem cartItem : userInfo.getCartItems()) { |
||||
|
if (targetCartItemId.equals(cartItem.getCartItemId())) { |
||||
|
System.out.println("✅ 找到前端选中的购物车项: " + cartItem.getCartItemId()); |
||||
|
return cartItem; |
||||
|
} |
||||
|
} |
||||
|
System.out.println("⚠️ 未找到前端指定的购物车项: " + targetCartItemId); |
||||
|
} |
||||
|
|
||||
|
// 🔥 其次检查是否有标记为选中的购物车项
|
||||
|
for (UserProductCartDTO.CartItem cartItem : userInfo.getCartItems()) { |
||||
|
if (isCartItemSelected(cartItem)) { |
||||
|
System.out.println("✅ 找到标记为选中的购物车项: " + cartItem.getCartItemId()); |
||||
|
return cartItem; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 🔥 最后才返回第一个购物车项
|
||||
|
UserProductCartDTO.CartItem firstItem = userInfo.getCartItems().get(0); |
||||
|
System.out.println("🔄 使用第一个购物车项作为默认: " + firstItem.getCartItemId()); |
||||
|
return firstItem; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断购物车项是否被选中(根据业务逻辑) |
||||
|
*/ |
||||
|
private boolean isCartItemSelected(UserProductCartDTO.CartItem cartItem) { |
||||
|
// 这里可以根据业务需求实现选中逻辑
|
||||
|
// 例如:通过某个字段标识,或者外部传入的参数
|
||||
|
|
||||
|
// 临时方案:默认返回false,使用第一个购物车项
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 专门为公海池客户转换DTO的方法 - 销售端使用购物车信息(修复版本) |
||||
|
* 新增HttpServletRequest参数用于获取选中的购物车项ID |
||||
|
*/ |
||||
|
private UnifiedCustomerDTO convertToUnifiedDTOForPublicSea(UserProductCartDTO userInfo, HttpServletRequest request) { |
||||
|
UnifiedCustomerDTO dto = new UnifiedCustomerDTO(); |
||||
|
|
||||
|
// 设置用户基础信息
|
||||
|
dto.setId(userInfo.getUserId() != null ? userInfo.getUserId() : ""); |
||||
|
dto.setPhoneNumber(userInfo.getPhoneNumber() != null ? userInfo.getPhoneNumber() : ""); |
||||
|
|
||||
|
// 设置公司信息
|
||||
|
dto.setCompany(userInfo.getCompany() != null ? userInfo.getCompany() : ""); |
||||
|
dto.setRegion(userInfo.getRegion() != null ? userInfo.getRegion() : ""); |
||||
|
|
||||
|
// 设置需求和规格
|
||||
|
dto.setDemand(userInfo.getDemand() != null ? userInfo.getDemand() : ""); |
||||
|
dto.setSpec(userInfo.getSpec() != null ? userInfo.getSpec() : ""); |
||||
|
|
||||
|
// 类型转换
|
||||
|
String frontendType = convertDatabaseTypeToFrontend(userInfo.getType()); |
||||
|
dto.setType(frontendType != null ? frontendType : ""); |
||||
|
|
||||
|
dto.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : ""); |
||||
|
dto.setLevel(userInfo.getLevel() != null ? userInfo.getLevel() : "公海池"); |
||||
|
dto.setCreated_at(userInfo.getCreated_at()); |
||||
|
dto.setUpdated_at(userInfo.getUpdated_at()); |
||||
|
|
||||
|
// 关键:设置数据源标识为wechat
|
||||
|
dto.setDataSource("wechat"); |
||||
|
|
||||
|
// 设置联系人信息 - 从usersContacts获取
|
||||
|
setContactInfoSafely(dto, userInfo); |
||||
|
|
||||
|
// 设置负责人信息
|
||||
|
setManagerInfoSafely(dto, userInfo.getUserId()); |
||||
|
|
||||
|
// 设置公海需求信息 - 从购物车表获取(销售端)
|
||||
|
if (userInfo.getCartItems() != null && !userInfo.getCartItems().isEmpty()) { |
||||
|
// 🔥 关键修复:从HttpServletRequest中获取目标购物车项ID
|
||||
|
String targetCartItemId = getTargetCartItemIdFromRequest(request); |
||||
|
|
||||
|
UserProductCartDTO.CartItem selectedCartItem = findSelectedCartItem(userInfo, targetCartItemId); |
||||
|
|
||||
|
// 设置到单个字段 - 使用选中的购物车项
|
||||
|
dto.setProductName(selectedCartItem.getProductName() != null ? selectedCartItem.getProductName() : ""); |
||||
|
dto.setSpecification(selectedCartItem.getSpecification() != null ? selectedCartItem.getSpecification() : ""); |
||||
|
dto.setQuantity(selectedCartItem.getQuantity() != null ? selectedCartItem.getQuantity() : 0); |
||||
|
dto.setGrossWeight(selectedCartItem.getGrossWeight() != null ? selectedCartItem.getGrossWeight() : ""); |
||||
|
dto.setYolk(selectedCartItem.getYolk() != null ? selectedCartItem.getYolk() : ""); |
||||
|
|
||||
|
// 🔥 关键修改:设置选中的购物车项ID
|
||||
|
dto.setTargetCartItemId(selectedCartItem.getCartItemId() != null ? selectedCartItem.getCartItemId() : ""); |
||||
|
|
||||
|
// 设置customDetails为购物车信息
|
||||
|
dto.setCustomDetails(userInfo.getCartItems().toArray()); |
||||
|
|
||||
|
System.out.println("✅ 成功设置选中购物车项到DTO: " + selectedCartItem.getProductName() + |
||||
|
", 购物车项ID: " + selectedCartItem.getCartItemId() + |
||||
|
", 是否前端指定: " + (targetCartItemId != null)); |
||||
|
} else { |
||||
|
// 如果没有购物车信息,设置默认值
|
||||
|
setDefaultProductValues(dto); |
||||
|
System.out.println("⚠️ 没有购物车信息,使用默认值"); |
||||
|
} |
||||
|
|
||||
|
// 设置 cartItems 到 UnifiedCustomerDTO - 销售端关键修复
|
||||
|
if (userInfo.getCartItems() != null && !userInfo.getCartItems().isEmpty()) { |
||||
|
List<UnifiedCustomerDTO.CartItem> unifiedCartItems = userInfo.getCartItems().stream() |
||||
|
.map(cartItem -> { |
||||
|
UnifiedCustomerDTO.CartItem unifiedItem = new UnifiedCustomerDTO.CartItem(); |
||||
|
unifiedItem.setCartItemId(cartItem.getCartItemId() != null ? cartItem.getCartItemId() : ""); |
||||
|
unifiedItem.setProductId(cartItem.getProductId() != null ? cartItem.getProductId() : ""); |
||||
|
unifiedItem.setProductName(cartItem.getProductName() != null ? cartItem.getProductName() : ""); |
||||
|
unifiedItem.setSpecification(cartItem.getSpecification() != null ? cartItem.getSpecification() : ""); |
||||
|
unifiedItem.setQuantity(cartItem.getQuantity() != null ? cartItem.getQuantity() : 0); |
||||
|
unifiedItem.setGrossWeight(cartItem.getGrossWeight() != null ? cartItem.getGrossWeight() : ""); |
||||
|
unifiedItem.setYolk(cartItem.getYolk() != null ? cartItem.getYolk() : ""); |
||||
|
return unifiedItem; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
dto.setCartItems(unifiedCartItems); |
||||
|
System.out.println("✅ 成功设置 cartItems 到 UnifiedCustomerDTO,数量: " + unifiedCartItems.size()); |
||||
|
} else { |
||||
|
System.out.println("❌ 没有购物车数据可设置到 cartItems"); |
||||
|
} |
||||
|
|
||||
|
return dto; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从请求参数中获取目标购物车项ID - 完整实现 |
||||
|
*/ |
||||
|
private String getTargetCartItemIdFromRequest() { |
||||
|
try { |
||||
|
// 从当前线程的HttpServletRequest中获取请求参数
|
||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); |
||||
|
if (attributes != null) { |
||||
|
HttpServletRequest request = attributes.getRequest(); |
||||
|
|
||||
|
// 从URL查询参数中获取targetCartItemId
|
||||
|
String targetCartItemId = request.getParameter("targetCartItemId"); |
||||
|
|
||||
|
if (targetCartItemId != null && !targetCartItemId.trim().isEmpty()) { |
||||
|
System.out.println("🎯 从请求参数获取到目标购物车项ID: " + targetCartItemId); |
||||
|
return targetCartItemId.trim(); |
||||
|
} |
||||
|
|
||||
|
// 如果URL参数中没有,尝试从请求属性中获取(前端可能通过其他方式设置)
|
||||
|
Object attributeValue = request.getAttribute("targetCartItemId"); |
||||
|
if (attributeValue != null) { |
||||
|
String cartItemId = attributeValue.toString(); |
||||
|
System.out.println("🎯 从请求属性获取到目标购物车项ID: " + cartItemId); |
||||
|
return cartItemId; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("⚠️ 未从请求中获取到目标购物车项ID"); |
||||
|
return null; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取目标购物车项ID失败: " + e.getMessage()); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 重载方法:从指定的HttpServletRequest中获取目标购物车项ID |
||||
|
*/ |
||||
|
private String getTargetCartItemIdFromRequest(HttpServletRequest request) { |
||||
|
try { |
||||
|
if (request == null) { |
||||
|
System.out.println("⚠️ HttpServletRequest为null"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 1. 首先从URL查询参数中获取
|
||||
|
String targetCartItemId = request.getParameter("targetCartItemId"); |
||||
|
|
||||
|
if (targetCartItemId != null && !targetCartItemId.trim().isEmpty()) { |
||||
|
System.out.println("🎯 从URL参数获取到目标购物车项ID: " + targetCartItemId); |
||||
|
return targetCartItemId.trim(); |
||||
|
} |
||||
|
|
||||
|
// 2. 如果URL参数中没有,尝试从请求属性中获取
|
||||
|
Object attributeValue = request.getAttribute("targetCartItemId"); |
||||
|
if (attributeValue != null) { |
||||
|
String cartItemId = attributeValue.toString(); |
||||
|
System.out.println("🎯 从请求属性获取到目标购物车项ID: " + cartItemId); |
||||
|
return cartItemId; |
||||
|
} |
||||
|
|
||||
|
// 3. 尝试从Header中获取
|
||||
|
String headerValue = request.getHeader("X-Target-CartItem-Id"); |
||||
|
if (headerValue != null && !headerValue.trim().isEmpty()) { |
||||
|
System.out.println("🎯 从Header获取到目标购物车项ID: " + headerValue); |
||||
|
return headerValue.trim(); |
||||
|
} |
||||
|
|
||||
|
System.out.println("⚠️ 未从请求中获取到目标购物车项ID"); |
||||
|
return null; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取目标购物车项ID失败: " + e.getMessage()); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全设置负责人信息 |
||||
|
*/ |
||||
|
private void setManagerInfoSafely(UnifiedCustomerDTO dto, String userId) { |
||||
|
try { |
||||
|
System.out.println("🔍 查询用户负责人信息,用户ID: " + userId); |
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserId(userId); |
||||
|
|
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 找到负责人信息,设置到DTO"); |
||||
|
// 设置负责人信息到统一的DTO字段
|
||||
|
dto.setManagercompany(userManager.getManagercompany() != null ? userManager.getManagercompany() : ""); |
||||
|
dto.setManagerdepartment(userManager.getManagerdepartment() != null ? userManager.getManagerdepartment() : ""); |
||||
|
dto.setOrganization(userManager.getOrganization() != null ? userManager.getOrganization() : ""); |
||||
|
dto.setRole(userManager.getRole() != null ? userManager.getRole() : ""); |
||||
|
dto.setUserName(userManager.getUserName() != null ? userManager.getUserName() : ""); |
||||
|
dto.setAssistant(userManager.getAssistant() != null ? userManager.getAssistant() : ""); |
||||
|
|
||||
|
// 调试日志
|
||||
|
System.out.println("📝 负责人信息详情: " + |
||||
|
"公司=" + dto.getManagercompany() + |
||||
|
", 部门=" + dto.getManagerdepartment() + |
||||
|
", 组织=" + dto.getOrganization() + |
||||
|
", 角色=" + dto.getRole() + |
||||
|
", 负责人=" + dto.getUserName() + |
||||
|
", 协助人=" + dto.getAssistant()); |
||||
|
} else { |
||||
|
System.out.println("⚠️ 未找到负责人信息,用户可能为公海池客户"); |
||||
|
// 设置默认值
|
||||
|
setDefaultManagerValues(dto); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 查询负责人信息失败: " + e.getMessage()); |
||||
|
// 发生异常时设置默认值
|
||||
|
setDefaultManagerValues(dto); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置默认负责人值 |
||||
|
*/ |
||||
|
private void setDefaultManagerValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setManagercompany(""); |
||||
|
dto.setManagerdepartment(""); |
||||
|
dto.setOrganization(""); |
||||
|
dto.setRole(""); |
||||
|
dto.setUserName(""); |
||||
|
dto.setAssistant(""); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 设置默认产品值 |
||||
|
*/ |
||||
|
private void setDefaultProductValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setProductName(""); |
||||
|
dto.setVariety(""); |
||||
|
dto.setSpecification(""); |
||||
|
dto.setQuantity(0); |
||||
|
dto.setGrossWeight(""); |
||||
|
dto.setYolk(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全设置联系人信息 |
||||
|
*/ |
||||
|
private void setContactInfoSafely(UnifiedCustomerDTO dto, UserProductCartDTO userInfo) { |
||||
|
if (userInfo.getUsersContacts() != null && !userInfo.getUsersContacts().isEmpty()) { |
||||
|
UserProductCartDTO.UsersContacts contact = userInfo.getUsersContacts().get(0); |
||||
|
dto.setWechat(contact.getWechat() != null ? contact.getWechat() : ""); |
||||
|
dto.setAccount(contact.getAccount() != null ? contact.getAccount() : ""); |
||||
|
dto.setAccountNumber(contact.getAccountNumber() != null ? contact.getAccountNumber() : ""); |
||||
|
dto.setBank(contact.getBank() != null ? contact.getBank() : ""); |
||||
|
dto.setAddress(contact.getAddress() != null ? contact.getAddress() : ""); |
||||
|
} else { |
||||
|
setDefaultContactValues(dto); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置默认联系人值 |
||||
|
*/ |
||||
|
private void setDefaultContactValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setWechat(""); |
||||
|
dto.setAccount(""); |
||||
|
dto.setAccountNumber(""); |
||||
|
dto.setBank(""); |
||||
|
dto.setAddress(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数据库类型转前端类型 |
||||
|
*/ |
||||
|
private String convertDatabaseTypeToFrontend(String databaseType) { |
||||
|
if (databaseType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (databaseType) { |
||||
|
case "seller": |
||||
|
return "供应端"; |
||||
|
case "buyer": |
||||
|
return "客户端"; |
||||
|
case "both": |
||||
|
return "BOTH"; |
||||
|
default: |
||||
|
return databaseType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 以下保持原有方法不变...
|
||||
|
@GetMapping("/customers/by-phone") |
||||
|
public ResponseEntity<Map<String, Object>> getByPhone(@RequestParam String phoneNumber, HttpServletRequest request) { |
||||
|
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); |
||||
|
System.out.println("getByPhone: ---------------------------------------------------" + phoneNumber); |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
//🔥 修复:从URL参数获取认证信息
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, false); |
||||
|
|
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
UnifiedCustomerDTO customer = customerService.getCustomerByPhone(phoneNumber, authInfo); |
||||
|
|
||||
|
// 检查客户等级,如果是公海池客户,确保数据源正确
|
||||
|
if (customer != null && customer.getLevel() != null && |
||||
|
(customer.getLevel().contains("sea-pools") || "公海池".equals(customer.getLevel()))) { |
||||
|
customer.setDataSource("wechat"); |
||||
|
} |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} catch (IllegalArgumentException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} catch (RuntimeException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新基于电话号码的客户信息(专门用于公海池客户)- 销售员权限:只允许更新为buyer和both类型 |
||||
|
*/ |
||||
|
@PutMapping("/phone-customers/update") |
||||
|
public ResponseEntity<Map<String, Object>> updatePhoneCustomer(@RequestBody UnifiedCustomerDTO updatedDTO, HttpServletRequest request) { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 获取认证信息
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
System.out.println("======= 开始处理公海池客户更新(wechat数据源) ======="); |
||||
|
System.out.println("手机号: " + updatedDTO.getPhoneNumber()); |
||||
|
System.out.println("原始等级: " + updatedDTO.getLevel()); |
||||
|
System.out.println("负责人信息: " + authInfo.getUserName()); |
||||
|
|
||||
|
// 🔥 在Controller层先进行类型转换
|
||||
|
System.out.println("🔄 Controller层类型转换前: " + updatedDTO.getType()); |
||||
|
String originalType = updatedDTO.getType(); |
||||
|
String convertedType = convertCustomerTypeInController(originalType); |
||||
|
updatedDTO.setType(convertedType); |
||||
|
System.out.println("🔄 Controller层类型转换后: " + originalType + " → " + convertedType); |
||||
|
|
||||
|
System.out.println("🔐 负责人认证信息: " + |
||||
|
"公司=" + authInfo.getManagercompany() + |
||||
|
", 部门=" + authInfo.getManagerdepartment() + |
||||
|
", 组织=" + authInfo.getOrganization() + |
||||
|
", 角色=" + authInfo.getRole() + |
||||
|
", 负责人=" + authInfo.getUserName() + |
||||
|
", 协助人=" + authInfo.getAssistant()); |
||||
|
|
||||
|
// 销售员权限:校验客户类型,只允许buyer和both
|
||||
|
if (!"buyer".equals(updatedDTO.getType()) && !"both".equals(updatedDTO.getType())) { |
||||
|
System.out.println("❌ 权限校验失败:销售员只能更新为buyer或both类型,当前类型: " + updatedDTO.getType()); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "销售员权限只能更新为客户端类型客户"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
// 调用服务层 - 传递authInfo用于负责人信息更新
|
||||
|
System.out.println("🔄 调用Service更新方法..."); |
||||
|
boolean success = customerService.updatePhoneBasedCustomer(updatedDTO, authInfo); |
||||
|
|
||||
|
System.out.println("✅ Service返回结果: " + success); |
||||
|
|
||||
|
if (success) { |
||||
|
System.out.println("🎉 公海池客户信息更新成功"); |
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户信息更新成功"); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
System.out.println("❌ 公海池客户信息更新失败"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "客户信息更新失败"); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("💥 更新公海池客户信息异常: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Controller层的类型转换方法 |
||||
|
*/ |
||||
|
private String convertCustomerTypeInController(String originalType) { |
||||
|
if (originalType == null) { |
||||
|
return "buyer"; |
||||
|
} |
||||
|
|
||||
|
switch (originalType.toUpperCase()) { |
||||
|
case "BOTH": |
||||
|
return "both"; |
||||
|
case "客户端": |
||||
|
case "BUYER": |
||||
|
return "buyer"; |
||||
|
case "供应端": |
||||
|
case "SELLER": |
||||
|
return "seller"; |
||||
|
default: |
||||
|
return originalType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PutMapping("/customers/update") |
||||
|
public ResponseEntity<Map<String, Object>> updateCustomer( |
||||
|
@RequestBody UnifiedCustomerDTO updatedDTO, HttpServletRequest request) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
System.out.println("======= 🔄 开始更新非公海池客户信息(销售端) ======="); |
||||
|
System.out.println("数据源: " + updatedDTO.getDataSource()); |
||||
|
System.out.println("客户ID: " + updatedDTO.getId()); |
||||
|
System.out.println("手机号: " + updatedDTO.getPhoneNumber()); |
||||
|
System.out.println("客户类型(转换前): " + updatedDTO.getType()); |
||||
|
System.out.println("客户等级: " + updatedDTO.getLevel()); |
||||
|
System.out.println("公司: " + updatedDTO.getCompany()); |
||||
|
System.out.println("区域: " + updatedDTO.getRegion()); |
||||
|
System.out.println("昵称: " + updatedDTO.getNickName()); |
||||
|
System.out.println("微信: " + updatedDTO.getWechat()); |
||||
|
System.out.println("地址: " + updatedDTO.getAddress()); |
||||
|
|
||||
|
// 打印负责人信息
|
||||
|
System.out.println("=== 负责人信息 ==="); |
||||
|
System.out.println("负责人公司: " + updatedDTO.getManagercompany()); |
||||
|
System.out.println("负责人部门: " + updatedDTO.getManagerdepartment()); |
||||
|
System.out.println("负责人组织: " + updatedDTO.getOrganization()); |
||||
|
System.out.println("负责人角色: " + updatedDTO.getRole()); |
||||
|
System.out.println("负责人姓名: " + updatedDTO.getUserName()); |
||||
|
System.out.println("协助人: " + updatedDTO.getAssistant()); |
||||
|
|
||||
|
// 🎯 新增:数据源自动验证和修正
|
||||
|
String originalDataSource = updatedDTO.getDataSource(); |
||||
|
String verifiedDataSource = verifyAndCorrectDataSource(updatedDTO); |
||||
|
if (!originalDataSource.equals(verifiedDataSource)) { |
||||
|
System.out.println("🔄 数据源自动修正: " + originalDataSource + " → " + verifiedDataSource); |
||||
|
updatedDTO.setDataSource(verifiedDataSource); |
||||
|
} |
||||
|
|
||||
|
// 关键修复:添加客户类型转换逻辑(之前遗漏)
|
||||
|
System.out.println("🔄 Controller层类型转换前: " + updatedDTO.getType()); |
||||
|
String originalType = updatedDTO.getType(); |
||||
|
String convertedType = convertCustomerTypeInController(originalType); |
||||
|
updatedDTO.setType(convertedType); |
||||
|
System.out.println("🔄 Controller层类型转换后: " + originalType + " → " + convertedType); |
||||
|
|
||||
|
System.out.println("=== 数据验证 ==="); |
||||
|
System.out.println("手机号是否为空: " + (updatedDTO.getPhoneNumber() == null || updatedDTO.getPhoneNumber().trim().isEmpty())); |
||||
|
System.out.println("客户类型是否有效: " + ("buyer".equals(updatedDTO.getType()) || "both".equals(updatedDTO.getType()))); |
||||
|
System.out.println("========================================="); |
||||
|
|
||||
|
// 验证数据源
|
||||
|
String dataSource = updatedDTO.getDataSource(); |
||||
|
if (dataSource == null || dataSource.trim().isEmpty()) { |
||||
|
System.out.println("❌ 数据源标识不能为空,请明确指定数据源(wechat或default)"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "数据源标识不能为空,请明确指定数据源(wechat或default)"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🔄 使用验证后的数据源: " + dataSource); |
||||
|
|
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 获取认证信息
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
// 权限校验
|
||||
|
System.out.println("🔐 ====== 开始权限校验 ======"); |
||||
|
System.out.println("🔐 当前类型: " + updatedDTO.getType()); |
||||
|
if (!"buyer".equals(updatedDTO.getType()) && !"both".equals(updatedDTO.getType())) { |
||||
|
System.out.println("❌ 权限校验失败:销售员只能更新为buyer或both类型,当前类型: " + updatedDTO.getType()); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "销售员权限只能更新为客户端或双向类型客户"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
System.out.println("✅ 权限校验通过"); |
||||
|
|
||||
|
boolean success; |
||||
|
|
||||
|
// 根据数据源处理更新
|
||||
|
if ("wechat".equals(dataSource)) { |
||||
|
System.out.println("使用wechat数据源更新非公海池客户"); |
||||
|
if (updatedDTO.getPhoneNumber() == null || updatedDTO.getPhoneNumber().trim().isEmpty()) { |
||||
|
throw new IllegalArgumentException("更新微信数据源时手机号不能为空"); |
||||
|
} |
||||
|
success = customerService.updateWechatCustomer(updatedDTO, authInfo, true); |
||||
|
} else if ("default".equals(dataSource)) { |
||||
|
System.out.println("使用默认数据源更新"); |
||||
|
if (updatedDTO.getId() == null || updatedDTO.getId().trim().isEmpty()) { |
||||
|
throw new IllegalArgumentException("更新默认数据源时公司ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 关键新增:检查default数据源中客户是否存在
|
||||
|
boolean exists = customerService.checkDefaultCustomerExists(updatedDTO.getId()); |
||||
|
if (!exists) { |
||||
|
System.out.println("❌ default数据源中不存在ID为" + updatedDTO.getId() + "的客户"); |
||||
|
|
||||
|
// 尝试检查该客户是否存在于wechat数据源
|
||||
|
boolean existsInWechat = false; |
||||
|
try { |
||||
|
// 先尝试通过手机号查找
|
||||
|
if (updatedDTO.getPhoneNumber() != null && !updatedDTO.getPhoneNumber().trim().isEmpty()) { |
||||
|
System.out.println("🔍 尝试通过手机号在wechat数据源中查找客户: " + updatedDTO.getPhoneNumber()); |
||||
|
UnifiedCustomerDTO wechatCustomerDTO = customerService.getCustomerByPhone(updatedDTO.getPhoneNumber(), authInfo); |
||||
|
if (wechatCustomerDTO != null) { |
||||
|
existsInWechat = true; |
||||
|
System.out.println("✅ 在wechat数据源中找到客户"); |
||||
|
} |
||||
|
} |
||||
|
// 如果手机号查找失败,尝试通过ID查找
|
||||
|
if (!existsInWechat && updatedDTO.getId() != null && !updatedDTO.getId().trim().isEmpty()) { |
||||
|
System.out.println("🔍 尝试通过ID在wechat数据源中查找客户: " + updatedDTO.getId()); |
||||
|
UnifiedCustomerDTO wechatCustomerDTO = customerService.getWechatCustomerById(updatedDTO.getId(), authInfo); |
||||
|
if (wechatCustomerDTO != null) { |
||||
|
existsInWechat = true; |
||||
|
System.out.println("✅ 在wechat数据源中找到客户"); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("⚠️ 检查wechat数据源时出错: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
if (existsInWechat) { |
||||
|
System.out.println("🔄 自动切换到wechat数据源进行更新"); |
||||
|
updatedDTO.setDataSource("wechat"); |
||||
|
success = customerService.updateWechatCustomer(updatedDTO, authInfo, true); |
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户信息更新成功(自动切换到正确的数据源)"); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "默认数据源中未找到该客户,请检查ID或数据源是否正确"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
success = customerService.updateDefaultCustomer(updatedDTO, authInfo); |
||||
|
|
||||
|
// 新增:验证更新结果
|
||||
|
if (!success) { |
||||
|
System.out.println("❌ SQL执行成功但未更新任何记录,可能数据未变化或记录不存在"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "更新失败,未找到可更新的客户记录(可能数据无变化或ID错误)"); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} else { |
||||
|
System.out.println("❌ 不支持的数据源: " + dataSource); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "不支持的数据源: " + dataSource); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户信息更新成功"); |
||||
|
return ResponseEntity.ok(response); |
||||
|
|
||||
|
} catch (IllegalArgumentException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} catch (RuntimeException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("更新客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证并修正数据源 |
||||
|
* 根据客户ID和手机号自动检测客户实际所在的数据源 |
||||
|
*/ |
||||
|
private String verifyAndCorrectDataSource(UnifiedCustomerDTO updatedDTO) { |
||||
|
String dataSource = updatedDTO.getDataSource(); |
||||
|
String customerId = updatedDTO.getId(); |
||||
|
String phoneNumber = updatedDTO.getPhoneNumber(); |
||||
|
|
||||
|
System.out.println("🔍 开始验证数据源..."); |
||||
|
System.out.println("📱 手机号: " + phoneNumber); |
||||
|
System.out.println("🆔 客户ID: " + customerId); |
||||
|
System.out.println("📊 前端指定数据源: " + dataSource); |
||||
|
|
||||
|
// 如果已经是wechat数据源,直接返回
|
||||
|
if ("wechat".equals(dataSource)) { |
||||
|
System.out.println("✅ 数据源验证通过:wechat"); |
||||
|
return dataSource; |
||||
|
} |
||||
|
|
||||
|
// 如果指定了default数据源,但客户实际上在wechat数据源中
|
||||
|
if ("default".equals(dataSource)) { |
||||
|
try { |
||||
|
// 优先通过手机号检查wechat数据源
|
||||
|
if (phoneNumber != null && !phoneNumber.trim().isEmpty()) { |
||||
|
System.out.println("🔍 通过手机号检查wechat数据源: " + phoneNumber); |
||||
|
UserProductCartDTO wechatCustomer = poolCustomerService.getWechatCustomerByPhone(phoneNumber); |
||||
|
if (wechatCustomer != null) { |
||||
|
System.out.println("🎯 检测到客户存在于wechat数据源(通过手机号),自动修正数据源"); |
||||
|
return "wechat"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 其次通过客户ID检查wechat数据源
|
||||
|
if (customerId != null && !customerId.trim().isEmpty()) { |
||||
|
System.out.println("🔍 通过客户ID检查wechat数据源: " + customerId); |
||||
|
UserProductCartDTO wechatCustomer = poolCustomerService.getPublicSeaCustomerInfo(customerId); |
||||
|
if (wechatCustomer != null) { |
||||
|
System.out.println("🎯 检测到客户存在于wechat数据源(通过客户ID),自动修正数据源"); |
||||
|
return "wechat"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 如果wechat数据源都没找到,保持default数据源
|
||||
|
System.out.println("✅ 数据源验证通过:default(客户确实在default数据源中)"); |
||||
|
return dataSource; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 数据源验证失败: " + e.getMessage()); |
||||
|
// 发生异常时保持原数据源
|
||||
|
return dataSource; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 如果是不支持的数据源,保持原样(后续会报错)
|
||||
|
System.out.println("⚠️ 不支持的数据源类型: " + dataSource); |
||||
|
return dataSource; |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,53 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.service.FollowUpService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/api/followup") |
||||
|
public class FollowupController { |
||||
|
|
||||
|
@Autowired |
||||
|
private FollowUpService followUpService; |
||||
|
|
||||
|
/** |
||||
|
* 根据电话号码获取跟进信息 |
||||
|
* @param phoneNumber 电话号码 |
||||
|
* @param dataSource 数据源(primary或wechat) |
||||
|
* @return 跟进信息 |
||||
|
*/ |
||||
|
@GetMapping("/get") |
||||
|
public ResponseEntity<String> getFollowUp( |
||||
|
@RequestParam String phoneNumber) { |
||||
|
try { |
||||
|
String followup = followUpService.getFollowUpByPhone(phoneNumber); |
||||
|
return ResponseEntity.ok(followup); |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError().body("获取跟进信息失败:" + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存跟进信息 |
||||
|
* @param phoneNumber 电话号码 |
||||
|
* @param followup 跟进信息 |
||||
|
* @return 保存结果 |
||||
|
*/ |
||||
|
@PostMapping("/save") |
||||
|
public ResponseEntity<String> saveFollowUp( |
||||
|
@RequestParam String phoneNumber, |
||||
|
@RequestParam String followup) { |
||||
|
try { |
||||
|
boolean result = followUpService.saveFollowUp(phoneNumber, followup); |
||||
|
if (result) { |
||||
|
return ResponseEntity.ok("跟进信息保存成功"); |
||||
|
} else { |
||||
|
return ResponseEntity.badRequest().body("跟进信息保存失败"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError().body("保存跟进信息失败:" + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.service.LoginService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/") |
||||
|
public class LoginController { |
||||
|
|
||||
|
@Autowired |
||||
|
private LoginService loginService; |
||||
|
|
||||
|
@PostMapping("/logins") |
||||
|
public Map<String, Object> login(@RequestParam String projectName, |
||||
|
@RequestParam String userName, |
||||
|
@RequestParam String password) { |
||||
|
|
||||
|
System.out.println("=== Controller收到登录请求 ==="); |
||||
|
System.out.println("工位名: " + projectName + ", 用户名: " + userName + ", 密码: " + password); |
||||
|
|
||||
|
Map<String, Object> result = loginService.authenticate(projectName, userName, password); |
||||
|
|
||||
|
System.out.println("Controller返回结果: " + result); |
||||
|
System.out.println("成功状态: " + result.get("success")); |
||||
|
|
||||
|
if (result.get("success").equals(true)) { |
||||
|
System.out.println("权限等级: " + result.get("root")); |
||||
|
System.out.println("Token: " + result.get("token")); |
||||
|
System.out.println("系统类型: " + (Boolean.TRUE.equals(result.get("isSupplySide")) ? "采购端" : "销售端")); |
||||
|
Map<String, Object> user = (Map<String, Object>) result.get("user"); |
||||
|
System.out.println("用户信息: " + user); |
||||
|
} |
||||
|
System.out.println(result.get("user")); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.service.PoolCustomerService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/pool/") |
||||
|
public class PoolCustomerController { |
||||
|
|
||||
|
@Autowired |
||||
|
private PoolCustomerService poolCustomerService; |
||||
|
|
||||
|
/** |
||||
|
* 根据用户ID获取客户信息 |
||||
|
* GET /pool/customers/{userId} |
||||
|
*/ |
||||
|
@GetMapping("/customersss/{userId}") |
||||
|
public ResponseEntity<?> getCustomerById(@PathVariable String userId) { |
||||
|
try { |
||||
|
UserProductCartDTO customerInfo = poolCustomerService.getCustomerInfo(userId); |
||||
|
return ResponseEntity.ok(customerInfo); |
||||
|
} catch (IllegalArgumentException e) { |
||||
|
return ResponseEntity.badRequest().body(createErrorResponse("参数错误", e.getMessage())); |
||||
|
} catch (RuntimeException e) { |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError() |
||||
|
.body(createErrorResponse("服务器错误", "获取客户信息失败")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询客户信息(支持按类型过滤) |
||||
|
* GET /pool/customers?type=seller&page=1&size=10 |
||||
|
*/ |
||||
|
@GetMapping("/customersss") |
||||
|
public ResponseEntity<?> getCustomers( |
||||
|
@RequestParam(required = false) String type, |
||||
|
@RequestParam(defaultValue = "1") int page, |
||||
|
@RequestParam(defaultValue = "10") int size) { |
||||
|
|
||||
|
try { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
response.put("page", page); |
||||
|
response.put("size", size); |
||||
|
response.put("type", type); |
||||
|
response.put("message", "分页查询功能待实现"); |
||||
|
|
||||
|
return ResponseEntity.ok(response); |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError() |
||||
|
.body(createErrorResponse("查询失败", e.getMessage())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建统一的错误响应格式 |
||||
|
*/ |
||||
|
private Map<String, Object> createErrorResponse(String error, String message) { |
||||
|
Map<String, Object> errorResponse = new HashMap<>(); |
||||
|
errorResponse.put("error", error); |
||||
|
errorResponse.put("message", message); |
||||
|
errorResponse.put("timestamp", System.currentTimeMillis()); |
||||
|
return errorResponse; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,895 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UnifiedCustomerDTO; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.mapper.SupplyUsersManagementsMapper; |
||||
|
import com.example.web.service.SupplyCustomerService; |
||||
|
import com.example.web.service.SupplyPoolCustomerService; |
||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
|
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/supply/pool") |
||||
|
@CrossOrigin(origins = "*") |
||||
|
public class SupplyCustomerController { |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyCustomerService supplyCustomerService; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyPoolCustomerService supplyPoolCustomerService; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyUsersManagementsMapper supplyUsersManagementsMapper; |
||||
|
|
||||
|
/** |
||||
|
* 根据公司ID查询客户详情 - 优先处理wechat数据源 |
||||
|
* GET /supply/pool/customers/{id} |
||||
|
*/ |
||||
|
@GetMapping("/customers/{id}") |
||||
|
public ResponseEntity<Map<String, Object>> getById(@PathVariable String id, HttpServletRequest request) { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🔍 查询客户: " + id); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 从URL参数中获取ManagerAuthInfo
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
|
||||
|
if (authInfo == null) { |
||||
|
System.out.println("❌ 未找到用户认证信息"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
System.out.println("✅ 获取到用户认证信息: " + authInfo.getUserName()); |
||||
|
|
||||
|
// 🎯 重构:完全基于数据存在性判断,彻底消除对ID格式的依赖
|
||||
|
System.out.println("🎯 开始查询双数据源(优先wechat)..."); |
||||
|
|
||||
|
// 1. 首先尝试查询wechat数据源
|
||||
|
System.out.println("📊 优先查询 WECHAT 数据源..."); |
||||
|
UserProductCartDTO userInfo = supplyPoolCustomerService.getPublicSeaCustomerInfo(id); |
||||
|
|
||||
|
if (userInfo != null) { |
||||
|
System.out.println("✅ 在wechat数据源中找到客户基础信息"); |
||||
|
|
||||
|
// 使用统一的公海池判断逻辑
|
||||
|
boolean isPublicSea = supplyPoolCustomerService.isPublicSeaCustomerPublic(userInfo, authInfo); |
||||
|
System.out.println("📊 公海池判断结果: " + isPublicSea); |
||||
|
|
||||
|
if (isPublicSea) { |
||||
|
System.out.println("🎯 识别为公海池客户,返回 WECHAT 数据源数据"); |
||||
|
UnifiedCustomerDTO customer = convertToUnifiedDTOForPublicSea(userInfo, request); |
||||
|
customer.setDataSource("wechat"); |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} |
||||
|
|
||||
|
// 如果不是公海池客户,检查权限并返回wechat数据源的非公海池客户
|
||||
|
System.out.println("📊 处理 WECHAT 数据源非公海池客户..."); |
||||
|
boolean hasPermission = supplyCustomerService.hasPermissionToViewWechatCustomer(userInfo, authInfo); |
||||
|
|
||||
|
if (hasPermission) { |
||||
|
System.out.println("✅ 有权限查看非公海池客户,返回 WECHAT 数据源数据"); |
||||
|
UnifiedCustomerDTO customer = convertToUnifiedDTOForPublicSea(userInfo, request); |
||||
|
customer.setDataSource("wechat"); |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
System.out.println("❌ 无权限查看wechat数据源的非公海池客户"); |
||||
|
// 继续查询默认数据源
|
||||
|
} |
||||
|
} else { |
||||
|
System.out.println("ℹ️ 在wechat数据源中未找到客户"); |
||||
|
} |
||||
|
|
||||
|
// 2. 如果wechat数据源没找到或无权限,再尝试查询默认数据源
|
||||
|
System.out.println("📊 查询 DEFAULT 数据源..."); |
||||
|
UnifiedCustomerDTO defaultCustomer = supplyCustomerService.getCustomerById(id, authInfo); |
||||
|
|
||||
|
if (defaultCustomer != null) { |
||||
|
System.out.println("✅ 在默认数据源中找到客户"); |
||||
|
response.put("success", true); |
||||
|
response.put("data", defaultCustomer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} |
||||
|
|
||||
|
// 3. 如果两个数据源都没找到
|
||||
|
System.out.println("❌ 未在任何数据源中找到客户信息"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "未找到对应的客户信息"); |
||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 服务器错误: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从请求中获取ManagerAuthInfo - 增强版本,严格区分销售端和采购端 |
||||
|
*/ |
||||
|
private ManagerAuthInfo getManagerAuthInfoFromRequest(HttpServletRequest request, boolean isSupplySide) { |
||||
|
String managerId = request.getParameter("managerId"); |
||||
|
String managercompany = request.getParameter("company"); |
||||
|
String managerdepartment = request.getParameter("department"); |
||||
|
String organization = request.getParameter("organization"); |
||||
|
String role = request.getParameter("role"); |
||||
|
String userName = request.getParameter("userName"); |
||||
|
String assistant = request.getParameter("assistant"); |
||||
|
|
||||
|
// URL解码参数
|
||||
|
try { |
||||
|
if (managerId != null) managerId = java.net.URLDecoder.decode(managerId, "UTF-8"); |
||||
|
if (managercompany != null) managercompany = java.net.URLDecoder.decode(managercompany, "UTF-8"); |
||||
|
if (managerdepartment != null) managerdepartment = java.net.URLDecoder.decode(managerdepartment, "UTF-8"); |
||||
|
if (organization != null) organization = java.net.URLDecoder.decode(organization, "UTF-8"); |
||||
|
if (role != null) role = java.net.URLDecoder.decode(role, "UTF-8"); |
||||
|
if (userName != null) userName = java.net.URLDecoder.decode(userName, "UTF-8"); |
||||
|
if (assistant != null) assistant = java.net.URLDecoder.decode(assistant, "UTF-8"); |
||||
|
} catch (java.io.UnsupportedEncodingException e) { |
||||
|
System.err.println("URL解码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 检查必要参数
|
||||
|
if (userName == null || userName.trim().isEmpty()) { |
||||
|
System.out.println("❌ 用户名为空,无法获取认证信息"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 部门检查
|
||||
|
if (managerdepartment == null) { |
||||
|
System.out.println("⚠️ 部门信息为空,使用默认值"); |
||||
|
managerdepartment = ""; |
||||
|
} |
||||
|
|
||||
|
// 智能判断实际端类型:根据部门信息自动调整isSupplySide值
|
||||
|
boolean actualIsSupplySide = isSupplySide; |
||||
|
if (managerdepartment.contains("销售")) { |
||||
|
actualIsSupplySide = false; // 销售部门自动判定为销售端
|
||||
|
System.out.println("🔄 部门包含'销售',自动调整为销售端"); |
||||
|
} else if (managerdepartment.contains("采购")) { |
||||
|
actualIsSupplySide = true; // 采购部门自动判定为采购端
|
||||
|
System.out.println("🔄 部门包含'采购',自动调整为采购端"); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🔍 认证信息检查,实际端类型: " + (actualIsSupplySide ? "采购端" : "销售端") + |
||||
|
",部门: '" + managerdepartment + "'"); |
||||
|
System.out.println("✅ 认证信息检查通过"); |
||||
|
|
||||
|
// 验证公司信息一致性
|
||||
|
if (managercompany == null || managercompany.trim().isEmpty()) { |
||||
|
System.out.println("❌ 公司信息为空"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
ManagerAuthInfo authInfo = new ManagerAuthInfo( |
||||
|
managerId != null ? managerId : "", |
||||
|
managercompany != null ? managercompany : "", |
||||
|
managerdepartment != null ? managerdepartment : "", |
||||
|
organization != null ? organization : "", |
||||
|
role != null ? role : "", |
||||
|
userName, |
||||
|
assistant != null ? assistant : ""); |
||||
|
|
||||
|
// 设置实际的端类型
|
||||
|
try { |
||||
|
// 尝试通过反射或setter方法设置supplySide属性
|
||||
|
java.lang.reflect.Field field = authInfo.getClass().getDeclaredField("supplySide"); |
||||
|
field.setAccessible(true); |
||||
|
field.set(authInfo, actualIsSupplySide); |
||||
|
} catch (Exception e) { |
||||
|
System.out.println("ℹ️ 无法设置supplySide属性: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🎯 认证信息详情: " + |
||||
|
"系统类型=" + (actualIsSupplySide ? "采购端" : "销售端") + |
||||
|
", 公司=" + authInfo.getManagercompany() + |
||||
|
", 部门=" + authInfo.getManagerdepartment() + |
||||
|
", 组织=" + authInfo.getOrganization() + |
||||
|
", 角色=" + authInfo.getRole() + |
||||
|
", 负责人=" + authInfo.getUserName() + |
||||
|
", 协助人=" + authInfo.getAssistant()); |
||||
|
|
||||
|
return authInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找选中的产品项 - 修复版本 |
||||
|
* 优先使用前端传递的选中ID,如果没有则使用第一个 |
||||
|
*/ |
||||
|
private UserProductCartDTO.ProductInfo findSelectedProduct(UserProductCartDTO userInfo, String targetProductItemId) { |
||||
|
if (userInfo.getProducts() == null || userInfo.getProducts().isEmpty()) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 🔥 关键修复:优先使用前端传递的选中产品项ID
|
||||
|
if (targetProductItemId != null && !targetProductItemId.trim().isEmpty()) { |
||||
|
for (UserProductCartDTO.ProductInfo product : userInfo.getProducts()) { |
||||
|
if (targetProductItemId.equals(product.getProductId())) { |
||||
|
System.out.println("✅ 找到前端选中的产品项: " + product.getProductId()); |
||||
|
return product; |
||||
|
} |
||||
|
} |
||||
|
System.out.println("⚠️ 未找到前端指定的产品项: " + targetProductItemId); |
||||
|
} |
||||
|
|
||||
|
// 🔥 其次检查是否有标记为选中的产品项
|
||||
|
for (UserProductCartDTO.ProductInfo product : userInfo.getProducts()) { |
||||
|
if (isProductSelected(product)) { |
||||
|
System.out.println("✅ 找到标记为选中的产品项: " + product.getProductId()); |
||||
|
return product; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 🔥 最后才返回第一个产品项
|
||||
|
UserProductCartDTO.ProductInfo firstItem = userInfo.getProducts().get(0); |
||||
|
System.out.println("🔄 使用第一个产品项作为默认: " + firstItem.getProductId()); |
||||
|
return firstItem; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断产品项是否被选中(根据业务逻辑) |
||||
|
*/ |
||||
|
private boolean isProductSelected(UserProductCartDTO.ProductInfo product) { |
||||
|
// 这里可以根据业务需求实现选中逻辑
|
||||
|
// 例如:通过某个字段标识,或者外部传入的参数
|
||||
|
|
||||
|
// 临时方案:默认返回false,使用第一个产品项
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 专门为公海池客户转换DTO的方法 - 采购端使用产品信息(修复版本) |
||||
|
* 新增HttpServletRequest参数用于获取选中的产品项ID |
||||
|
*/ |
||||
|
private UnifiedCustomerDTO convertToUnifiedDTOForPublicSea(UserProductCartDTO userInfo, HttpServletRequest request) { |
||||
|
UnifiedCustomerDTO dto = new UnifiedCustomerDTO(); |
||||
|
|
||||
|
// 设置用户基础信息
|
||||
|
dto.setId(userInfo.getUserId() != null ? userInfo.getUserId() : ""); |
||||
|
dto.setPhoneNumber(userInfo.getPhoneNumber() != null ? userInfo.getPhoneNumber() : ""); |
||||
|
|
||||
|
// 设置公司信息
|
||||
|
dto.setCompany(userInfo.getCompany() != null ? userInfo.getCompany() : ""); |
||||
|
dto.setRegion(userInfo.getRegion() != null ? userInfo.getRegion() : ""); |
||||
|
|
||||
|
// 设置需求和规格
|
||||
|
dto.setDemand(userInfo.getDemand() != null ? userInfo.getDemand() : ""); |
||||
|
dto.setSpec(userInfo.getSpec() != null ? userInfo.getSpec() : ""); |
||||
|
|
||||
|
// 类型转换
|
||||
|
String frontendType = convertDatabaseTypeToFrontend(userInfo.getType()); |
||||
|
dto.setType(frontendType != null ? frontendType : ""); |
||||
|
|
||||
|
dto.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : ""); |
||||
|
dto.setLevel(userInfo.getLevel() != null ? userInfo.getLevel() : "公海池"); |
||||
|
dto.setCreated_at(userInfo.getCreated_at()); |
||||
|
dto.setUpdated_at(userInfo.getUpdated_at()); |
||||
|
|
||||
|
// 关键:设置数据源标识为wechat
|
||||
|
dto.setDataSource("wechat"); |
||||
|
|
||||
|
// 设置联系人信息 - 从usersContacts获取
|
||||
|
setContactInfoSafely(dto, userInfo); |
||||
|
|
||||
|
// 设置负责人信息
|
||||
|
setManagerInfoSafely(dto, userInfo.getUserId()); |
||||
|
|
||||
|
// 设置公海需求信息 - 从产品表获取(采购端)
|
||||
|
if (userInfo.getProducts() != null && !userInfo.getProducts().isEmpty()) { |
||||
|
// 🔥 关键修复:从HttpServletRequest中获取目标产品项ID
|
||||
|
String targetProductItemId = getTargetProductItemIdFromRequest(request); |
||||
|
|
||||
|
UserProductCartDTO.ProductInfo selectedProduct = findSelectedProduct(userInfo, targetProductItemId); |
||||
|
|
||||
|
// 设置到单个字段 - 使用选中的产品项
|
||||
|
dto.setProductName(selectedProduct.getProductName() != null ? selectedProduct.getProductName() : ""); |
||||
|
dto.setVariety(selectedProduct.getVariety() != null ? selectedProduct.getVariety() : ""); |
||||
|
dto.setSpecification(selectedProduct.getSpecification() != null ? selectedProduct.getSpecification() : ""); |
||||
|
dto.setQuantity(selectedProduct.getQuantity() != null ? selectedProduct.getQuantity() : 0); |
||||
|
dto.setGrossWeight(selectedProduct.getGrossWeight() != null ? selectedProduct.getGrossWeight() : ""); |
||||
|
dto.setYolk(selectedProduct.getYolk() != null ? selectedProduct.getYolk() : ""); |
||||
|
|
||||
|
// 🔥 关键修改:设置选中的产品项ID
|
||||
|
dto.setTargetProductItemId(selectedProduct.getProductId() != null ? selectedProduct.getProductId() : ""); |
||||
|
|
||||
|
// 设置customDetails为产品信息
|
||||
|
dto.setCustomDetails(userInfo.getProducts().toArray()); |
||||
|
|
||||
|
System.out.println("✅ 成功设置选中产品项到DTO: " + selectedProduct.getProductName() + |
||||
|
", 产品项ID: " + selectedProduct.getProductId() + |
||||
|
", 是否前端指定: " + (targetProductItemId != null)); |
||||
|
} else { |
||||
|
// 如果没有产品信息,设置默认值
|
||||
|
setDefaultProductValues(dto); |
||||
|
System.out.println("⚠️ 没有产品信息,使用默认值"); |
||||
|
} |
||||
|
|
||||
|
// 设置 productItems 到 UnifiedCustomerDTO - 采购端关键修复
|
||||
|
if (userInfo.getProducts() != null && !userInfo.getProducts().isEmpty()) { |
||||
|
List<UnifiedCustomerDTO.ProductItem> unifiedProductItems = userInfo.getProducts().stream() |
||||
|
.map(product -> { |
||||
|
UnifiedCustomerDTO.ProductItem unifiedItem = new UnifiedCustomerDTO.ProductItem(); |
||||
|
unifiedItem.setProductId(product.getProductId() != null ? product.getProductId() : ""); |
||||
|
unifiedItem.setProductName(product.getProductName() != null ? product.getProductName() : ""); |
||||
|
unifiedItem.setVariety(product.getVariety() != null ? product.getVariety() : ""); |
||||
|
unifiedItem.setSpecification(product.getSpecification() != null ? product.getSpecification() : ""); |
||||
|
unifiedItem.setQuantity(product.getQuantity() != null ? product.getQuantity() : 0); |
||||
|
unifiedItem.setGrossWeight(product.getGrossWeight() != null ? product.getGrossWeight() : ""); |
||||
|
unifiedItem.setYolk(product.getYolk() != null ? product.getYolk() : ""); |
||||
|
return unifiedItem; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
dto.setProductItems(unifiedProductItems); |
||||
|
System.out.println("✅ 成功设置 productItems 到 UnifiedCustomerDTO,数量: " + unifiedProductItems.size()); |
||||
|
} else { |
||||
|
System.out.println("❌ 没有产品数据可设置到 productItems"); |
||||
|
} |
||||
|
|
||||
|
return dto; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从请求参数中获取目标产品项ID - 完整实现 |
||||
|
*/ |
||||
|
private String getTargetProductItemIdFromRequest(HttpServletRequest request) { |
||||
|
try { |
||||
|
if (request == null) { |
||||
|
System.out.println("⚠️ HttpServletRequest为null"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 1. 首先从URL查询参数中获取
|
||||
|
String targetProductItemId = request.getParameter("targetProductItemId"); |
||||
|
|
||||
|
if (targetProductItemId != null && !targetProductItemId.trim().isEmpty()) { |
||||
|
System.out.println("🎯 从URL参数获取到目标产品项ID: " + targetProductItemId); |
||||
|
return targetProductItemId.trim(); |
||||
|
} |
||||
|
|
||||
|
// 2. 如果URL参数中没有,尝试从请求属性中获取
|
||||
|
Object attributeValue = request.getAttribute("targetProductItemId"); |
||||
|
if (attributeValue != null) { |
||||
|
String productItemId = attributeValue.toString(); |
||||
|
System.out.println("🎯 从请求属性获取到目标产品项ID: " + productItemId); |
||||
|
return productItemId; |
||||
|
} |
||||
|
|
||||
|
// 3. 尝试从Header中获取
|
||||
|
String headerValue = request.getHeader("X-Target-ProductItem-Id"); |
||||
|
if (headerValue != null && !headerValue.trim().isEmpty()) { |
||||
|
System.out.println("🎯 从Header获取到目标产品项ID: " + headerValue); |
||||
|
return headerValue.trim(); |
||||
|
} |
||||
|
|
||||
|
System.out.println("⚠️ 未从请求中获取到目标产品项ID"); |
||||
|
return null; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取目标产品项ID失败: " + e.getMessage()); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全设置负责人信息 |
||||
|
*/ |
||||
|
private void setManagerInfoSafely(UnifiedCustomerDTO dto, String userId) { |
||||
|
try { |
||||
|
System.out.println("🔍 查询用户负责人信息,用户ID: " + userId); |
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserId(userId); |
||||
|
|
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 找到负责人信息,设置到DTO"); |
||||
|
// 设置负责人信息到统一的DTO字段
|
||||
|
dto.setManagercompany(userManager.getManagercompany() != null ? userManager.getManagercompany() : ""); |
||||
|
dto.setManagerdepartment(userManager.getManagerdepartment() != null ? userManager.getManagerdepartment() : ""); |
||||
|
dto.setOrganization(userManager.getOrganization() != null ? userManager.getOrganization() : ""); |
||||
|
dto.setRole(userManager.getRole() != null ? userManager.getRole() : ""); |
||||
|
dto.setUserName(userManager.getUserName() != null ? userManager.getUserName() : ""); |
||||
|
dto.setAssistant(userManager.getAssistant() != null ? userManager.getAssistant() : ""); |
||||
|
|
||||
|
// 调试日志
|
||||
|
System.out.println("📝 负责人信息详情: " + |
||||
|
"公司=" + dto.getManagercompany() + |
||||
|
", 部门=" + dto.getManagerdepartment() + |
||||
|
", 组织=" + dto.getOrganization() + |
||||
|
", 角色=" + dto.getRole() + |
||||
|
", 负责人=" + dto.getUserName() + |
||||
|
", 协助人=" + dto.getAssistant()); |
||||
|
} else { |
||||
|
System.out.println("⚠️ 未找到负责人信息,用户可能为公海池客户"); |
||||
|
// 设置默认值
|
||||
|
setDefaultManagerValues(dto); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 查询负责人信息失败: " + e.getMessage()); |
||||
|
// 发生异常时设置默认值
|
||||
|
setDefaultManagerValues(dto); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置默认负责人值 |
||||
|
*/ |
||||
|
private void setDefaultManagerValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setManagercompany(""); |
||||
|
dto.setManagerdepartment(""); |
||||
|
dto.setOrganization(""); |
||||
|
dto.setRole(""); |
||||
|
dto.setUserName(""); |
||||
|
dto.setAssistant(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置默认产品值 |
||||
|
*/ |
||||
|
private void setDefaultProductValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setProductName(""); |
||||
|
dto.setVariety(""); |
||||
|
dto.setSpecification(""); |
||||
|
dto.setQuantity(0); |
||||
|
dto.setGrossWeight(""); |
||||
|
dto.setYolk(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全设置联系人信息 |
||||
|
*/ |
||||
|
private void setContactInfoSafely(UnifiedCustomerDTO dto, UserProductCartDTO userInfo) { |
||||
|
if (userInfo.getUsersContacts() != null && !userInfo.getUsersContacts().isEmpty()) { |
||||
|
UserProductCartDTO.UsersContacts contact = userInfo.getUsersContacts().get(0); |
||||
|
dto.setWechat(contact.getWechat() != null ? contact.getWechat() : ""); |
||||
|
dto.setAccount(contact.getAccount() != null ? contact.getAccount() : ""); |
||||
|
dto.setAccountNumber(contact.getAccountNumber() != null ? contact.getAccountNumber() : ""); |
||||
|
dto.setBank(contact.getBank() != null ? contact.getBank() : ""); |
||||
|
dto.setAddress(contact.getAddress() != null ? contact.getAddress() : ""); |
||||
|
} else { |
||||
|
setDefaultContactValues(dto); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置默认联系人值 |
||||
|
*/ |
||||
|
private void setDefaultContactValues(UnifiedCustomerDTO dto) { |
||||
|
dto.setWechat(""); |
||||
|
dto.setAccount(""); |
||||
|
dto.setAccountNumber(""); |
||||
|
dto.setBank(""); |
||||
|
dto.setAddress(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数据库类型转前端类型 |
||||
|
*/ |
||||
|
private String convertDatabaseTypeToFrontend(String databaseType) { |
||||
|
if (databaseType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (databaseType) { |
||||
|
case "seller": |
||||
|
return "供应端"; |
||||
|
case "buyer": |
||||
|
return "客户端"; |
||||
|
case "both": |
||||
|
return "BOTH"; |
||||
|
default: |
||||
|
return databaseType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号查询客户详情 |
||||
|
*/ |
||||
|
@GetMapping("/customers/by-phone") |
||||
|
public ResponseEntity<Map<String, Object>> getByPhone(@RequestParam String phoneNumber, HttpServletRequest request) { |
||||
|
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); |
||||
|
System.out.println("getByPhone: ---------------------------------------------------" + phoneNumber); |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 从URL参数获取认证信息
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
|
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
UnifiedCustomerDTO customer = supplyCustomerService.getCustomerByPhone(phoneNumber, authInfo); |
||||
|
|
||||
|
// 检查客户等级,如果是公海池客户,确保数据源正确
|
||||
|
if (customer != null && customer.getLevel() != null && |
||||
|
(customer.getLevel().contains("sea-pools") || "公海池".equals(customer.getLevel()))) { |
||||
|
customer.setDataSource("wechat"); |
||||
|
} |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("data", customer); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} catch (IllegalArgumentException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} catch (RuntimeException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新基于电话号码的客户信息(专门用于公海池客户)- 采购员权限:只允许更新为seller和both类型 |
||||
|
*/ |
||||
|
@PutMapping("/phone-customers/update") |
||||
|
public ResponseEntity<Map<String, Object>> updatePhoneCustomer(@RequestBody UnifiedCustomerDTO updatedDTO, HttpServletRequest request) { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
// 从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 获取认证信息
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
System.out.println("======= 开始处理公海池客户更新(wechat数据源)- 采购端 ======="); |
||||
|
System.out.println("手机号: " + updatedDTO.getPhoneNumber()); |
||||
|
System.out.println("原始等级: " + updatedDTO.getLevel()); |
||||
|
System.out.println("负责人信息: " + authInfo.getUserName()); |
||||
|
|
||||
|
// 🔥 在Controller层先进行类型转换
|
||||
|
System.out.println("🔄 Controller层类型转换前: " + updatedDTO.getType()); |
||||
|
String originalType = updatedDTO.getType(); |
||||
|
String convertedType = convertCustomerTypeInController(originalType); |
||||
|
updatedDTO.setType(convertedType); |
||||
|
System.out.println("🔄 Controller层类型转换后: " + originalType + " → " + convertedType); |
||||
|
|
||||
|
System.out.println("🔐 负责人认证信息: " + |
||||
|
"公司=" + authInfo.getManagercompany() + |
||||
|
", 部门=" + authInfo.getManagerdepartment() + |
||||
|
", 组织=" + authInfo.getOrganization() + |
||||
|
", 角色=" + authInfo.getRole() + |
||||
|
", 负责人=" + authInfo.getUserName() + |
||||
|
", 协助人=" + authInfo.getAssistant()); |
||||
|
|
||||
|
// 采购员权限:校验客户类型,只允许seller和both
|
||||
|
if (!"seller".equals(updatedDTO.getType()) && !"both".equals(updatedDTO.getType())) { |
||||
|
System.out.println("❌ 权限校验失败:采购员只能更新为seller或both类型,当前类型: " + updatedDTO.getType()); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "采购员权限只能更新为供应端类型客户"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
// 调用服务层 - 传递authInfo用于负责人信息更新
|
||||
|
System.out.println("🔄 调用Service更新方法..."); |
||||
|
boolean success = supplyCustomerService.updatePhoneBasedCustomer(updatedDTO, authInfo); |
||||
|
|
||||
|
System.out.println("✅ Service返回结果: " + success); |
||||
|
|
||||
|
if (success) { |
||||
|
System.out.println("🎉 公海池客户信息更新成功"); |
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户信息更新成功"); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
System.out.println("❌ 公海池客户信息更新失败"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "客户信息更新失败"); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("💥 更新公海池客户信息异常: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Controller层的类型转换方法 - 采购端 |
||||
|
*/ |
||||
|
private String convertCustomerTypeInController(String originalType) { |
||||
|
if (originalType == null) { |
||||
|
return "seller"; |
||||
|
} |
||||
|
|
||||
|
switch (originalType.toUpperCase()) { |
||||
|
case "BOTH": |
||||
|
return "both"; |
||||
|
case "客户端": |
||||
|
case "BUYER": |
||||
|
return "buyer"; |
||||
|
case "供应端": |
||||
|
case "SELLER": |
||||
|
return "seller"; |
||||
|
default: |
||||
|
return originalType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新基于电话号码的客户信息(专门用于公海池客户)- 采购员权限:只允许更新为seller和both类型 |
||||
|
*/ |
||||
|
@PutMapping("/customers/update") |
||||
|
public ResponseEntity<Map<String, Object>> updateCustomer( |
||||
|
@RequestBody UnifiedCustomerDTO updatedDTO, HttpServletRequest request) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
try { |
||||
|
System.out.println("======= 🔄 开始更新非公海池客户信息(采购端) ======="); |
||||
|
System.out.println("数据源: " + updatedDTO.getDataSource()); |
||||
|
System.out.println("客户ID: " + updatedDTO.getId()); |
||||
|
System.out.println("手机号: " + updatedDTO.getPhoneNumber()); |
||||
|
System.out.println("客户类型(转换前): " + updatedDTO.getType()); |
||||
|
System.out.println("客户等级: " + updatedDTO.getLevel()); |
||||
|
System.out.println("公司: " + updatedDTO.getCompany()); |
||||
|
System.out.println("区域: " + updatedDTO.getRegion()); |
||||
|
System.out.println("昵称: " + updatedDTO.getNickName()); |
||||
|
System.out.println("微信: " + updatedDTO.getWechat()); |
||||
|
System.out.println("地址: " + updatedDTO.getAddress()); |
||||
|
|
||||
|
// 打印负责人信息
|
||||
|
System.out.println("=== 负责人信息 ==="); |
||||
|
System.out.println("负责人公司: " + updatedDTO.getManagercompany()); |
||||
|
System.out.println("负责人部门: " + updatedDTO.getManagerdepartment()); |
||||
|
System.out.println("负责人组织: " + updatedDTO.getOrganization()); |
||||
|
System.out.println("负责人角色: " + updatedDTO.getRole()); |
||||
|
System.out.println("负责人姓名: " + updatedDTO.getUserName()); |
||||
|
System.out.println("协助人: " + updatedDTO.getAssistant()); |
||||
|
|
||||
|
// 🎯 关键修复:先进行数据源验证和修正
|
||||
|
String originalDataSource = updatedDTO.getDataSource(); |
||||
|
String verifiedDataSource = verifyAndCorrectDataSource(updatedDTO); |
||||
|
|
||||
|
if (!originalDataSource.equals(verifiedDataSource)) { |
||||
|
System.out.println("🔄 数据源自动修正: " + originalDataSource + " → " + verifiedDataSource); |
||||
|
updatedDTO.setDataSource(verifiedDataSource); |
||||
|
} |
||||
|
|
||||
|
// 🎯 关键修复:从URL参数获取用户类型,与前端保持一致
|
||||
|
String isSupplySideParam = request.getParameter("isSupplySide"); |
||||
|
boolean isSupplySide = !"false".equalsIgnoreCase(isSupplySideParam); |
||||
|
System.out.println("🎯 根据URL参数选择认证类型: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
// 获取认证信息 - 根据URL参数选择
|
||||
|
ManagerAuthInfo authInfo = getManagerAuthInfoFromRequest(request, isSupplySide); |
||||
|
if (authInfo == null) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "用户未登录或认证信息缺失"); |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); |
||||
|
} |
||||
|
|
||||
|
// 关键修复:添加客户类型转换逻辑
|
||||
|
System.out.println("🔄 Controller层类型转换前: " + updatedDTO.getType()); |
||||
|
String originalType = updatedDTO.getType(); |
||||
|
String convertedType = convertCustomerTypeInController(originalType); |
||||
|
updatedDTO.setType(convertedType); |
||||
|
System.out.println("🔄 Controller层类型转换后: " + originalType + " → " + convertedType); |
||||
|
|
||||
|
System.out.println("=== 数据验证 ==="); |
||||
|
System.out.println("手机号是否为空: " + (updatedDTO.getPhoneNumber() == null || updatedDTO.getPhoneNumber().trim().isEmpty())); |
||||
|
System.out.println("客户类型是否有效: " + ("seller".equals(updatedDTO.getType()) || "both".equals(updatedDTO.getType()))); |
||||
|
System.out.println("========================================="); |
||||
|
|
||||
|
// 使用修正后的数据源
|
||||
|
String dataSource = verifiedDataSource; |
||||
|
System.out.println("🔄 使用修正后的数据源: " + dataSource); |
||||
|
|
||||
|
// 权限校验
|
||||
|
System.out.println("🔐 ====== 开始权限校验 ======"); |
||||
|
System.out.println("🔐 当前类型: " + updatedDTO.getType()); |
||||
|
if (!"seller".equals(updatedDTO.getType()) && !"both".equals(updatedDTO.getType())) { |
||||
|
System.out.println("❌ 权限校验失败:采购员只能更新为seller或both类型,当前类型: " + updatedDTO.getType()); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "采购员权限只能更新为供应端类型客户"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
System.out.println("✅ 权限校验通过"); |
||||
|
|
||||
|
boolean success; |
||||
|
|
||||
|
// 🎯 关键修复:根据修正后的数据源处理更新
|
||||
|
if ("wechat".equals(dataSource)) { |
||||
|
System.out.println("🎯 使用wechat数据源更新客户信息"); |
||||
|
if (updatedDTO.getPhoneNumber() == null || updatedDTO.getPhoneNumber().trim().isEmpty()) { |
||||
|
throw new IllegalArgumentException("更新微信数据源时手机号不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 🚨 重要:检查客户是否真的在wechat数据源中
|
||||
|
UserProductCartDTO wechatCustomer = supplyPoolCustomerService.getWechatCustomerByPhone(updatedDTO.getPhoneNumber()); |
||||
|
if (wechatCustomer == null) { |
||||
|
System.out.println("❌ wechat数据源中未找到该客户,手机号: " + updatedDTO.getPhoneNumber()); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "微信数据源中未找到该客户信息"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
// 🎯 关键修复:确保传递正确的负责人信息处理标志
|
||||
|
success = supplyCustomerService.updateWechatCustomer(updatedDTO, authInfo, true); |
||||
|
|
||||
|
} else if ("default".equals(dataSource)) { |
||||
|
System.out.println("🎯 使用默认数据源更新"); |
||||
|
if (updatedDTO.getId() == null || updatedDTO.getId().trim().isEmpty()) { |
||||
|
throw new IllegalArgumentException("更新默认数据源时公司ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 检查default数据源中客户是否存在
|
||||
|
boolean exists = supplyCustomerService.checkDefaultCustomerExists(updatedDTO.getId()); |
||||
|
if (!exists) { |
||||
|
System.out.println("❌ default数据源中不存在ID为" + updatedDTO.getId() + "的客户"); |
||||
|
|
||||
|
// 尝试检查该客户是否存在于wechat数据源
|
||||
|
boolean existsInWechat = false; |
||||
|
try { |
||||
|
// 先尝试通过手机号查找
|
||||
|
if (updatedDTO.getPhoneNumber() != null && !updatedDTO.getPhoneNumber().trim().isEmpty()) { |
||||
|
System.out.println("🔍 尝试通过手机号在wechat数据源中查找客户: " + updatedDTO.getPhoneNumber()); |
||||
|
UnifiedCustomerDTO wechatCustomerDTO = supplyCustomerService.getCustomerByPhone(updatedDTO.getPhoneNumber(), authInfo); |
||||
|
if (wechatCustomerDTO != null) { |
||||
|
existsInWechat = true; |
||||
|
System.out.println("✅ 在wechat数据源中找到客户"); |
||||
|
} |
||||
|
} |
||||
|
// 如果手机号查找失败,尝试通过ID查找
|
||||
|
if (!existsInWechat && updatedDTO.getId() != null && !updatedDTO.getId().trim().isEmpty()) { |
||||
|
System.out.println("🔍 尝试通过ID在wechat数据源中查找客户: " + updatedDTO.getId()); |
||||
|
UnifiedCustomerDTO wechatCustomerDTO = supplyCustomerService.getWechatCustomerById(updatedDTO.getId(), authInfo); |
||||
|
if (wechatCustomerDTO != null) { |
||||
|
existsInWechat = true; |
||||
|
System.out.println("✅ 在wechat数据源中找到客户"); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("⚠️ 检查wechat数据源时出错: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
if (existsInWechat) { |
||||
|
System.out.println("🔄 自动切换到wechat数据源进行更新"); |
||||
|
updatedDTO.setDataSource("wechat"); |
||||
|
success = supplyCustomerService.updateWechatCustomer(updatedDTO, authInfo, true); |
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户信息更新成功(自动切换到正确的数据源)"); |
||||
|
return ResponseEntity.ok(response); |
||||
|
} else { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "默认数据源中未找到该客户,请检查ID或数据源是否正确"); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
success = supplyCustomerService.updateDefaultCustomer(updatedDTO, authInfo); |
||||
|
|
||||
|
// 验证更新结果
|
||||
|
if (!success) { |
||||
|
System.out.println("❌ SQL执行成功但未更新任何记录,可能数据未变化或记录不存在"); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "更新失败,未找到可更新的客户记录(可能数据无变化或ID错误)"); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} else { |
||||
|
System.out.println("❌ 不支持的数据源: " + dataSource); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "不支持的数据源: " + dataSource); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} |
||||
|
|
||||
|
// 🎯 关键修复:返回修正后的数据源信息给前端
|
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
result.put("success", true); |
||||
|
result.put("message", "客户信息更新成功"); |
||||
|
result.put("correctedDataSource", verifiedDataSource); |
||||
|
result.put("originalDataSource", originalDataSource); |
||||
|
|
||||
|
if (!originalDataSource.equals(verifiedDataSource)) { |
||||
|
result.put("dataSourceCorrected", true); |
||||
|
result.put("message", "客户信息更新成功(数据源已自动修正)"); |
||||
|
} |
||||
|
|
||||
|
return ResponseEntity.ok(result); |
||||
|
|
||||
|
} catch (IllegalArgumentException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.badRequest().body(response); |
||||
|
} catch (RuntimeException e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", e.getMessage()); |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("更新客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
response.put("success", false); |
||||
|
response.put("message", "服务器错误:" + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证并修正数据源 |
||||
|
* 根据客户ID和手机号自动检测客户实际所在的数据源 |
||||
|
*/ |
||||
|
private String verifyAndCorrectDataSource(UnifiedCustomerDTO updatedDTO) { |
||||
|
String dataSource = updatedDTO.getDataSource(); |
||||
|
String customerId = updatedDTO.getId(); |
||||
|
String phoneNumber = updatedDTO.getPhoneNumber(); |
||||
|
|
||||
|
System.out.println("🔍 开始验证数据源..."); |
||||
|
System.out.println("📱 手机号: " + phoneNumber); |
||||
|
System.out.println("🆔 客户ID: " + customerId); |
||||
|
System.out.println("📊 前端指定数据源: " + dataSource); |
||||
|
|
||||
|
// 🔥 关键修复:尊重前端指定的数据源,只在明确错误时修正
|
||||
|
if ("default".equals(dataSource)) { |
||||
|
// 检查default数据源中客户是否存在
|
||||
|
boolean existsInDefault = supplyCustomerService.checkDefaultCustomerExists(customerId); |
||||
|
|
||||
|
if (existsInDefault) { |
||||
|
System.out.println("✅ 客户确实在default数据源中,保持数据源不变"); |
||||
|
return "default"; |
||||
|
} else { |
||||
|
System.out.println("⚠️ default数据源中未找到客户,尝试检查wechat数据源"); |
||||
|
// 只有在default数据源不存在时才检查wechat
|
||||
|
try { |
||||
|
UserProductCartDTO wechatCustomer = supplyPoolCustomerService.getWechatCustomerByPhone(phoneNumber); |
||||
|
if (wechatCustomer != null) { |
||||
|
System.out.println("🔄 检测到客户存在于wechat数据源,自动修正数据源"); |
||||
|
return "wechat"; |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查wechat数据源失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 保持原数据源
|
||||
|
System.out.println("✅ 保持原数据源: " + dataSource); |
||||
|
return dataSource; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.service.SupplyCustomerRecycleService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/supply/pool") |
||||
|
public class SupplyCustomerRecycleController { |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyCustomerRecycleService supplycustomerRecycleService; |
||||
|
|
||||
|
/** |
||||
|
* 手动触发客户回流 |
||||
|
* POST /supply/pool/customers/recycle |
||||
|
*/ |
||||
|
@PostMapping("/customers/recycle") |
||||
|
public ResponseEntity<Map<String, Object>> manualRecycle() { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
supplycustomerRecycleService.manualRecycle(); |
||||
|
|
||||
|
response.put("success", true); |
||||
|
response.put("message", "客户回流任务执行成功"); |
||||
|
response.put("config", supplycustomerRecycleService.getRecycleConfigInfo()); |
||||
|
return ResponseEntity.ok(response); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "客户回流任务执行失败: " + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取回流配置信息 |
||||
|
* GET /supply/pool/customers/recycle/config |
||||
|
*/ |
||||
|
@GetMapping("/customers/recycle/config") |
||||
|
public ResponseEntity<Map<String, Object>> getRecycleConfig() { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
response.put("success", true); |
||||
|
response.put("config", supplycustomerRecycleService.getRecycleConfigInfo()); |
||||
|
return ResponseEntity.ok(response); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
response.put("success", false); |
||||
|
response.put("message", "获取回流配置失败: " + e.getMessage()); |
||||
|
return ResponseEntity.internalServerError().body(response); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,73 @@ |
|||||
|
package com.example.web.controller; |
||||
|
|
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.service.PoolCustomerService; |
||||
|
import com.example.web.service.SupplyPoolCustomerService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/supply/pool/") |
||||
|
public class SupplyPoolCustomerController { |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyPoolCustomerService supplypoolCustomerService; |
||||
|
|
||||
|
/** |
||||
|
* 根据用户ID获取客户信息 |
||||
|
* GET /pool/customers/{userId} |
||||
|
*/ |
||||
|
@GetMapping("/customersss/{userId}") |
||||
|
public ResponseEntity<?> getCustomerById(@PathVariable String userId) { |
||||
|
try { |
||||
|
UserProductCartDTO customerInfo = supplypoolCustomerService.getCustomerInfo(userId); |
||||
|
return ResponseEntity.ok(customerInfo); |
||||
|
} catch (IllegalArgumentException e) { |
||||
|
return ResponseEntity.badRequest().body(createErrorResponse("参数错误", e.getMessage())); |
||||
|
} catch (RuntimeException e) { |
||||
|
return ResponseEntity.notFound().build(); |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError() |
||||
|
.body(createErrorResponse("服务器错误", "获取客户信息失败")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询客户信息(支持按类型过滤) |
||||
|
* GET /pool/customers?type=seller&page=1&size=10 |
||||
|
*/ |
||||
|
@GetMapping("/customersss") |
||||
|
public ResponseEntity<?> getCustomers( |
||||
|
@RequestParam(required = false) String type, |
||||
|
@RequestParam(defaultValue = "1") int page, |
||||
|
@RequestParam(defaultValue = "10") int size) { |
||||
|
|
||||
|
try { |
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
response.put("page", page); |
||||
|
response.put("size", size); |
||||
|
response.put("type", type); |
||||
|
response.put("message", "分页查询功能待实现"); |
||||
|
|
||||
|
return ResponseEntity.ok(response); |
||||
|
} catch (Exception e) { |
||||
|
return ResponseEntity.internalServerError() |
||||
|
.body(createErrorResponse("查询失败", e.getMessage())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建统一的错误响应格式 |
||||
|
*/ |
||||
|
private Map<String, Object> createErrorResponse(String error, String message) { |
||||
|
Map<String, Object> errorResponse = new HashMap<>(); |
||||
|
errorResponse.put("error", error); |
||||
|
errorResponse.put("message", message); |
||||
|
errorResponse.put("timestamp", System.currentTimeMillis()); |
||||
|
return errorResponse; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
package com.example.web.dto; |
||||
|
|
||||
|
import com.example.web.entity.Contacts; |
||||
|
import com.example.web.entity.Enterprise; |
||||
|
import com.example.web.entity.Managers; |
||||
|
// 企业信息数据传输对象(DTO),用于封装企业完整信息(企业基本信息+联系人+负责人等)
|
||||
|
// getter和setter:提供属性的获取和设置方法,用于在各层之间传递数据
|
||||
|
public class EnterpriseInfoDTO { |
||||
|
|
||||
|
private Enterprise enterprise; |
||||
|
private Contacts contacts; |
||||
|
private Managers managers; |
||||
|
|
||||
|
// 构造方法
|
||||
|
public EnterpriseInfoDTO() {} |
||||
|
|
||||
|
public EnterpriseInfoDTO(Enterprise enterprise, Contacts contacts, Managers managers) { |
||||
|
this.enterprise = enterprise; |
||||
|
this.contacts = contacts; |
||||
|
this.managers = managers; |
||||
|
} |
||||
|
|
||||
|
// getter和setter
|
||||
|
public Enterprise getEnterprise() { |
||||
|
return enterprise; |
||||
|
}// 获取企业基本信息对象(包含公司名称、地区、类型等核心字段)
|
||||
|
|
||||
|
public void setEnterprise(Enterprise enterprise) { |
||||
|
this.enterprise = enterprise; |
||||
|
} |
||||
|
|
||||
|
public Contacts getContacts() { |
||||
|
return contacts; |
||||
|
} |
||||
|
|
||||
|
public void setContacts(Contacts contacts) { |
||||
|
this.contacts = contacts; |
||||
|
} |
||||
|
|
||||
|
public Managers getManagers() { |
||||
|
return managers; |
||||
|
} |
||||
|
|
||||
|
public void setManagers(Managers managers) { |
||||
|
this.managers = managers; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
package com.example.web.dto; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class ManagerAuthInfo { |
||||
|
private String managerId; |
||||
|
private String managercompany; |
||||
|
private String managerdepartment; |
||||
|
private String organization; |
||||
|
private String role; |
||||
|
private String userName; |
||||
|
private String assistant; |
||||
|
|
||||
|
public ManagerAuthInfo(String managerId, String managercompany, String managerdepartment, String organization, String role, String userName, String assistant) { |
||||
|
this.managerId = managerId; |
||||
|
this.managercompany = managercompany; |
||||
|
this.managerdepartment = managerdepartment; |
||||
|
this.organization = organization; |
||||
|
this.role = role; |
||||
|
this.userName = userName; |
||||
|
this.assistant = assistant; |
||||
|
} |
||||
|
|
||||
|
public String getManagerId() { |
||||
|
return managerId; |
||||
|
} |
||||
|
|
||||
|
public void setManagerId(String managerId) { |
||||
|
this.managerId = managerId; |
||||
|
} |
||||
|
|
||||
|
public String getManagercompany() { |
||||
|
return managercompany; |
||||
|
} |
||||
|
|
||||
|
public void setManagercompany(String managercompany) { |
||||
|
this.managercompany = managercompany; |
||||
|
} |
||||
|
|
||||
|
public String getManagerdepartment() { |
||||
|
return managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public void setManagerdepartment(String managerdepartment) { |
||||
|
this.managerdepartment = managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public String getOrganization() { |
||||
|
return organization; |
||||
|
} |
||||
|
|
||||
|
public void setOrganization(String organization) { |
||||
|
this.organization = organization; |
||||
|
} |
||||
|
|
||||
|
public String getRole() { |
||||
|
return role; |
||||
|
} |
||||
|
|
||||
|
public void setRole(String role) { |
||||
|
this.role = role; |
||||
|
} |
||||
|
|
||||
|
public String getUserName() { |
||||
|
return userName; |
||||
|
} |
||||
|
|
||||
|
public void setUserName(String userName) { |
||||
|
this.userName = userName; |
||||
|
} |
||||
|
|
||||
|
public String getAssistant() { |
||||
|
return assistant; |
||||
|
} |
||||
|
|
||||
|
public void setAssistant(String assistant) { |
||||
|
this.assistant = assistant; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,321 @@ |
|||||
|
package com.example.web.dto; |
||||
|
|
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class UnifiedCustomerDTO { |
||||
|
private String id = ""; |
||||
|
private String company = ""; |
||||
|
private String region = ""; |
||||
|
private String level = ""; |
||||
|
private String type = ""; |
||||
|
private String demand = ""; |
||||
|
private String spec = ""; |
||||
|
private String nickName = ""; |
||||
|
|
||||
|
@NotBlank(message = "手机号不能为空") |
||||
|
private String phoneNumber = ""; |
||||
|
|
||||
|
// 向后兼容的单个联系人字段
|
||||
|
private String wechat = ""; |
||||
|
private String account = ""; |
||||
|
private String accountNumber = ""; |
||||
|
private String bank = ""; |
||||
|
private String address = ""; |
||||
|
|
||||
|
// 向后兼容的单个产品字段
|
||||
|
private String productName = ""; |
||||
|
private String variety = ""; |
||||
|
private String specification = ""; |
||||
|
private Integer quantity = 0; |
||||
|
private String grossWeight = ""; |
||||
|
private String yolk = ""; |
||||
|
|
||||
|
// 负责人信息字段
|
||||
|
private String managerId =""; //负责人id
|
||||
|
private String managercompany = ""; // 负责人公司
|
||||
|
private String managerdepartment = ""; // 负责人部门
|
||||
|
private String organization = ""; // 负责人组织
|
||||
|
private String role = ""; // 负责人角色
|
||||
|
private String userName = ""; // 负责人用户名
|
||||
|
private String assistant = ""; // 协助人
|
||||
|
|
||||
|
|
||||
|
// 时间信息
|
||||
|
private LocalDateTime created_at; |
||||
|
private LocalDateTime updated_at; |
||||
|
|
||||
|
// 扩展信息
|
||||
|
private Object[] customDetails = new Object[0]; |
||||
|
private String dataSource; // "wechat" 或 "default" 或 "mixed"
|
||||
|
|
||||
|
// ==================== 一对多字段 ====================
|
||||
|
private List<ContactInfo> contacts = new ArrayList<>(); |
||||
|
private List<CartItem> cartItems = new ArrayList<>(); // 销售端使用
|
||||
|
private List<ProductItem> productItems = new ArrayList<>(); // 采购端使用
|
||||
|
|
||||
|
// ==================== 精确修改字段 ====================
|
||||
|
private String targetContactId; // 要修改的联系人ID
|
||||
|
private String targetCartItemId; // 要修改的购物车项ID
|
||||
|
private String targetProductItemId; // 要修改的产品项ID
|
||||
|
|
||||
|
// ==================== 更新数据字段 ====================
|
||||
|
// 修改字段名以保持与Service的一致性
|
||||
|
private ContactInfo updateContactData; // 联系人更新数据(与Service中的使用保持一致)
|
||||
|
private CartItem updateCartItemData; // 购物车项更新数据(与Service中的使用保持一致)
|
||||
|
private ProductItem updateProductItemData; // 产品项更新数据
|
||||
|
|
||||
|
// ==================== 内部类定义 ====================
|
||||
|
|
||||
|
/** |
||||
|
* 联系人信息 |
||||
|
*/ |
||||
|
public static class ContactInfo { |
||||
|
private String contactId = ""; |
||||
|
private String wechat = ""; |
||||
|
private String account = ""; |
||||
|
private String accountNumber = ""; |
||||
|
private String bank = ""; |
||||
|
private String address = ""; |
||||
|
|
||||
|
// Getter 和 Setter 方法
|
||||
|
public String getContactId() { return contactId; } |
||||
|
public void setContactId(String contactId) { this.contactId = contactId; } |
||||
|
public String getWechat() { return wechat; } |
||||
|
public void setWechat(String wechat) { this.wechat = wechat; } |
||||
|
public String getAccount() { return account; } |
||||
|
public void setAccount(String account) { this.account = account; } |
||||
|
public String getAccountNumber() { return accountNumber; } |
||||
|
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } |
||||
|
public String getBank() { return bank; } |
||||
|
public void setBank(String bank) { this.bank = bank; } |
||||
|
public String getAddress() { return address; } |
||||
|
public void setAddress(String address) { this.address = address; } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 购物车项信息(销售端使用) |
||||
|
*/ |
||||
|
public static class CartItem { |
||||
|
private String cartItemId = ""; |
||||
|
private String productId = ""; |
||||
|
private String productName = ""; |
||||
|
private String specification = ""; |
||||
|
private Integer quantity = 0; |
||||
|
private String grossWeight = ""; |
||||
|
private String yolk = ""; |
||||
|
|
||||
|
// Getter 和 Setter 方法
|
||||
|
public String getCartItemId() { return cartItemId; } |
||||
|
public void setCartItemId(String cartItemId) { this.cartItemId = cartItemId; } |
||||
|
public String getProductId() { return productId; } |
||||
|
public void setProductId(String productId) { this.productId = productId; } |
||||
|
public String getProductName() { return productName; } |
||||
|
public void setProductName(String productName) { this.productName = productName; } |
||||
|
public String getSpecification() { return specification; } |
||||
|
public void setSpecification(String specification) { this.specification = specification; } |
||||
|
public Integer getQuantity() { return quantity; } |
||||
|
public void setQuantity(Integer quantity) { this.quantity = quantity; } |
||||
|
public String getGrossWeight() { return grossWeight; } |
||||
|
public void setGrossWeight(String grossWeight) { this.grossWeight = grossWeight; } |
||||
|
public String getYolk() { return yolk; } |
||||
|
public void setYolk(String yolk) { this.yolk = yolk; } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 产品项信息(采购端使用) |
||||
|
*/ |
||||
|
public static class ProductItem { |
||||
|
private String productId = ""; |
||||
|
private String productName = ""; |
||||
|
private String variety = ""; |
||||
|
private String specification = ""; |
||||
|
private Integer quantity = 0; |
||||
|
private String grossWeight = ""; |
||||
|
private String yolk = ""; |
||||
|
|
||||
|
// Getter 和 Setter 方法
|
||||
|
public String getProductId() { return productId; } |
||||
|
public void setProductId(String productId) { this.productId = productId; } |
||||
|
public String getProductName() { return productName; } |
||||
|
public void setProductName(String productName) { this.productName = productName; } |
||||
|
public String getVariety() { return variety; } |
||||
|
public void setVariety(String variety) { this.variety = variety; } |
||||
|
public String getSpecification() { return specification; } |
||||
|
public void setSpecification(String specification) { this.specification = specification; } |
||||
|
public Integer getQuantity() { return quantity; } |
||||
|
public void setQuantity(Integer quantity) { this.quantity = quantity; } |
||||
|
public String getGrossWeight() { return grossWeight; } |
||||
|
public void setGrossWeight(String grossWeight) { this.grossWeight = grossWeight; } |
||||
|
public String getYolk() { return yolk; } |
||||
|
public void setYolk(String yolk) { this.yolk = yolk; } |
||||
|
} |
||||
|
|
||||
|
// ==================== Getter 和 Setter 方法 ====================
|
||||
|
|
||||
|
// 一对多字段的getter/setter
|
||||
|
public List<ContactInfo> getContacts() { return contacts; } |
||||
|
public void setContacts(List<ContactInfo> contacts) { this.contacts = contacts; } |
||||
|
|
||||
|
public List<CartItem> getCartItems() { return cartItems; } |
||||
|
public void setCartItems(List<CartItem> cartItems) { this.cartItems = cartItems; } |
||||
|
|
||||
|
public List<ProductItem> getProductItems() { return productItems; } |
||||
|
public void setProductItems(List<ProductItem> productItems) { this.productItems = productItems; } |
||||
|
|
||||
|
// 精确修改字段的getter/setter
|
||||
|
public String getTargetContactId() { return targetContactId; } |
||||
|
public void setTargetContactId(String targetContactId) { this.targetContactId = targetContactId; } |
||||
|
|
||||
|
public String getTargetCartItemId() { return targetCartItemId; } |
||||
|
public void setTargetCartItemId(String targetCartItemId) { this.targetCartItemId = targetCartItemId; } |
||||
|
|
||||
|
public String getTargetProductItemId() { return targetProductItemId; } |
||||
|
public void setTargetProductItemId(String targetProductItemId) { this.targetProductItemId = targetProductItemId; } |
||||
|
|
||||
|
// 更新数据字段的getter/setter
|
||||
|
public ContactInfo getUpdateContactData() { return updateContactData; } |
||||
|
public void setUpdateContactData(ContactInfo updateContactData) { this.updateContactData = updateContactData; } |
||||
|
|
||||
|
public CartItem getUpdateCartItemData() { return updateCartItemData; } |
||||
|
public void setUpdateCartItemData(CartItem updateCartItemData) { this.updateCartItemData = updateCartItemData; } |
||||
|
|
||||
|
public ProductItem getUpdateProductItemData() { return updateProductItemData; } |
||||
|
public void setUpdateProductItemData(ProductItem updateProductItemData) { this.updateProductItemData = updateProductItemData; } |
||||
|
|
||||
|
// 向后兼容:为旧的updateContact字段提供兼容性(如果需要)
|
||||
|
/** |
||||
|
* @deprecated 请使用 getUpdateContactData() |
||||
|
*/ |
||||
|
public ContactInfo getUpdateContact() { return updateContactData; } |
||||
|
|
||||
|
/** |
||||
|
* @deprecated 请使用 setUpdateContactData() |
||||
|
*/ |
||||
|
public void setUpdateContact(ContactInfo updateContact) { this.updateContactData = updateContact; } |
||||
|
|
||||
|
/** |
||||
|
* @deprecated 请使用 getUpdateCartItemData() |
||||
|
*/ |
||||
|
public CartItem getUpdateCartItem() { return updateCartItemData; } |
||||
|
|
||||
|
/** |
||||
|
* @deprecated 请使用 setUpdateCartItemData() |
||||
|
*/ |
||||
|
public void setUpdateCartItem(CartItem updateCartItem) { this.updateCartItemData = updateCartItem; } |
||||
|
|
||||
|
/** |
||||
|
* @deprecated 请使用 getUpdateProductItemData() |
||||
|
*/ |
||||
|
public ProductItem getUpdateProductItem() { return updateProductItemData; } |
||||
|
|
||||
|
/** |
||||
|
* @deprecated 请使用 setUpdateProductItemData() |
||||
|
*/ |
||||
|
public void setUpdateProductItem(ProductItem updateProductItem) { this.updateProductItemData = updateProductItem; } |
||||
|
|
||||
|
// 基础字段的getter/setter
|
||||
|
public String getId() { return id; } |
||||
|
public void setId(String id) { this.id = id; } |
||||
|
|
||||
|
public String getCompany() { return company; } |
||||
|
public void setCompany(String company) { this.company = company; } |
||||
|
|
||||
|
public String getRegion() { return region; } |
||||
|
public void setRegion(String region) { this.region = region; } |
||||
|
|
||||
|
public String getLevel() { return level; } |
||||
|
public void setLevel(String level) { this.level = level; } |
||||
|
|
||||
|
public String getType() { return type; } |
||||
|
public void setType(String type) { this.type = type; } |
||||
|
|
||||
|
public String getDemand() { return demand; } |
||||
|
public void setDemand(String demand) { this.demand = demand; } |
||||
|
|
||||
|
public String getSpec() { return spec; } |
||||
|
public void setSpec(String spec) { this.spec = spec; } |
||||
|
|
||||
|
public String getNickName() { return nickName; } |
||||
|
public void setNickName(String nickName) { this.nickName = nickName; } |
||||
|
|
||||
|
public String getPhoneNumber() { return phoneNumber; } |
||||
|
public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } |
||||
|
|
||||
|
public String getWechat() { return wechat; } |
||||
|
public void setWechat(String wechat) { this.wechat = wechat; } |
||||
|
|
||||
|
public String getAccount() { return account; } |
||||
|
public void setAccount(String account) { this.account = account; } |
||||
|
|
||||
|
public String getAccountNumber() { return accountNumber; } |
||||
|
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } |
||||
|
|
||||
|
public String getBank() { return bank; } |
||||
|
public void setBank(String bank) { this.bank = bank; } |
||||
|
|
||||
|
public String getAddress() { return address; } |
||||
|
public void setAddress(String address) { this.address = address; } |
||||
|
|
||||
|
public String getProductName() { return productName; } |
||||
|
public void setProductName(String productName) { this.productName = productName; } |
||||
|
|
||||
|
public String getVariety() { return variety; } |
||||
|
public void setVariety(String variety) { this.variety = variety; } |
||||
|
|
||||
|
public String getSpecification() { return specification; } |
||||
|
public void setSpecification(String specification) { this.specification = specification; } |
||||
|
|
||||
|
public Integer getQuantity() { return quantity; } |
||||
|
public void setQuantity(Integer quantity) { this.quantity = quantity; } |
||||
|
|
||||
|
public String getGrossWeight() { return grossWeight; } |
||||
|
public void setGrossWeight(String grossWeight) { this.grossWeight = grossWeight; } |
||||
|
|
||||
|
public String getYolk() { return yolk; } |
||||
|
public void setYolk(String yolk) { this.yolk = yolk; } |
||||
|
|
||||
|
public String getManagerId() { |
||||
|
return managerId; |
||||
|
} |
||||
|
|
||||
|
public void setManagerId(String managerId) { |
||||
|
this.managerId = managerId; |
||||
|
} |
||||
|
|
||||
|
public String getManagercompany() { return managercompany; } |
||||
|
public void setManagercompany(String managercompany) { this.managercompany = managercompany; } |
||||
|
|
||||
|
public String getManagerdepartment() { return managerdepartment; } |
||||
|
public void setManagerdepartment(String managerdepartment) { this.managerdepartment = managerdepartment; } |
||||
|
|
||||
|
public String getOrganization() { return organization; } |
||||
|
public void setOrganization(String organization) { this.organization = organization; } |
||||
|
|
||||
|
public String getRole() { return role; } |
||||
|
public void setRole(String role) { this.role = role; } |
||||
|
|
||||
|
public String getUserName() { return userName; } |
||||
|
public void setUserName(String userName) { this.userName = userName; } |
||||
|
|
||||
|
public String getAssistant() { return assistant; } |
||||
|
public void setAssistant(String assistant) { this.assistant = assistant; } |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { return created_at; } |
||||
|
public void setCreated_at(LocalDateTime created_at) { this.created_at = created_at; } |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { return updated_at; } |
||||
|
public void setUpdated_at(LocalDateTime updated_at) { this.updated_at = updated_at; } |
||||
|
|
||||
|
public Object[] getCustomDetails() { return customDetails; } |
||||
|
public void setCustomDetails(Object[] customDetails) { this.customDetails = customDetails; } |
||||
|
|
||||
|
public String getDataSource() { return dataSource; } |
||||
|
public void setDataSource(String dataSource) { this.dataSource = dataSource; } |
||||
|
} |
||||
@ -0,0 +1,423 @@ |
|||||
|
package com.example.web.dto; |
||||
|
|
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
@Data |
||||
|
public class UserProductCartDTO { |
||||
|
private String userId;//用户id
|
||||
|
private String phoneNumber;//用户手机号
|
||||
|
private String type;//用户类型
|
||||
|
private String nickName;//用户昵称
|
||||
|
private String company;//客户公司
|
||||
|
private String region;//客户地区
|
||||
|
private String level;//客户等级
|
||||
|
private String demand;//客户需求
|
||||
|
private String spec;//规格
|
||||
|
private LocalDateTime created_at;//创建时间
|
||||
|
private LocalDateTime updated_at;//更新时间
|
||||
|
private List<ProductInfo> products= new ArrayList<>();;//产品信息
|
||||
|
private List<CartItem> cartItems= new ArrayList<>();;//购物车信息
|
||||
|
private List<UsersContacts> usersContacts= new ArrayList<>();;//联系人信息
|
||||
|
|
||||
|
public String getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) { |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getPhoneNumber() { |
||||
|
return phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public void setPhoneNumber(String phoneNumber) { |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public String getType() { |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
public void setType(String type) { |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() { |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) { |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getCompany() { |
||||
|
return company; |
||||
|
} |
||||
|
|
||||
|
public void setCompany(String company) { |
||||
|
this.company = company; |
||||
|
} |
||||
|
|
||||
|
public String getRegion() { |
||||
|
return region; |
||||
|
} |
||||
|
|
||||
|
public void setRegion(String region) { |
||||
|
this.region = region; |
||||
|
} |
||||
|
|
||||
|
public String getLevel() { |
||||
|
return level; |
||||
|
} |
||||
|
|
||||
|
public void setLevel(String level) { |
||||
|
this.level = level; |
||||
|
} |
||||
|
|
||||
|
public String getDemand() { |
||||
|
return demand; |
||||
|
} |
||||
|
|
||||
|
public void setDemand(String demand) { |
||||
|
this.demand = demand; |
||||
|
} |
||||
|
|
||||
|
public String getSpec() { |
||||
|
return spec; |
||||
|
} |
||||
|
|
||||
|
public void setSpec(String spec) { |
||||
|
this.spec = spec; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public List<ProductInfo> getProducts() { |
||||
|
return products; |
||||
|
} |
||||
|
|
||||
|
public void setProducts(List<ProductInfo> products) { |
||||
|
this.products = products; |
||||
|
} |
||||
|
|
||||
|
public List<CartItem> getCartItems() { |
||||
|
return cartItems; |
||||
|
} |
||||
|
|
||||
|
public void setCartItems(List<CartItem> cartItems) { |
||||
|
this.cartItems = cartItems; |
||||
|
} |
||||
|
|
||||
|
public List<UsersContacts> getUsersContacts() { |
||||
|
return usersContacts; |
||||
|
} |
||||
|
|
||||
|
public void setUsersContacts(List<UsersContacts> usersContacts) { |
||||
|
this.usersContacts = usersContacts; |
||||
|
} |
||||
|
|
||||
|
@Data |
||||
|
public static class ProductInfo { |
||||
|
private String productName = ""; |
||||
|
private String variety = ""; |
||||
|
private String specification = ""; |
||||
|
private Integer quantity = 0; |
||||
|
private String grossWeight = ""; |
||||
|
private String yolk = ""; |
||||
|
private String productId = ""; |
||||
|
private String price = ""; |
||||
|
private String sellerId = ""; |
||||
|
private String sellerNickName = ""; |
||||
|
private String sellerPhone = ""; |
||||
|
private LocalDateTime created_at; |
||||
|
private LocalDateTime updated_at; |
||||
|
|
||||
|
public String getProductName() { |
||||
|
return productName; |
||||
|
} |
||||
|
|
||||
|
public void setProductName(String productName) { |
||||
|
this.productName = productName; |
||||
|
} |
||||
|
|
||||
|
public String getVariety() { |
||||
|
return variety; |
||||
|
} |
||||
|
|
||||
|
public void setVariety(String variety) { |
||||
|
this.variety = variety; |
||||
|
} |
||||
|
|
||||
|
public String getSpecification() { |
||||
|
return specification; |
||||
|
} |
||||
|
|
||||
|
public void setSpecification(String specification) { |
||||
|
this.specification = specification; |
||||
|
} |
||||
|
|
||||
|
public Integer getQuantity() { |
||||
|
return quantity; |
||||
|
} |
||||
|
|
||||
|
public void setQuantity(Integer quantity) { |
||||
|
this.quantity = quantity; |
||||
|
} |
||||
|
|
||||
|
public String getGrossWeight() { |
||||
|
return grossWeight; |
||||
|
} |
||||
|
|
||||
|
public void setGrossWeight(String grossWeight) { |
||||
|
this.grossWeight = grossWeight; |
||||
|
} |
||||
|
|
||||
|
public String getYolk() { |
||||
|
return yolk; |
||||
|
} |
||||
|
|
||||
|
public void setYolk(String yolk) { |
||||
|
this.yolk = yolk; |
||||
|
} |
||||
|
|
||||
|
public String getProductId() { |
||||
|
return productId; |
||||
|
} |
||||
|
|
||||
|
public void setProductId(String productId) { |
||||
|
this.productId = productId; |
||||
|
} |
||||
|
|
||||
|
public String getPrice() { |
||||
|
return price; |
||||
|
} |
||||
|
|
||||
|
public void setPrice(String price) { |
||||
|
this.price = price; |
||||
|
} |
||||
|
|
||||
|
public String getSellerId() { |
||||
|
return sellerId; |
||||
|
} |
||||
|
|
||||
|
public void setSellerId(String sellerId) { |
||||
|
this.sellerId = sellerId; |
||||
|
} |
||||
|
|
||||
|
public String getSellerNickName() { |
||||
|
return sellerNickName; |
||||
|
} |
||||
|
|
||||
|
public void setSellerNickName(String sellerNickName) { |
||||
|
this.sellerNickName = sellerNickName; |
||||
|
} |
||||
|
|
||||
|
public String getSellerPhone() { |
||||
|
return sellerPhone; |
||||
|
} |
||||
|
|
||||
|
public void setSellerPhone(String sellerPhone) { |
||||
|
this.sellerPhone = sellerPhone; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Data |
||||
|
public static class CartItem { |
||||
|
private String cartItemId = ""; // 新增:购物车项唯一标识
|
||||
|
private String productName = ""; |
||||
|
private String variety = ""; |
||||
|
private String specification = ""; |
||||
|
private Integer quantity = 0; |
||||
|
private String grossWeight = ""; |
||||
|
private String yolk = ""; |
||||
|
private String productId = ""; |
||||
|
private String price = ""; |
||||
|
private Boolean selected = false; |
||||
|
private LocalDateTime added_at; |
||||
|
|
||||
|
public String getCartItemId() { |
||||
|
return cartItemId; |
||||
|
} |
||||
|
|
||||
|
public void setCartItemId(String cartItemId) { |
||||
|
this.cartItemId = cartItemId; |
||||
|
} |
||||
|
|
||||
|
public String getProductName() { |
||||
|
return productName; |
||||
|
} |
||||
|
|
||||
|
public void setProductName(String productName) { |
||||
|
this.productName = productName; |
||||
|
} |
||||
|
|
||||
|
public String getSpecification() { |
||||
|
return specification; |
||||
|
} |
||||
|
|
||||
|
public void setSpecification(String specification) { |
||||
|
this.specification = specification; |
||||
|
} |
||||
|
|
||||
|
public Integer getQuantity() { |
||||
|
return quantity; |
||||
|
} |
||||
|
|
||||
|
public void setQuantity(Integer quantity) { |
||||
|
this.quantity = quantity; |
||||
|
} |
||||
|
|
||||
|
public String getGrossWeight() { |
||||
|
return grossWeight; |
||||
|
} |
||||
|
|
||||
|
public void setGrossWeight(String grossWeight) { |
||||
|
this.grossWeight = grossWeight; |
||||
|
} |
||||
|
|
||||
|
public String getYolk() { |
||||
|
return yolk; |
||||
|
} |
||||
|
|
||||
|
public void setYolk(String yolk) { |
||||
|
this.yolk = yolk; |
||||
|
} |
||||
|
|
||||
|
public String getProductId() { |
||||
|
return productId; |
||||
|
} |
||||
|
|
||||
|
public void setProductId(String productId) { |
||||
|
this.productId = productId; |
||||
|
} |
||||
|
|
||||
|
public String getPrice() { |
||||
|
return price; |
||||
|
} |
||||
|
|
||||
|
public void setPrice(String price) { |
||||
|
this.price = price; |
||||
|
} |
||||
|
|
||||
|
public Boolean getSelected() { |
||||
|
return selected; |
||||
|
} |
||||
|
|
||||
|
public void setSelected(Boolean selected) { |
||||
|
this.selected = selected; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getAdded_at() { |
||||
|
return added_at; |
||||
|
} |
||||
|
|
||||
|
public void setAdded_at(LocalDateTime added_at) { |
||||
|
this.added_at = added_at; |
||||
|
} |
||||
|
} |
||||
|
@Data |
||||
|
public static class UsersContacts { |
||||
|
private String contactId = ""; // 新增:联系人唯一标识
|
||||
|
private String wechat = ""; |
||||
|
private String account = ""; |
||||
|
private String accountNumber = ""; |
||||
|
private String bank = ""; |
||||
|
private String address = ""; |
||||
|
|
||||
|
public UsersContacts(String wechat, String account, String accountNumber, String bank, String address) { |
||||
|
this.wechat = wechat; |
||||
|
this.account = account; |
||||
|
this.accountNumber = accountNumber; |
||||
|
this.bank = bank; |
||||
|
this.address = address; |
||||
|
} |
||||
|
public UsersContacts() {} |
||||
|
|
||||
|
public String getContactId() { |
||||
|
return contactId; |
||||
|
} |
||||
|
|
||||
|
public void setContactId(String contactId) { |
||||
|
this.contactId = contactId; |
||||
|
} |
||||
|
|
||||
|
public String getWechat() { |
||||
|
return wechat; |
||||
|
} |
||||
|
|
||||
|
public void setWechat(String wechat) { |
||||
|
this.wechat = wechat; |
||||
|
} |
||||
|
|
||||
|
public String getAccount() { |
||||
|
return account; |
||||
|
} |
||||
|
|
||||
|
public void setAccount(String account) { |
||||
|
this.account = account; |
||||
|
} |
||||
|
|
||||
|
public String getAccountNumber() { |
||||
|
return accountNumber; |
||||
|
} |
||||
|
|
||||
|
public void setAccountNumber(String accountNumber) { |
||||
|
this.accountNumber = accountNumber; |
||||
|
} |
||||
|
|
||||
|
public String getBank() { |
||||
|
return bank; |
||||
|
} |
||||
|
|
||||
|
public void setBank(String bank) { |
||||
|
this.bank = bank; |
||||
|
} |
||||
|
|
||||
|
public String getAddress() { |
||||
|
return address; |
||||
|
} |
||||
|
|
||||
|
public void setAddress(String address) { |
||||
|
this.address = address; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,128 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 购物车表 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Cart_items { |
||||
|
private Integer id;//购物车id
|
||||
|
private String userId;//用户id
|
||||
|
private String productId;//产品id
|
||||
|
private String productName;//产品名称
|
||||
|
private String specification;//规格
|
||||
|
private Integer quantity;//数量
|
||||
|
private String grossWeight;//毛重
|
||||
|
private String price;//单价
|
||||
|
private Integer selected;//是否选中
|
||||
|
private String added_at;//添加时间
|
||||
|
private String yolk;//蛋黄
|
||||
|
|
||||
|
public Cart_items(Integer id, String userId, String productId, String productName, String specification, Integer quantity, String grossWeight, String price, Integer selected, String added_at, String yolk) { |
||||
|
this.id = id; |
||||
|
this.userId = userId; |
||||
|
this.productId = productId; |
||||
|
this.productName = productName; |
||||
|
this.specification = specification; |
||||
|
this.quantity = quantity; |
||||
|
this.grossWeight = grossWeight; |
||||
|
this.price = price; |
||||
|
this.selected = selected; |
||||
|
this.added_at = added_at; |
||||
|
this.yolk = yolk; |
||||
|
} |
||||
|
|
||||
|
public Integer getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(Integer id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) { |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getProductId() { |
||||
|
return productId; |
||||
|
} |
||||
|
|
||||
|
public void setProductId(String productId) { |
||||
|
this.productId = productId; |
||||
|
} |
||||
|
|
||||
|
public String getProductName() { |
||||
|
return productName; |
||||
|
} |
||||
|
|
||||
|
public void setProductName(String productName) { |
||||
|
this.productName = productName; |
||||
|
} |
||||
|
|
||||
|
public String getSpecification() { |
||||
|
return specification; |
||||
|
} |
||||
|
|
||||
|
public void setSpecification(String specification) { |
||||
|
this.specification = specification; |
||||
|
} |
||||
|
|
||||
|
public Integer getQuantity() { |
||||
|
return quantity; |
||||
|
} |
||||
|
|
||||
|
public void setQuantity(Integer quantity) { |
||||
|
this.quantity = quantity; |
||||
|
} |
||||
|
|
||||
|
public String getGrossWeight() { |
||||
|
return grossWeight; |
||||
|
} |
||||
|
|
||||
|
public void setGrossWeight(String grossWeight) { |
||||
|
this.grossWeight = grossWeight; |
||||
|
} |
||||
|
|
||||
|
public String getPrice() { |
||||
|
return price; |
||||
|
} |
||||
|
|
||||
|
public void setPrice(String price) { |
||||
|
this.price = price; |
||||
|
} |
||||
|
|
||||
|
public Integer getSelected() { |
||||
|
return selected; |
||||
|
} |
||||
|
|
||||
|
public void setSelected(Integer selected) { |
||||
|
this.selected = selected; |
||||
|
} |
||||
|
|
||||
|
public String getAdded_at() { |
||||
|
return added_at; |
||||
|
} |
||||
|
|
||||
|
public void setAdded_at(String added_at) { |
||||
|
this.added_at = added_at; |
||||
|
} |
||||
|
|
||||
|
public String getYolk() { |
||||
|
return yolk; |
||||
|
} |
||||
|
|
||||
|
public void setYolk(String yolk) { |
||||
|
this.yolk = yolk; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,138 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* @Description: 联系人实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class Contacts { |
||||
|
private String contact_id;//联系人id
|
||||
|
private String id;//用户id
|
||||
|
private String nickName;//联系人姓名
|
||||
|
private String phoneNumber;//联系人电话
|
||||
|
private String wechat;//联系人微信
|
||||
|
private String account;//联系人账号
|
||||
|
private String accountNumber;//联系人账号
|
||||
|
private String bank;//联系人银行
|
||||
|
private String address;//联系人地址
|
||||
|
private String followup;//跟进信息
|
||||
|
private LocalDateTime created_at;//创建时间
|
||||
|
private LocalDateTime updated_at;//更新时间
|
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public Contacts() { |
||||
|
|
||||
|
} |
||||
|
public Contacts(String contact_id, String id, String nickName, String phoneNumber, String wechat, String account, String accountNumber, String bank, String address, String followup) { |
||||
|
this.contact_id = contact_id; |
||||
|
this.id = id; |
||||
|
this.nickName = nickName; |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
this.wechat = wechat; |
||||
|
this.account = account; |
||||
|
this.accountNumber = accountNumber; |
||||
|
this.bank = bank; |
||||
|
this.address = address; |
||||
|
this.followup = followup; |
||||
|
} |
||||
|
|
||||
|
public String getContact_id() { |
||||
|
return contact_id; |
||||
|
} |
||||
|
|
||||
|
public void setContact_id(String contact_id) { |
||||
|
this.contact_id = contact_id; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() { |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) { |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getPhoneNumber() { |
||||
|
return phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public void setPhoneNumber(String phoneNumber) { |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public String getWechat() { |
||||
|
return wechat; |
||||
|
} |
||||
|
|
||||
|
public void setWechat(String wechat) { |
||||
|
this.wechat = wechat; |
||||
|
} |
||||
|
|
||||
|
public String getAccount() { |
||||
|
return account; |
||||
|
} |
||||
|
|
||||
|
public void setAccount(String account) { |
||||
|
this.account = account; |
||||
|
} |
||||
|
|
||||
|
public String getAccountNumber() { |
||||
|
return accountNumber; |
||||
|
} |
||||
|
|
||||
|
public void setAccountNumber(String accountNumber) { |
||||
|
this.accountNumber = accountNumber; |
||||
|
} |
||||
|
|
||||
|
public String getBank() { |
||||
|
return bank; |
||||
|
} |
||||
|
|
||||
|
public void setBank(String bank) { |
||||
|
this.bank = bank; |
||||
|
} |
||||
|
|
||||
|
public String getAddress() { |
||||
|
return address; |
||||
|
} |
||||
|
|
||||
|
public void setAddress(String address) { |
||||
|
this.address = address; |
||||
|
} |
||||
|
|
||||
|
public String getFollowup() { |
||||
|
return followup; |
||||
|
} |
||||
|
|
||||
|
public void setFollowup(String followup) { |
||||
|
this.followup = followup; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,88 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @Description: 企业实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class Enterprise { |
||||
|
private String id;//企业id
|
||||
|
private String company;//企业名称
|
||||
|
private String region;//地区
|
||||
|
private String level;//企业等级
|
||||
|
private String type;//企业类型
|
||||
|
private String demand;//企业需求
|
||||
|
private String spec;//规格
|
||||
|
|
||||
|
// 无参构造器
|
||||
|
public Enterprise() { |
||||
|
} |
||||
|
public Enterprise(String id, String company, String region, String level, String type, String demand, String spec) { |
||||
|
this.id = id; |
||||
|
this.company = company; |
||||
|
this.region = region; |
||||
|
this.level = level; |
||||
|
this.type = type; |
||||
|
this.demand = demand; |
||||
|
this.spec = spec; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getCompany() { |
||||
|
return company; |
||||
|
} |
||||
|
|
||||
|
public void setCompany(String company) { |
||||
|
this.company = company; |
||||
|
} |
||||
|
|
||||
|
public String getRegion() { |
||||
|
return region; |
||||
|
} |
||||
|
|
||||
|
public void setRegion(String region) { |
||||
|
this.region = region; |
||||
|
} |
||||
|
|
||||
|
public String getLevel() { |
||||
|
return level; |
||||
|
} |
||||
|
|
||||
|
public void setLevel(String level) { |
||||
|
this.level = level; |
||||
|
} |
||||
|
|
||||
|
public String getType() { |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
public void setType(String type) { |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public String getDemand() { |
||||
|
return demand; |
||||
|
} |
||||
|
|
||||
|
public void setDemand(String demand) { |
||||
|
this.demand = demand; |
||||
|
} |
||||
|
|
||||
|
public String getSpec() { |
||||
|
return spec; |
||||
|
} |
||||
|
|
||||
|
public void setSpec(String spec) { |
||||
|
this.spec = spec; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @Description: 登录实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
@NoArgsConstructor |
||||
|
public class Login { |
||||
|
private String projectName;//职位名称
|
||||
|
private String userName;//用户名
|
||||
|
private String password;//密码
|
||||
|
private Integer id;//用户id
|
||||
|
|
||||
|
|
||||
|
public String getProjectName() { |
||||
|
return projectName; |
||||
|
} |
||||
|
|
||||
|
public void setProjectName(String projectName) { |
||||
|
this.projectName = projectName; |
||||
|
} |
||||
|
|
||||
|
public Integer getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(Integer id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getPassword() { |
||||
|
return password; |
||||
|
} |
||||
|
|
||||
|
public void setPassword(String password) { |
||||
|
this.password = password; |
||||
|
} |
||||
|
|
||||
|
public String getUserName() { |
||||
|
return userName; |
||||
|
} |
||||
|
|
||||
|
public void setUserName(String userName) { |
||||
|
this.userName = userName; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,124 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* @Description: 管理员实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class Managers { |
||||
|
private Integer manager_id;//管理员id
|
||||
|
private String id;//企业id
|
||||
|
private String managerId; // 负责人id
|
||||
|
private String managercompany; // 负责公司
|
||||
|
private String managerdepartment; // 负责部门
|
||||
|
private String organization; // 负责小组
|
||||
|
private String role; // 角色
|
||||
|
private String root; // 权限
|
||||
|
private LocalDateTime created_at; // 创建时间
|
||||
|
private LocalDateTime updated_at; // 更新时间
|
||||
|
private String userName;//负责人姓名
|
||||
|
private String assistant;//协助人
|
||||
|
|
||||
|
public Integer getManager_id() { |
||||
|
return manager_id; |
||||
|
} |
||||
|
|
||||
|
public void setManager_id(Integer manager_id) { |
||||
|
this.manager_id = manager_id; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getManagerId() { |
||||
|
return managerId; |
||||
|
} |
||||
|
|
||||
|
public void setManagerId(String managerId) { |
||||
|
this.managerId = managerId; |
||||
|
} |
||||
|
|
||||
|
public String getManagercompany() { |
||||
|
return managercompany; |
||||
|
} |
||||
|
|
||||
|
public void setManagercompany(String managercompany) { |
||||
|
this.managercompany = managercompany; |
||||
|
} |
||||
|
|
||||
|
public String getManagerdepartment() { |
||||
|
return managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public void setManagerdepartment(String managerdepartment) { |
||||
|
this.managerdepartment = managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public String getOrganization() { |
||||
|
return organization; |
||||
|
} |
||||
|
|
||||
|
public void setOrganization(String organization) { |
||||
|
this.organization = organization; |
||||
|
} |
||||
|
|
||||
|
public String getRole() { |
||||
|
return role; |
||||
|
} |
||||
|
|
||||
|
public void setRole(String role) { |
||||
|
this.role = role; |
||||
|
} |
||||
|
|
||||
|
public String getRoot() { |
||||
|
return root; |
||||
|
} |
||||
|
|
||||
|
public void setRoot(String root) { |
||||
|
this.root = root; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public String getUserName() { |
||||
|
return userName; |
||||
|
} |
||||
|
|
||||
|
public void setUserName(String userName) { |
||||
|
this.userName = userName; |
||||
|
} |
||||
|
|
||||
|
public String getAssistant() { |
||||
|
return assistant; |
||||
|
} |
||||
|
|
||||
|
public void setAssistant(String assistant) { |
||||
|
this.assistant = assistant; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,161 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
// 数据库中grossWeight和price已改为varchar类型
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 产品实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
|
||||
|
public class Products { |
||||
|
private Integer id;//产品id
|
||||
|
private String productId;//产品编号
|
||||
|
private String sellerId;//卖家id
|
||||
|
private String productName;//产品名称
|
||||
|
private String price;//单价 (数据库中为varchar类型)
|
||||
|
private Integer quantity;//数量
|
||||
|
private String variety;//品种
|
||||
|
private String grossWeight;//毛重 (数据库中为varchar类型)
|
||||
|
private String specification;//规格
|
||||
|
private String status;//状态
|
||||
|
private LocalDateTime created_at;//创建时间
|
||||
|
private LocalDateTime updated_at;//更新时间
|
||||
|
private String yolk;//蛋黄
|
||||
|
private String rejectReason;//驳回原因
|
||||
|
|
||||
|
public Products(Integer id, String productId, String sellerId, String productName, String price, Integer quantity, String variety, String grossWeight, String specification, String status, LocalDateTime created_at, LocalDateTime updated_at, String yolk, String rejectReason) { |
||||
|
this.id = id; |
||||
|
this.productId = productId; |
||||
|
this.sellerId = sellerId; |
||||
|
this.productName = productName; |
||||
|
this.price = price; |
||||
|
this.quantity = quantity; |
||||
|
this.variety = variety; |
||||
|
this.grossWeight = grossWeight; |
||||
|
this.specification = specification; |
||||
|
this.status = status; |
||||
|
this.created_at = created_at; |
||||
|
this.updated_at = updated_at; |
||||
|
this.yolk = yolk; |
||||
|
this.rejectReason = rejectReason; |
||||
|
} |
||||
|
|
||||
|
public Integer getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(Integer id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getProductId() { |
||||
|
return productId; |
||||
|
} |
||||
|
|
||||
|
public void setProductId(String productId) { |
||||
|
this.productId = productId; |
||||
|
} |
||||
|
|
||||
|
public String getSellerId() { |
||||
|
return sellerId; |
||||
|
} |
||||
|
|
||||
|
public void setSellerId(String sellerId) { |
||||
|
this.sellerId = sellerId; |
||||
|
} |
||||
|
|
||||
|
public String getProductName() { |
||||
|
return productName; |
||||
|
} |
||||
|
|
||||
|
public void setProductName(String productName) { |
||||
|
this.productName = productName; |
||||
|
} |
||||
|
|
||||
|
public String getPrice() { |
||||
|
return price; |
||||
|
} |
||||
|
|
||||
|
public void setPrice(String price) { |
||||
|
this.price = price; |
||||
|
} |
||||
|
|
||||
|
public Integer getQuantity() { |
||||
|
return quantity; |
||||
|
} |
||||
|
|
||||
|
public void setQuantity(Integer quantity) { |
||||
|
this.quantity = quantity; |
||||
|
} |
||||
|
|
||||
|
public String getVariety() { |
||||
|
return variety; |
||||
|
} |
||||
|
|
||||
|
public void setVariety(String variety) { |
||||
|
this.variety = variety; |
||||
|
} |
||||
|
|
||||
|
public String getGrossWeight() { |
||||
|
return grossWeight; |
||||
|
} |
||||
|
|
||||
|
public void setGrossWeight(String grossWeight) { |
||||
|
this.grossWeight = grossWeight; |
||||
|
} |
||||
|
|
||||
|
public String getSpecification() { |
||||
|
return specification; |
||||
|
} |
||||
|
|
||||
|
public void setSpecification(String specification) { |
||||
|
this.specification = specification; |
||||
|
} |
||||
|
|
||||
|
public String getStatus() { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
public void setStatus(String status) { |
||||
|
this.status = status; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public String getYolk() { |
||||
|
return yolk; |
||||
|
} |
||||
|
|
||||
|
public void setYolk(String yolk) { |
||||
|
this.yolk = yolk; |
||||
|
} |
||||
|
|
||||
|
public String getRejectReason() { |
||||
|
return rejectReason; |
||||
|
} |
||||
|
|
||||
|
public void setRejectReason(String rejectReason) { |
||||
|
this.rejectReason = rejectReason; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
/** |
||||
|
* @Description: 权限划分实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
@AllArgsConstructor |
||||
|
@NoArgsConstructor |
||||
|
public class Rootdb { |
||||
|
private String projectName;//职位名称
|
||||
|
private Integer root;//权限划分
|
||||
|
|
||||
|
|
||||
|
public String getProjectName() { |
||||
|
return projectName; |
||||
|
} |
||||
|
|
||||
|
public void setProjectName(String projectName) { |
||||
|
this.projectName = projectName; |
||||
|
} |
||||
|
|
||||
|
public Integer getRoot() { |
||||
|
return root; |
||||
|
} |
||||
|
|
||||
|
public void setRoot(Integer root) { |
||||
|
this.root = root; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,228 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* 用户实体类 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class Users { |
||||
|
private Integer id;//用户id
|
||||
|
private String openid;//用户唯一标识
|
||||
|
private String userId;//用户id
|
||||
|
private String nickName;//用户昵称
|
||||
|
private String avatarUrl;//用户头像
|
||||
|
private String phoneNumber;//用户手机号
|
||||
|
private String type;//用户类型
|
||||
|
private Integer gender;//用户性别
|
||||
|
private String country;//国家
|
||||
|
private String province;//省份
|
||||
|
private String city;//城市
|
||||
|
private String language;//语言
|
||||
|
private String session_key;//会话密钥
|
||||
|
private LocalDateTime created_at;//创建时间
|
||||
|
private LocalDateTime updated_at;//更新时间
|
||||
|
private String company;//客户公司
|
||||
|
private String region;//客户地区
|
||||
|
private String level;//客户等级
|
||||
|
private String demand;//客户需求
|
||||
|
private String spec;//规格
|
||||
|
private String followup;//跟进信息
|
||||
|
|
||||
|
public Users(Integer id, String openid, String userId, String nickName, String avatarUrl, String phoneNumber, String type, Integer gender, String country, String province, String city, String language, String session_key, LocalDateTime created_at, LocalDateTime updated_at, String company, String region, String level, String demand, String spec, String followup) { |
||||
|
this.id = id; |
||||
|
this.openid = openid; |
||||
|
this.userId = userId; |
||||
|
this.nickName = nickName; |
||||
|
this.avatarUrl = avatarUrl; |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
this.type = type; |
||||
|
this.gender = gender; |
||||
|
this.country = country; |
||||
|
this.province = province; |
||||
|
this.city = city; |
||||
|
this.language = language; |
||||
|
this.session_key = session_key; |
||||
|
this.created_at = created_at; |
||||
|
this.updated_at = updated_at; |
||||
|
this.company = company; |
||||
|
this.region = region; |
||||
|
this.level = level; |
||||
|
this.demand = demand; |
||||
|
this.spec = spec; |
||||
|
this.followup = followup; |
||||
|
} |
||||
|
|
||||
|
public Integer getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(Integer id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getOpenid() { |
||||
|
return openid; |
||||
|
} |
||||
|
|
||||
|
public void setOpenid(String openid) { |
||||
|
this.openid = openid; |
||||
|
} |
||||
|
|
||||
|
public String getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) { |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() { |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) { |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getAvatarUrl() { |
||||
|
return avatarUrl; |
||||
|
} |
||||
|
|
||||
|
public void setAvatarUrl(String avatarUrl) { |
||||
|
this.avatarUrl = avatarUrl; |
||||
|
} |
||||
|
|
||||
|
public String getPhoneNumber() { |
||||
|
return phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public void setPhoneNumber(String phoneNumber) { |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public String getType() { |
||||
|
return type; |
||||
|
} |
||||
|
|
||||
|
public void setType(String type) { |
||||
|
this.type = type; |
||||
|
} |
||||
|
|
||||
|
public Integer getGender() { |
||||
|
return gender; |
||||
|
} |
||||
|
|
||||
|
public void setGender(Integer gender) { |
||||
|
this.gender = gender; |
||||
|
} |
||||
|
|
||||
|
public String getCountry() { |
||||
|
return country; |
||||
|
} |
||||
|
|
||||
|
public void setCountry(String country) { |
||||
|
this.country = country; |
||||
|
} |
||||
|
|
||||
|
public String getProvince() { |
||||
|
return province; |
||||
|
} |
||||
|
|
||||
|
public void setProvince(String province) { |
||||
|
this.province = province; |
||||
|
} |
||||
|
|
||||
|
public String getCity() { |
||||
|
return city; |
||||
|
} |
||||
|
|
||||
|
public void setCity(String city) { |
||||
|
this.city = city; |
||||
|
} |
||||
|
|
||||
|
public String getLanguage() { |
||||
|
return language; |
||||
|
} |
||||
|
|
||||
|
public void setLanguage(String language) { |
||||
|
this.language = language; |
||||
|
} |
||||
|
|
||||
|
public String getSession_key() { |
||||
|
return session_key; |
||||
|
} |
||||
|
|
||||
|
public void setSession_key(String session_key) { |
||||
|
this.session_key = session_key; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public String getCompany() { |
||||
|
return company; |
||||
|
} |
||||
|
|
||||
|
public void setCompany(String company) { |
||||
|
this.company = company; |
||||
|
} |
||||
|
|
||||
|
public String getRegion() { |
||||
|
return region; |
||||
|
} |
||||
|
|
||||
|
public void setRegion(String region) { |
||||
|
this.region = region; |
||||
|
} |
||||
|
|
||||
|
public String getLevel() { |
||||
|
return level; |
||||
|
} |
||||
|
|
||||
|
public void setLevel(String level) { |
||||
|
this.level = level; |
||||
|
} |
||||
|
|
||||
|
public String getDemand() { |
||||
|
return demand; |
||||
|
} |
||||
|
|
||||
|
public void setDemand(String demand) { |
||||
|
this.demand = demand; |
||||
|
} |
||||
|
|
||||
|
public String getSpec() { |
||||
|
return spec; |
||||
|
} |
||||
|
|
||||
|
public void setSpec(String spec) { |
||||
|
this.spec = spec; |
||||
|
} |
||||
|
|
||||
|
public String getFollowup() { |
||||
|
return followup; |
||||
|
} |
||||
|
|
||||
|
public void setFollowup(String followup) { |
||||
|
this.followup = followup; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,122 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
@Data |
||||
|
public class UsersContacts { |
||||
|
private String userId;//用户id
|
||||
|
private String id;//联系人id
|
||||
|
private String nickName;//联系人姓名
|
||||
|
private String phoneNumber;//联系人电话
|
||||
|
private String wechat;//联系人微信
|
||||
|
private String account;//联系人账号
|
||||
|
private String accountNumber;//联系人账号
|
||||
|
private String bank;//联系人银行
|
||||
|
private String address;//联系人地址
|
||||
|
private LocalDateTime created_at;//创建时间
|
||||
|
private LocalDateTime updated_at;//更新时间
|
||||
|
|
||||
|
|
||||
|
public UsersContacts(String userId, String id, String nickName, String phoneNumber, String wechat, String account, String accountNumber, String bank, String address, LocalDateTime created_at, LocalDateTime updated_at) { |
||||
|
this.userId = userId; |
||||
|
this.id = id; |
||||
|
this.nickName = nickName; |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
this.wechat = wechat; |
||||
|
this.account = account; |
||||
|
this.accountNumber = accountNumber; |
||||
|
this.bank = bank; |
||||
|
this.address = address; |
||||
|
this.created_at = created_at; |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public String getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) { |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getNickName() { |
||||
|
return nickName; |
||||
|
} |
||||
|
|
||||
|
public void setNickName(String nickName) { |
||||
|
this.nickName = nickName; |
||||
|
} |
||||
|
|
||||
|
public String getPhoneNumber() { |
||||
|
return phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public void setPhoneNumber(String phoneNumber) { |
||||
|
this.phoneNumber = phoneNumber; |
||||
|
} |
||||
|
|
||||
|
public String getWechat() { |
||||
|
return wechat; |
||||
|
} |
||||
|
|
||||
|
public void setWechat(String wechat) { |
||||
|
this.wechat = wechat; |
||||
|
} |
||||
|
|
||||
|
public String getAccount() { |
||||
|
return account; |
||||
|
} |
||||
|
|
||||
|
public void setAccount(String account) { |
||||
|
this.account = account; |
||||
|
} |
||||
|
|
||||
|
public String getAccountNumber() { |
||||
|
return accountNumber; |
||||
|
} |
||||
|
|
||||
|
public void setAccountNumber(String accountNumber) { |
||||
|
this.accountNumber = accountNumber; |
||||
|
} |
||||
|
|
||||
|
public String getBank() { |
||||
|
return bank; |
||||
|
} |
||||
|
|
||||
|
public void setBank(String bank) { |
||||
|
this.bank = bank; |
||||
|
} |
||||
|
|
||||
|
public String getAddress() { |
||||
|
return address; |
||||
|
} |
||||
|
|
||||
|
public void setAddress(String address) { |
||||
|
this.address = address; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,127 @@ |
|||||
|
package com.example.web.entity; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
/** |
||||
|
* 负责人信息实体类 |
||||
|
* 对应wechat_app数据源中的用户管理表 |
||||
|
* 存储微信小程序用户的负责人信息 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class UsersManagements { |
||||
|
|
||||
|
private Integer id; // 自增主键id
|
||||
|
private String userId; // 用户id
|
||||
|
private String managerId; // 负责人id
|
||||
|
private String managercompany; // 负责公司
|
||||
|
private String managerdepartment; // 负责部门
|
||||
|
private String organization; // 负责小组
|
||||
|
private String role; // 角色
|
||||
|
private String root; // 权限
|
||||
|
private LocalDateTime created_at; // 创建时间
|
||||
|
private LocalDateTime updated_at; // 更新时间
|
||||
|
private String userName;//负责人姓名
|
||||
|
private String assistant;//协助人
|
||||
|
|
||||
|
public Integer getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(Integer id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getUserId() { |
||||
|
return userId; |
||||
|
} |
||||
|
|
||||
|
public void setUserId(String userId) { |
||||
|
this.userId = userId; |
||||
|
} |
||||
|
|
||||
|
public String getManagerId() { |
||||
|
return managerId; |
||||
|
} |
||||
|
|
||||
|
public void setManagerId(String managerId) { |
||||
|
this.managerId = managerId; |
||||
|
} |
||||
|
|
||||
|
public String getManagercompany() { |
||||
|
return managercompany; |
||||
|
} |
||||
|
|
||||
|
public void setManagercompany(String managercompany) { |
||||
|
this.managercompany = managercompany; |
||||
|
} |
||||
|
|
||||
|
public String getManagerdepartment() { |
||||
|
return managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public void setManagerdepartment(String managerdepartment) { |
||||
|
this.managerdepartment = managerdepartment; |
||||
|
} |
||||
|
|
||||
|
public String getOrganization() { |
||||
|
return organization; |
||||
|
} |
||||
|
|
||||
|
public void setOrganization(String organization) { |
||||
|
this.organization = organization; |
||||
|
} |
||||
|
|
||||
|
public String getRole() { |
||||
|
return role; |
||||
|
} |
||||
|
|
||||
|
public void setRole(String role) { |
||||
|
this.role = role; |
||||
|
} |
||||
|
|
||||
|
public String getRoot() { |
||||
|
return root; |
||||
|
} |
||||
|
|
||||
|
public void setRoot(String root) { |
||||
|
this.root = root; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getCreated_at() { |
||||
|
return created_at; |
||||
|
} |
||||
|
|
||||
|
public void setCreated_at(LocalDateTime created_at) { |
||||
|
this.created_at = created_at; |
||||
|
} |
||||
|
|
||||
|
public LocalDateTime getUpdated_at() { |
||||
|
return updated_at; |
||||
|
} |
||||
|
|
||||
|
public void setUpdated_at(LocalDateTime updated_at) { |
||||
|
this.updated_at = updated_at; |
||||
|
} |
||||
|
|
||||
|
public String getUserName() { |
||||
|
return userName; |
||||
|
} |
||||
|
|
||||
|
public void setUserName(String userName) { |
||||
|
this.userName = userName; |
||||
|
} |
||||
|
|
||||
|
public String getAssistant() { |
||||
|
return assistant; |
||||
|
} |
||||
|
|
||||
|
public void setAssistant(String assistant) { |
||||
|
this.assistant = assistant; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface Cart_itemsMapper { |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.entity.Contacts; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
import org.apache.ibatis.annotations.Select; |
||||
|
import org.apache.ibatis.annotations.Update; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface ContactsMapper { |
||||
|
|
||||
|
// 根据企业ID查询联系人信息
|
||||
|
List<Contacts> selectContactsByEnterpriseId(String id); |
||||
|
|
||||
|
// 查询所有联系人信息
|
||||
|
List<Contacts> selectAllContacts(); |
||||
|
// 新增联系人
|
||||
|
int insertContacts(Contacts contacts); |
||||
|
// 新增:根据电话号码查询记录数(用于判断是否重复)
|
||||
|
int countByPhoneNumber(String phoneNumber); |
||||
|
// 新增:根据手机号查询联系人(关联企业信息)
|
||||
|
Contacts selectByPhoneNumber(String phoneNumber); |
||||
|
// 修改编辑功能
|
||||
|
int updateContacts(Contacts contacts); |
||||
|
|
||||
|
// 查询跟进信息
|
||||
|
@Select("SELECT followup FROM contacts WHERE phoneNumber = #{phoneNumber}") |
||||
|
String getFollowUpByPhone(@Param("phoneNumber") String phoneNumber); |
||||
|
|
||||
|
// 更新跟进信息
|
||||
|
@Update("UPDATE contacts SET followup = #{followup} WHERE phoneNumber = #{phoneNumber}") |
||||
|
int updateFollowUpByPhone(@Param("phoneNumber") String phoneNumber, @Param("followup") String followup); |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.dto.EnterpriseInfoDTO; |
||||
|
import com.example.web.entity.Enterprise; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface EnterpriseMapper { |
||||
|
|
||||
|
// 查询所有企业及其联系人和负责人信息
|
||||
|
List<EnterpriseInfoDTO> selectAllEnterpriseInfo(); |
||||
|
|
||||
|
// 根据企业ID查询详细信息
|
||||
|
EnterpriseInfoDTO selectEnterpriseInfoById(String id); |
||||
|
|
||||
|
// 查询所有企业基本信息
|
||||
|
List<Enterprise> selectAllEnterprises(); |
||||
|
// 新增企业
|
||||
|
int insertEnterprise(Enterprise enterprise); |
||||
|
//编辑修改
|
||||
|
int updateEnterprise(Enterprise enterprise); |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.entity.Login; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("primary") |
||||
|
public interface LoginMapper { |
||||
|
|
||||
|
|
||||
|
// 移除 @Select 注解,使用 XML 配置
|
||||
|
Login findByProjectNameAndUserName(@Param("projectName") String projectName, |
||||
|
@Param("userName") String userName); |
||||
|
|
||||
|
// 新增方法 - 支持动态查询
|
||||
|
List<Login> findByConditions(@Param("projectName") String projectName, |
||||
|
@Param("userName") String userName); |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.entity.Managers; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface ManagersMapper { |
||||
|
List<Managers> selectManagersByEnterpriseId(String id); |
||||
|
|
||||
|
// 查询所有负责人信息
|
||||
|
List<Managers> selectAllManagers(); |
||||
|
|
||||
|
// 分页查询负责人信息
|
||||
|
List<Managers> selectAllManagersWithPagination(@Param("limit") int limit, @Param("offset") int offset); |
||||
|
|
||||
|
// 获取负责人总数
|
||||
|
int getManagersCount(); |
||||
|
|
||||
|
// 新增负责人
|
||||
|
int insertManagers(Managers managers); |
||||
|
|
||||
|
//编辑修改
|
||||
|
int updateManagers(Managers managers); |
||||
|
|
||||
|
// 根据负责人姓名查询
|
||||
|
List<Managers> selectByUserName(@Param("userName") String userName); |
||||
|
|
||||
|
// 🔥 新增:根据用户名和managerId查询
|
||||
|
List<Managers> selectByUserNameAndManagerId(@Param("userName") String userName, |
||||
|
@Param("managerId") String managerId); |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface ProductsMapper { |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.entity.Rootdb; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 权限信息Mapper接口 |
||||
|
* 对应userlogin数据源中的权限表操作 |
||||
|
* 使用@DataSource("primary")注解指定数据源 |
||||
|
*/ |
||||
|
@Mapper |
||||
|
@DataSource("primary") |
||||
|
public interface RootdbMapper { |
||||
|
// 权限信息相关的数据库操作方法将在这里定义
|
||||
|
// 移除 @Select 注解,使用 XML 配置
|
||||
|
Rootdb findByProjectName(@Param("projectName") String projectName); |
||||
|
|
||||
|
// 新增方法
|
||||
|
List<Rootdb> findAll(); |
||||
|
|
||||
|
List<Rootdb> findByRootLevel(@Param("root") Integer root); |
||||
|
|
||||
|
List<Rootdb> findByProjectNames(@Param("projectNames") List<String> projectNames); |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface SupplyCart_itemsMapper { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.entity.Contacts; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface SupplyContactsMapper { |
||||
|
|
||||
|
// 根据企业ID查询联系人信息
|
||||
|
List<Contacts> selectContactsByEnterpriseId(String id); |
||||
|
|
||||
|
// 查询所有联系人信息
|
||||
|
List<Contacts> selectAllContacts(); |
||||
|
// 新增联系人
|
||||
|
int insertContacts(Contacts contacts); |
||||
|
// 新增:根据电话号码查询记录数(用于判断是否重复)
|
||||
|
int countByPhoneNumber(String phoneNumber); |
||||
|
// 新增:根据手机号查询联系人(关联企业信息)
|
||||
|
Contacts selectByPhoneNumber(String phoneNumber); |
||||
|
// 修改编辑功能
|
||||
|
int updateContacts(Contacts contacts); |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.dto.EnterpriseInfoDTO; |
||||
|
import com.example.web.entity.Enterprise; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface SupplyEnterpriseMapper { |
||||
|
|
||||
|
// 查询所有企业及其联系人和负责人信息
|
||||
|
List<EnterpriseInfoDTO> selectAllEnterpriseInfo(); |
||||
|
|
||||
|
// 根据企业ID查询详细信息
|
||||
|
EnterpriseInfoDTO selectEnterpriseInfoById(String id); |
||||
|
|
||||
|
// 查询所有企业基本信息
|
||||
|
List<Enterprise> selectAllEnterprises(); |
||||
|
// 新增企业
|
||||
|
int insertEnterprise(Enterprise enterprise); |
||||
|
//编辑修改
|
||||
|
int updateEnterprise(Enterprise enterprise); |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.entity.Managers; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
public interface SupplyManagersMapper { |
||||
|
List<Managers> selectManagersByEnterpriseId(String id); |
||||
|
|
||||
|
// 查询所有负责人信息
|
||||
|
List<Managers> selectAllManagers(); |
||||
|
|
||||
|
// 新增负责人
|
||||
|
int insertManagers(Managers managers); |
||||
|
|
||||
|
//编辑修改
|
||||
|
int updateManagers(Managers managers); |
||||
|
|
||||
|
// 根据负责人姓名查询
|
||||
|
List<Managers> selectByUserName(@Param("userName") String userName); |
||||
|
|
||||
|
// 🔥 新增:根据用户名和managerId查询
|
||||
|
List<Managers> selectByUserNameAndManagerId(@Param("userName") String userName, |
||||
|
@Param("managerId") String managerId); |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface SupplyProductsMapper { |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 负责人信息Mapper接口 |
||||
|
* 对应wechat_app数据源中的负责人信息表操作 |
||||
|
* 使用@DataSource("wechat")注解指定数据源 |
||||
|
*/ |
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface SupplyUsersManagementsMapper { |
||||
|
// 负责人信息相关的数据库操作方法将在这里定义
|
||||
|
|
||||
|
// 🔥 新增:根据用户名和managerId查询
|
||||
|
List<UsersManagements> findByUserNameAndManagerId(@Param("userName") String userName, |
||||
|
@Param("managerId") String managerId); |
||||
|
|
||||
|
// 新增方法
|
||||
|
List<UsersManagements> findByDepartment(@Param("department") String department); |
||||
|
|
||||
|
List<UsersManagements> findByConditions(@Param("userName") String userName, |
||||
|
@Param("department") String department, |
||||
|
@Param("company") String company, |
||||
|
@Param("role") String role); |
||||
|
/** |
||||
|
* 根据用户ID查询负责人信息 |
||||
|
*/ |
||||
|
UsersManagements findByUserId(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 插入负责人信息 |
||||
|
*/ |
||||
|
int insertUsersManagements(UsersManagements usersManagements); |
||||
|
|
||||
|
/** |
||||
|
* 更新负责人信息 |
||||
|
*/ |
||||
|
int updateUsersManagements(UsersManagements usersManagements); |
||||
|
|
||||
|
// 🔥 新增:更新负责人信息的更新时间(不改变负责人本身)
|
||||
|
boolean updateManagerUpdateTime(@Param("userId") String userId, @Param("updatedAt") LocalDateTime updatedAt); |
||||
|
|
||||
|
// 🔥 新增:查询指定客户的完整负责人信息
|
||||
|
UsersManagements findCompleteManagerInfoByUserId(String userId); |
||||
|
|
||||
|
// 新增:根据用户ID和认证信息直接查询匹配的负责人
|
||||
|
UsersManagements findByUserIdAndAuthInfo(@Param("userId") String userId, |
||||
|
@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 新增:批量查询用户权限
|
||||
|
List<String> findAuthorizedUserIds(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户负责人信息
|
||||
|
List<UsersManagements> findByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,266 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
import org.apache.ibatis.annotations.Select; |
||||
|
import org.apache.ibatis.annotations.Update; |
||||
|
|
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface SupplyUsersMapper { |
||||
|
// 获取用户基本信息
|
||||
|
UserProductCartDTO getUserBasicInfo(@Param("userId") String userId); |
||||
|
|
||||
|
// 获取卖家的产品信息
|
||||
|
List<UserProductCartDTO.ProductInfo> getSellerProducts(@Param("sellerId") String sellerId); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取所有用户的基本信息 |
||||
|
*/ |
||||
|
List<UserProductCartDTO> getAllUserBasicInfo(); |
||||
|
|
||||
|
// 新增根据手机号查询用户的方法
|
||||
|
UserProductCartDTO selectByPhone(@Param("phoneNumber") String phoneNumber); |
||||
|
|
||||
|
// 新增:根据用户ID精确查询用户
|
||||
|
UserProductCartDTO selectByUserId(@Param("userId") String userId); |
||||
|
|
||||
|
// 新增:更新公海需求信息
|
||||
|
int updateProduct( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("product") UserProductCartDTO.ProductInfo product |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号更新用户信息 |
||||
|
*/ |
||||
|
int updateByPhone(UserProductCartDTO user); |
||||
|
|
||||
|
/** |
||||
|
* 更新卖家产品信息 |
||||
|
*/ |
||||
|
int updateProductBySellerId( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 更新用户联系人信息 - 更新第一个联系人(向后兼容) |
||||
|
*/ |
||||
|
int updateContactsByUserId( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 获取用户联系人信息 - 获取第一个联系人(向后兼容) |
||||
|
*/ |
||||
|
List<UserProductCartDTO.UsersContacts> getUserContacts(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 更新或插入联系人信息 |
||||
|
*/ |
||||
|
int updateOrInsertContact( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("contactId") String contactId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 采购端:更新或插入产品信息(类似购物车的updateOrInsertCartItem) |
||||
|
*/ |
||||
|
int updateOrInsertProduct( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk, |
||||
|
@Param("price") String price |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 更新特定联系人信息 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
int updateSpecificContact( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("contactId") String contactId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 采购端:更新特定产品信息 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
int updateSpecificProduct( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 获取用户所有联系人 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
List<ContactInfo> getUserAllContacts(@Param("userId") String userId); |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 采购端:获取用户所有产品信息 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
List<ProductInfo> getUserAllProducts(@Param("sellerId") String sellerId); |
||||
|
|
||||
|
// 联系人信息内部类 - 用于一对多查询
|
||||
|
class ContactInfo { |
||||
|
private String contactId; |
||||
|
private String userId; |
||||
|
private String wechat; |
||||
|
private String account; |
||||
|
private String accountNumber; |
||||
|
private String bank; |
||||
|
private String address; |
||||
|
|
||||
|
public String getContactId() { return contactId; } |
||||
|
public void setContactId(String contactId) { this.contactId = contactId; } |
||||
|
public String getUserId() { return userId; } |
||||
|
public void setUserId(String userId) { this.userId = userId; } |
||||
|
public String getWechat() { return wechat; } |
||||
|
public void setWechat(String wechat) { this.wechat = wechat; } |
||||
|
public String getAccount() { return account; } |
||||
|
public void setAccount(String account) { this.account = account; } |
||||
|
public String getAccountNumber() { return accountNumber; } |
||||
|
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } |
||||
|
public String getBank() { return bank; } |
||||
|
public void setBank(String bank) { this.bank = bank; } |
||||
|
public String getAddress() { return address; } |
||||
|
public void setAddress(String address) { this.address = address; } |
||||
|
} |
||||
|
|
||||
|
// 产品信息内部类 - 用于一对多查询
|
||||
|
class ProductInfo { |
||||
|
private String productId; |
||||
|
private String userId; |
||||
|
private String productName; |
||||
|
private String variety; |
||||
|
private String specification; |
||||
|
private Integer quantity; |
||||
|
private String grossWeight; |
||||
|
private String yolk; |
||||
|
|
||||
|
public String getProductId() { return productId; } |
||||
|
public void setProductId(String productId) { this.productId = productId; } |
||||
|
public String getUserId() { return userId; } |
||||
|
public void setUserId(String userId) { this.userId = userId; } |
||||
|
public String getProductName() { return productName; } |
||||
|
public void setProductName(String productName) { this.productName = productName; } |
||||
|
public String getVariety() { return variety; } |
||||
|
public void setVariety(String variety) { this.variety = variety; } |
||||
|
public String getSpecification() { return specification; } |
||||
|
public void setSpecification(String specification) { this.specification = specification; } |
||||
|
public Integer getQuantity() { return quantity; } |
||||
|
public void setQuantity(Integer quantity) { this.quantity = quantity; } |
||||
|
public String getGrossWeight() { return grossWeight; } |
||||
|
public void setGrossWeight(String grossWeight) { this.grossWeight = grossWeight; } |
||||
|
public String getYolk() { return yolk; } |
||||
|
public void setYolk(String yolk) { this.yolk = yolk; } |
||||
|
} |
||||
|
/** |
||||
|
* 根据产品ID精确更新产品信息 |
||||
|
*/ |
||||
|
int updateProductByProductId( |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
// 在 SupplyUsersMapper.java 中添加以下方法
|
||||
|
|
||||
|
/** |
||||
|
* 查询超过指定时间的未分级客户 |
||||
|
*/ |
||||
|
List<UserProductCartDTO> findUnclassifiedCustomersOlderThan(LocalDateTime thresholdTime); |
||||
|
|
||||
|
/** |
||||
|
* 查询超过指定时间的组织公海池客户 |
||||
|
*/ |
||||
|
List<UserProductCartDTO> findOrganizationSeaPoolsCustomersOlderThan(LocalDateTime thresholdTime); |
||||
|
|
||||
|
/** |
||||
|
* 更新客户等级 |
||||
|
*/ |
||||
|
@Update("UPDATE users SET level = #{level}, updated_at = #{updateTime} WHERE user_id = #{userId}") |
||||
|
boolean updateCustomerLevel(@Param("userId") String userId, |
||||
|
@Param("level") String level, |
||||
|
@Param("updateTime") LocalDateTime updateTime); |
||||
|
// 🔥 新增:查询最近回流的客户
|
||||
|
List<UserProductCartDTO> findRecentlyRecycledCustomers(@Param("sinceTime") LocalDateTime sinceTime); |
||||
|
|
||||
|
// 新增:直接查询有权限的客户列表(支持分页)
|
||||
|
List<UserProductCartDTO> getAuthorizedCustomers(@Param("authInfo") ManagerAuthInfo authInfo, @Param("limit") int limit, @Param("offset") int offset); |
||||
|
|
||||
|
/** |
||||
|
* 根据认证信息获取有权限的用户ID列表 |
||||
|
*/ |
||||
|
List<String> getAuthorizedUserIds(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 获取授权客户总数
|
||||
|
int getAuthorizedCustomersCount(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号和权限查询用户 |
||||
|
*/ |
||||
|
UserProductCartDTO selectByPhoneWithAuth(@Param("phoneNumber") String phoneNumber, |
||||
|
@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户联系人信息
|
||||
|
List<UsersMapper.ContactInfo> getUserContactsByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户产品信息
|
||||
|
List<UserProductCartDTO.ProductInfo> getSellerProductsByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户基本信息
|
||||
|
List<UserProductCartDTO> getUserBasicInfoByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
// 查询跟进信息
|
||||
|
@Select("SELECT followup FROM users WHERE phoneNumber = #{phoneNumber}") |
||||
|
String getFollowUpByPhone(@Param("phoneNumber") String phoneNumber); |
||||
|
|
||||
|
// 更新跟进信息
|
||||
|
@Update("UPDATE users SET followup = #{followup} WHERE phoneNumber = #{phoneNumber}") |
||||
|
int updateFollowUpByPhone(@Param("phoneNumber") String phoneNumber, @Param("followup") String followup); |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 负责人信息Mapper接口 |
||||
|
* 对应wechat_app数据源中的负责人信息表操作 |
||||
|
* 使用@DataSource("wechat")注解指定数据源 |
||||
|
*/ |
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface UsersManagementsMapper { |
||||
|
// 负责人信息相关的数据库操作方法将在这里定义
|
||||
|
|
||||
|
// 🔥 新增:根据用户名和managerId查询
|
||||
|
List<UsersManagements> findByUserNameAndManagerId(@Param("userName") String userName, |
||||
|
@Param("managerId") String managerId); |
||||
|
|
||||
|
// 新增方法
|
||||
|
List<UsersManagements> findByDepartment(@Param("department") String department); |
||||
|
|
||||
|
List<UsersManagements> findByConditions(@Param("userName") String userName, |
||||
|
@Param("department") String department, |
||||
|
@Param("company") String company, |
||||
|
@Param("role") String role); |
||||
|
/** |
||||
|
* 根据用户ID查询负责人信息 |
||||
|
*/ |
||||
|
UsersManagements findByUserId(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 插入负责人信息 |
||||
|
*/ |
||||
|
int insertUsersManagements(UsersManagements usersManagements); |
||||
|
|
||||
|
/** |
||||
|
* 更新负责人信息 |
||||
|
*/ |
||||
|
int updateUsersManagements(UsersManagements usersManagements); |
||||
|
|
||||
|
// 🔥 新增:更新负责人信息的更新时间(不改变负责人本身)
|
||||
|
boolean updateManagerUpdateTime(@Param("userId") String userId, @Param("updatedAt") LocalDateTime updatedAt); |
||||
|
|
||||
|
// 🔥 新增:查询指定客户的完整负责人信息
|
||||
|
UsersManagements findCompleteManagerInfoByUserId(String userId); |
||||
|
|
||||
|
// 新增:根据用户ID和认证信息直接查询匹配的负责人
|
||||
|
UsersManagements findByUserIdAndAuthInfo(@Param("userId") String userId, |
||||
|
@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 新增:批量查询用户权限
|
||||
|
List<String> findAuthorizedUserIds(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户负责人信息
|
||||
|
List<UsersManagements> findByUserIds(@Param("userIds") List<String> userIds); |
||||
|
} |
||||
@ -0,0 +1,269 @@ |
|||||
|
package com.example.web.mapper; |
||||
|
|
||||
|
import com.example.web.annotation.DataSource; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import org.apache.ibatis.annotations.Mapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
import org.apache.ibatis.annotations.Update; |
||||
|
|
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Mapper |
||||
|
@DataSource("wechat") |
||||
|
public interface UsersMapper { |
||||
|
// 获取用户基本信息
|
||||
|
UserProductCartDTO getUserBasicInfo(@Param("userId") String userId); |
||||
|
|
||||
|
// 获取卖家的产品信息
|
||||
|
List<UserProductCartDTO.ProductInfo> getSellerProducts(@Param("sellerId") String sellerId); |
||||
|
|
||||
|
// 销售端:获取买家的购物车信息(公海需求)
|
||||
|
List<UserProductCartDTO.CartItem> getBuyerCartItems(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 销售端:获取所有买家用户的基本信息(类型为buyer和both) |
||||
|
*/ |
||||
|
List<UserProductCartDTO> getAllUserBasicInfo(); |
||||
|
|
||||
|
// 销售端:根据手机号查询买家用户
|
||||
|
UserProductCartDTO selectByPhone(@Param("phoneNumber") String phoneNumber); |
||||
|
|
||||
|
// 新增:根据用户ID精确查询用户
|
||||
|
UserProductCartDTO selectByUserId(@Param("userId") String userId); |
||||
|
|
||||
|
// 新增:更新公海需求信息
|
||||
|
int updateProduct( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("product") UserProductCartDTO.ProductInfo product |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号更新用户信息 |
||||
|
*/ |
||||
|
int updateByPhone(UserProductCartDTO user); |
||||
|
|
||||
|
/** |
||||
|
* 更新卖家产品信息 |
||||
|
*/ |
||||
|
int updateProductBySellerId( |
||||
|
@Param("sellerId") String sellerId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 销售端:更新买家购物车信息 - 更新第一个购物车项(向后兼容) |
||||
|
*/ |
||||
|
int updateCartItemByBuyerId( |
||||
|
@Param("buyerId") String buyerId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 更新用户联系人信息 - 更新第一个联系人(向后兼容) |
||||
|
*/ |
||||
|
int updateContactsByUserId( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 获取用户联系人信息 - 获取第一个联系人(向后兼容) |
||||
|
*/ |
||||
|
List<UserProductCartDTO.UsersContacts> getUserContacts(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 更新或插入联系人信息 |
||||
|
*/ |
||||
|
int updateOrInsertContact( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("contactId") String contactId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 更新或插入购物车项 |
||||
|
*/ |
||||
|
int updateOrInsertCartItem( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("cartItemId") String cartItemId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 更新特定联系人信息 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
int updateSpecificContact( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("contactId") String contactId, |
||||
|
@Param("wechat") String wechat, |
||||
|
@Param("account") String account, |
||||
|
@Param("accountNumber") String accountNumber, |
||||
|
@Param("bank") String bank, |
||||
|
@Param("address") String address |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 更新特定购物车项信息 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
int updateSpecificCartItem( |
||||
|
@Param("userId") String userId, |
||||
|
@Param("cartItemId") String cartItemId, |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* 获取用户所有联系人 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
List<ContactInfo> getUserAllContacts(@Param("userId") String userId); |
||||
|
|
||||
|
/** |
||||
|
* 获取用户所有购物车项 - 一对多逻辑新增 |
||||
|
*/ |
||||
|
List<CartItem> getUserAllCartItems(@Param("userId") String userId); |
||||
|
|
||||
|
// 联系人信息内部类 - 用于一对多查询
|
||||
|
class ContactInfo { |
||||
|
private String contactId; |
||||
|
private String userId; |
||||
|
private String wechat; |
||||
|
private String account; |
||||
|
private String accountNumber; |
||||
|
private String bank; |
||||
|
private String address; |
||||
|
|
||||
|
public String getContactId() { return contactId; } |
||||
|
public void setContactId(String contactId) { this.contactId = contactId; } |
||||
|
public String getUserId() { return userId; } |
||||
|
public void setUserId(String userId) { this.userId = userId; } |
||||
|
public String getWechat() { return wechat; } |
||||
|
public void setWechat(String wechat) { this.wechat = wechat; } |
||||
|
public String getAccount() { return account; } |
||||
|
public void setAccount(String account) { this.account = account; } |
||||
|
public String getAccountNumber() { return accountNumber; } |
||||
|
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } |
||||
|
public String getBank() { return bank; } |
||||
|
public void setBank(String bank) { this.bank = bank; } |
||||
|
public String getAddress() { return address; } |
||||
|
public void setAddress(String address) { this.address = address; } |
||||
|
} |
||||
|
|
||||
|
// 购物车项内部类 - 用于一对多查询
|
||||
|
class CartItem { |
||||
|
private String cartItemId; |
||||
|
private String userId; |
||||
|
private String productId; |
||||
|
private String productName; |
||||
|
private String specification; |
||||
|
private Integer quantity; |
||||
|
private String grossWeight; |
||||
|
private String yolk; |
||||
|
|
||||
|
public String getCartItemId() { return cartItemId; } |
||||
|
public void setCartItemId(String cartItemId) { this.cartItemId = cartItemId; } |
||||
|
public String getUserId() { return userId; } |
||||
|
public void setUserId(String userId) { this.userId = userId; } |
||||
|
public String getProductId() { return productId; } |
||||
|
public void setProductId(String productId) { this.productId = productId; } |
||||
|
public String getProductName() { return productName; } |
||||
|
public void setProductName(String productName) { this.productName = productName; } |
||||
|
public String getSpecification() { return specification; } |
||||
|
public void setSpecification(String specification) { this.specification = specification; } |
||||
|
public Integer getQuantity() { return quantity; } |
||||
|
public void setQuantity(Integer quantity) { this.quantity = quantity; } |
||||
|
public String getGrossWeight() { return grossWeight; } |
||||
|
public void setGrossWeight(String grossWeight) { this.grossWeight = grossWeight; } |
||||
|
public String getYolk() { return yolk; } |
||||
|
public void setYolk(String yolk) { this.yolk = yolk; } |
||||
|
} |
||||
|
/** |
||||
|
* 根据产品ID精确更新产品信息 |
||||
|
*/ |
||||
|
int updateProductByProductId( |
||||
|
@Param("productId") String productId, |
||||
|
@Param("productName") String productName, |
||||
|
@Param("variety") String variety, |
||||
|
@Param("specification") String specification, |
||||
|
@Param("quantity") Integer quantity, |
||||
|
@Param("grossWeight") String grossWeight, |
||||
|
@Param("yolk") String yolk |
||||
|
); |
||||
|
// 在 SupplyUsersMapper.java 中添加以下方法
|
||||
|
|
||||
|
/** |
||||
|
* 查询超过指定时间的未分级客户 |
||||
|
*/ |
||||
|
List<UserProductCartDTO> findUnclassifiedCustomersOlderThan(LocalDateTime thresholdTime); |
||||
|
|
||||
|
/** |
||||
|
* 查询超过指定时间的组织公海池客户 |
||||
|
*/ |
||||
|
List<UserProductCartDTO> findOrganizationSeaPoolsCustomersOlderThan(LocalDateTime thresholdTime); |
||||
|
|
||||
|
/** |
||||
|
* 更新客户等级 |
||||
|
*/ |
||||
|
@Update("UPDATE users SET level = #{level}, updated_at = #{updateTime} WHERE user_id = #{userId}") |
||||
|
boolean updateCustomerLevel(@Param("userId") String userId, |
||||
|
@Param("level") String level, |
||||
|
@Param("updateTime") LocalDateTime updateTime); |
||||
|
// 🔥 新增:查询最近回流的客户
|
||||
|
List<UserProductCartDTO> findRecentlyRecycledCustomers(@Param("sinceTime") LocalDateTime sinceTime); |
||||
|
|
||||
|
// 新增:直接查询有权限的客户列表(支持分页)
|
||||
|
List<UserProductCartDTO> getAuthorizedCustomers(@Param("authInfo") ManagerAuthInfo authInfo, @Param("limit") int limit, @Param("offset") int offset); |
||||
|
|
||||
|
/** |
||||
|
* 根据认证信息获取有权限的用户ID列表 |
||||
|
*/ |
||||
|
List<String> getAuthorizedUserIds(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 获取授权客户总数
|
||||
|
int getAuthorizedCustomersCount(@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号和权限查询用户 |
||||
|
*/ |
||||
|
UserProductCartDTO selectByPhoneWithAuth(@Param("phoneNumber") String phoneNumber, |
||||
|
@Param("authInfo") ManagerAuthInfo authInfo); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户联系人信息
|
||||
|
List<ContactInfo> getUserContactsByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户购物车信息
|
||||
|
List<CartItem> getCartItemsByUserIds(@Param("userIds") List<String> userIds); |
||||
|
|
||||
|
// 🔥 新增:批量查询用户基本信息
|
||||
|
List<UserProductCartDTO> getUserBasicInfoByUserIds(@Param("userIds") List<String> userIds); |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,501 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.EnterpriseInfoDTO; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UnifiedCustomerDTO; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.Enterprise; |
||||
|
import com.example.web.entity.Contacts; |
||||
|
import com.example.web.entity.Managers; |
||||
|
import com.example.web.mapper.EnterpriseMapper; |
||||
|
import com.example.web.mapper.ContactsMapper; |
||||
|
import com.example.web.mapper.ManagersMapper; |
||||
|
import com.example.web.mapper.UsersMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
@Service// 标识为Spring服务层组件,用于处理业务逻辑
|
||||
|
public class EnterpriseService { |
||||
|
|
||||
|
@Autowired// 自动注入数据访问层(Mapper)对象,用于数据库操作
|
||||
|
private EnterpriseMapper enterpriseMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private ContactsMapper contactsMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private ManagersMapper managersMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private UsersMapper usersMapper; |
||||
|
|
||||
|
|
||||
|
|
||||
|
// 修改:检查电话号码是否重复(同时检查两个数据源)
|
||||
|
public boolean isPhoneNumberDuplicate(String phoneNumber) { |
||||
|
// 1. 检查微信数据源中的电话号码是否重复
|
||||
|
boolean wechatDuplicate = false; |
||||
|
try { |
||||
|
UserProductCartDTO existingUser = usersMapper.selectByPhone(phoneNumber); |
||||
|
wechatDuplicate = existingUser != null; |
||||
|
if (wechatDuplicate) { |
||||
|
System.out.println("❌ 电话号码在微信数据源中已存在: " + phoneNumber); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("查询微信数据源电话号码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 2. 检查默认数据源(userlogin)中的电话号码是否重复
|
||||
|
boolean defaultDuplicate = false; |
||||
|
try { |
||||
|
int count = contactsMapper.countByPhoneNumber(phoneNumber); |
||||
|
defaultDuplicate = count > 0; |
||||
|
if (defaultDuplicate) { |
||||
|
System.out.println("❌ 电话号码在默认数据源中已存在: " + phoneNumber); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("查询默认数据源电话号码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 3. 返回最终结果:任意一个数据源中存在都算重复
|
||||
|
boolean isDuplicate = wechatDuplicate || defaultDuplicate; |
||||
|
System.out.println("📞 电话号码重复检查结果: " + phoneNumber + |
||||
|
" -> 微信数据源:" + wechatDuplicate + |
||||
|
", 默认数据源:" + defaultDuplicate + |
||||
|
", 最终结果:" + isDuplicate); |
||||
|
|
||||
|
return isDuplicate; |
||||
|
} |
||||
|
|
||||
|
private String convertFrontendTypeToDatabase(String frontendType) { |
||||
|
if (frontendType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (frontendType) { |
||||
|
case "供应端": |
||||
|
return "seller"; |
||||
|
case "客户端": |
||||
|
return "buyer"; |
||||
|
case "BOTH": |
||||
|
return "both"; // 改为小写
|
||||
|
default: |
||||
|
return frontendType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private String convertDatabaseTypeToFrontend(String databaseType) { |
||||
|
if (databaseType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (databaseType) { |
||||
|
case "seller": |
||||
|
return "供应端"; |
||||
|
case "buyer": |
||||
|
return "客户端"; |
||||
|
case "both": // 匹配小写的数据库存储
|
||||
|
return "BOTH"; |
||||
|
default: |
||||
|
return databaseType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
// 新增客户:保存企业、联系人、负责人信息(默认数据源)
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public boolean addCustomer(UnifiedCustomerDTO dto) { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("➕ 开始新增客户到默认数据源"); |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("📋 客户信息: 手机=" + dto.getPhoneNumber() + |
||||
|
", 公司=" + dto.getCompany() + |
||||
|
", 类型=" + dto.getType() + |
||||
|
", 等级=" + dto.getLevel()); |
||||
|
|
||||
|
// 1. 转换前端类型为数据库类型
|
||||
|
String databaseType = convertFrontendTypeToDatabase(dto.getType()); |
||||
|
dto.setType(databaseType); |
||||
|
System.out.println("🔄 类型转换: 前端=" + dto.getType() + " → 数据库=" + databaseType); |
||||
|
|
||||
|
// 2. 权限校验
|
||||
|
if (!"buyer".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
System.out.println("❌ 权限校验失败: 销售端只能新增客户端类型和BOTH客户"); |
||||
|
throw new IllegalArgumentException("采购端权限只能新增客户端类型客户和BOTH类型客户"); |
||||
|
} |
||||
|
System.out.println("✅ 权限校验通过"); |
||||
|
|
||||
|
// 3. 等级校验
|
||||
|
if (!StringUtils.hasText(dto.getLevel())) { |
||||
|
System.out.println("❌ 等级校验失败: 客户等级不能为空"); |
||||
|
throw new IllegalArgumentException("客户等级不能为空"); |
||||
|
} |
||||
|
System.out.println("✅ 等级校验通过"); |
||||
|
|
||||
|
// 4. 检查电话号码是否重复
|
||||
|
System.out.println("🔍 检查电话号码重复性..."); |
||||
|
if (isPhoneNumberDuplicate(dto.getPhoneNumber())) { |
||||
|
System.out.println("❌ 电话号码重复: " + dto.getPhoneNumber()); |
||||
|
throw new IllegalArgumentException("电话号码已存在"); |
||||
|
} |
||||
|
System.out.println("✅ 电话号码检查通过"); |
||||
|
|
||||
|
// 5. 封装并保存企业信息
|
||||
|
System.out.println("💾 保存企业信息..."); |
||||
|
Enterprise enterprise = new Enterprise(); |
||||
|
enterprise.setId(dto.getId()); |
||||
|
enterprise.setCompany(dto.getCompany()); |
||||
|
enterprise.setRegion(dto.getRegion()); |
||||
|
enterprise.setLevel(dto.getLevel()); |
||||
|
enterprise.setType(dto.getType()); |
||||
|
enterprise.setDemand(dto.getDemand()); |
||||
|
enterprise.setSpec(dto.getSpec()); |
||||
|
|
||||
|
int enterpriseRows = enterpriseMapper.insertEnterprise(enterprise); |
||||
|
System.out.println("✅ 企业信息保存结果: " + enterpriseRows + " 行受影响"); |
||||
|
|
||||
|
// 6. 封装联系人信息
|
||||
|
System.out.println("💾 保存联系人信息..."); |
||||
|
Contacts contacts = new Contacts(); |
||||
|
String contactId = UUID.randomUUID().toString().replaceAll("-", ""); |
||||
|
contacts.setContact_id(contactId); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
contacts.setPhoneNumber(dto.getPhoneNumber()); |
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
contacts.setCreated_at(dto.getCreated_at() != null ? dto.getCreated_at() : LocalDateTime.now()); |
||||
|
contacts.setUpdated_at(dto.getUpdated_at() != null ? dto.getUpdated_at() : LocalDateTime.now()); |
||||
|
|
||||
|
int contactsRows = contactsMapper.insertContacts(contacts); |
||||
|
System.out.println("✅ 联系人信息保存结果: " + contactsRows + " 行受影响"); |
||||
|
|
||||
|
// 7. 封装负责人信息 - 使用前端传递的认证信息(更新为新表结构)
|
||||
|
System.out.println("💾 保存负责人信息..."); |
||||
|
Managers managers = new Managers(); |
||||
|
managers.setId(dto.getId()); |
||||
|
managers.setManagerId(StringUtils.hasText(dto.getManagerId()) ? dto.getManagerId() : "未分配"); |
||||
|
managers.setManagercompany(StringUtils.hasText(dto.getManagercompany()) ? dto.getManagercompany() : "未分配"); |
||||
|
managers.setManagerdepartment(StringUtils.hasText(dto.getManagerdepartment()) ? dto.getManagerdepartment() : "未分配"); |
||||
|
managers.setOrganization(StringUtils.hasText(dto.getOrganization()) ? dto.getOrganization() : "未分配"); |
||||
|
managers.setRole(StringUtils.hasText(dto.getRole()) ? dto.getRole() : "未分配"); |
||||
|
managers.setRoot("3"); // 默认权限
|
||||
|
managers.setUserName(StringUtils.hasText(dto.getUserName()) ? dto.getUserName() : "未分配"); |
||||
|
managers.setAssistant(StringUtils.hasText(dto.getAssistant()) ? dto.getAssistant() : "无"); |
||||
|
managers.setCreated_at(LocalDateTime.now()); |
||||
|
managers.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int managersRows = managersMapper.insertManagers(managers); |
||||
|
System.out.println("✅ 负责人信息保存结果: " + managersRows + " 行受影响"); |
||||
|
|
||||
|
boolean success = enterpriseRows > 0 && contactsRows > 0 && managersRows > 0; |
||||
|
|
||||
|
if (success) { |
||||
|
System.out.println("🎉 新增客户成功,负责人信息已自动填充"); |
||||
|
// 记录负责人信息详情
|
||||
|
System.out.println("📝 负责人信息详情: " + |
||||
|
"负责人id=" + managers.getManagerId() + |
||||
|
"负责公司=" + managers.getManagercompany() + |
||||
|
", 负责部门=" + managers.getManagerdepartment() + |
||||
|
", 组织=" + managers.getOrganization() + |
||||
|
", 角色=" + managers.getRole() + |
||||
|
", 负责人=" + managers.getUserName() + |
||||
|
", 协助人=" + managers.getAssistant()); |
||||
|
} else { |
||||
|
System.out.println("❌ 新增客户失败"); |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有企业的完整信息(企业信息 + 联系人信息 + 负责人信息) |
||||
|
*/ |
||||
|
public List<EnterpriseInfoDTO> getAllEnterpriseInfo() { |
||||
|
try { |
||||
|
return enterpriseMapper.selectAllEnterpriseInfo(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取详细信息 |
||||
|
*/ |
||||
|
public EnterpriseInfoDTO getEnterpriseInfoById(String id) { |
||||
|
try { |
||||
|
return enterpriseMapper.selectEnterpriseInfoById(id); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有企业基本信息 |
||||
|
*/ |
||||
|
public List<Enterprise> getAllEnterprises() { |
||||
|
try { |
||||
|
return enterpriseMapper.selectAllEnterprises(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取联系人信息 |
||||
|
*/ |
||||
|
public List<Contacts> getContactsByEnterpriseId(String id) { |
||||
|
try { |
||||
|
return contactsMapper.selectContactsByEnterpriseId(id); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取负责人信息 |
||||
|
*/ |
||||
|
public List<Managers> getManagersByEnterpriseId(String id) { |
||||
|
try { |
||||
|
return managersMapper.selectManagersByEnterpriseId(id); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 搜索企业信息(根据企业名称、地区、类型等) |
||||
|
*/ |
||||
|
public List<EnterpriseInfoDTO> searchEnterprises(String keyword) { |
||||
|
try { |
||||
|
// 这里可以扩展更复杂的搜索逻辑
|
||||
|
List<EnterpriseInfoDTO> allInfo = enterpriseMapper.selectAllEnterpriseInfo(); |
||||
|
if (keyword == null || keyword.trim().isEmpty()) { |
||||
|
return allInfo; |
||||
|
} |
||||
|
|
||||
|
List<EnterpriseInfoDTO> result = new ArrayList<>(); |
||||
|
for (EnterpriseInfoDTO info : allInfo) { |
||||
|
if (info.getEnterprise() != null) { |
||||
|
String company = info.getEnterprise().getCompany() != null ? info.getEnterprise().getCompany().toLowerCase() : ""; |
||||
|
String region = info.getEnterprise().getRegion() != null ? info.getEnterprise().getRegion().toLowerCase() : ""; |
||||
|
String type = info.getEnterprise().getType() != null ? info.getEnterprise().getType().toLowerCase() : ""; |
||||
|
|
||||
|
if (company.contains(keyword.toLowerCase()) || |
||||
|
region.contains(keyword.toLowerCase()) || |
||||
|
type.contains(keyword.toLowerCase())) { |
||||
|
result.add(info); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新默认数据源客户信息(企业、联系人、负责人) |
||||
|
*/ |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public boolean updateDefaultCustomer(UnifiedCustomerDTO dto, ManagerAuthInfo authInfo) { |
||||
|
// 转换前端类型为数据库类型
|
||||
|
String databaseType = convertFrontendTypeToDatabase(dto.getType()); |
||||
|
dto.setType(databaseType); |
||||
|
|
||||
|
// 销售员权限:校验客户类型,只允许buyer和both
|
||||
|
if (!"buyer".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
throw new IllegalArgumentException("销售员权限只能更新为客户端类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 1. 更新企业信息
|
||||
|
Enterprise enterprise = new Enterprise(); |
||||
|
enterprise.setId(dto.getId()); |
||||
|
enterprise.setCompany(dto.getCompany()); |
||||
|
enterprise.setRegion(dto.getRegion()); |
||||
|
enterprise.setLevel(dto.getLevel()); |
||||
|
enterprise.setType(dto.getType()); |
||||
|
enterprise.setDemand(dto.getDemand()); |
||||
|
enterprise.setSpec(dto.getSpec()); |
||||
|
int enterpriseRows = enterpriseMapper.updateEnterprise(enterprise); |
||||
|
|
||||
|
if (enterpriseRows <= 0) { |
||||
|
throw new RuntimeException("更新企业信息失败,企业ID: " + dto.getId()); |
||||
|
} |
||||
|
|
||||
|
// 2. 更新联系人信息 - 修复逻辑
|
||||
|
Contacts contacts = new Contacts(); |
||||
|
// 先根据企业ID查询原始联系人信息
|
||||
|
List<Contacts> originalContactsList = contactsMapper.selectContactsByEnterpriseId(dto.getId()); |
||||
|
if (originalContactsList != null && !originalContactsList.isEmpty()) { |
||||
|
Contacts originalContacts = originalContactsList.get(0); |
||||
|
contacts.setContact_id(originalContacts.getContact_id()); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
// 关键:使用原始电话号码,禁止修改
|
||||
|
contacts.setPhoneNumber(originalContacts.getPhoneNumber()); |
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
|
||||
|
int contactsRows = contactsMapper.updateContacts(contacts); |
||||
|
if (contactsRows <= 0) { |
||||
|
throw new RuntimeException("更新联系人信息失败,联系人ID: " + originalContacts.getContact_id()); |
||||
|
} |
||||
|
} else { |
||||
|
// 如果没有找到联系人记录,创建新的联系人
|
||||
|
System.out.println("未找到现有联系人,创建新的联系人记录"); |
||||
|
contacts.setContact_id(UUID.randomUUID().toString().replaceAll("-", "")); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
contacts.setPhoneNumber(""); // 新创建的联系人电话号码为空
|
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
contacts.setCreated_at(LocalDateTime.now()); |
||||
|
contacts.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int contactsRows = contactsMapper.insertContacts(contacts); |
||||
|
if (contactsRows <= 0) { |
||||
|
throw new RuntimeException("创建联系人信息失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 🔥 修改:检查是否需要更新负责人信息
|
||||
|
boolean hasFrontendManagerInfo = StringUtils.hasText(dto.getManagercompany()) || |
||||
|
StringUtils.hasText(dto.getManagerdepartment()) || |
||||
|
StringUtils.hasText(dto.getOrganization()) || |
||||
|
StringUtils.hasText(dto.getRole()) || |
||||
|
StringUtils.hasText(dto.getUserName()) || |
||||
|
StringUtils.hasText(dto.getAssistant()); |
||||
|
|
||||
|
// 定义非公海池等级
|
||||
|
Set<String> nonPublicSeaLevels = Set.of("important", "normal", "low-value", "logistics", "unclassified"); |
||||
|
boolean isNonPublicSeaCustomer = nonPublicSeaLevels.contains(dto.getLevel()); |
||||
|
|
||||
|
System.out.println("🎯 负责人信息更新检查: " + |
||||
|
"是否非公海池客户=" + isNonPublicSeaCustomer + |
||||
|
", 前端是否提交负责人信息=" + hasFrontendManagerInfo); |
||||
|
|
||||
|
// 🔥 只有非公海池客户且前端提交了负责人信息时才更新
|
||||
|
if (isNonPublicSeaCustomer && hasFrontendManagerInfo) { |
||||
|
System.out.println("✅ 需要更新负责人信息"); |
||||
|
|
||||
|
Managers managers = new Managers(); |
||||
|
managers.setId(dto.getId()); |
||||
|
|
||||
|
System.out.println("✅ 前端提交了负责人信息,使用前端数据更新"); |
||||
|
// 使用前端提交的数据
|
||||
|
managers.setManagercompany(dto.getManagercompany()); |
||||
|
managers.setManagerdepartment(dto.getManagerdepartment()); |
||||
|
managers.setOrganization(dto.getOrganization()); |
||||
|
managers.setRole(dto.getRole()); |
||||
|
managers.setUserName(dto.getUserName()); |
||||
|
managers.setAssistant(dto.getAssistant()); |
||||
|
|
||||
|
managers.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int managersRows = managersMapper.updateManagers(managers); |
||||
|
if (managersRows <= 0) { |
||||
|
// 如果没有更新到记录,尝试插入
|
||||
|
System.out.println("未找到现有负责人记录,创建新的负责人记录"); |
||||
|
managers.setManagerId(authInfo.getManagerId()); |
||||
|
managers.setRoot("3"); |
||||
|
managers.setCreated_at(LocalDateTime.now()); |
||||
|
managersRows = managersMapper.insertManagers(managers); |
||||
|
if (managersRows <= 0) { |
||||
|
throw new RuntimeException("更新负责人信息失败"); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 负责人信息更新成功"); |
||||
|
} else { |
||||
|
System.out.println("ℹ️ 无需更新负责人信息 - " + |
||||
|
(!isNonPublicSeaCustomer ? "客户不是非公海池客户" : "") + |
||||
|
(!hasFrontendManagerInfo ? "前端未提交负责人信息" : "")); |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新wechat数据源的客户信息(用户和产品信息) |
||||
|
*/ |
||||
|
public boolean updateWechatCustomer(UnifiedCustomerDTO dto) { |
||||
|
// 修复:确保类型转换正确
|
||||
|
String type = dto.getType(); |
||||
|
if ("BOTH".equals(type)) { |
||||
|
type = "both"; |
||||
|
dto.setType(type); |
||||
|
} else if ("客户端".equals(type)) { |
||||
|
type = "buyer"; |
||||
|
dto.setType(type); |
||||
|
} else if ("供应端".equals(type)) { |
||||
|
type = "seller"; |
||||
|
dto.setType(type); |
||||
|
} |
||||
|
|
||||
|
// 销售员权限:校验客户类型,只允许buyer和both
|
||||
|
if (!"buyer".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
throw new IllegalArgumentException("销售权限只能更新为供应端类型客户和BOTH类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 1. 根据手机号查询wechat用户ID(关联用户与产品)
|
||||
|
UserProductCartDTO user = usersMapper.selectByPhone(dto.getPhoneNumber()); |
||||
|
if (user == null) { |
||||
|
// 若该用户在wechat数据源中不存在,无需更新
|
||||
|
return true; |
||||
|
} |
||||
|
// 2. 更新用户基本信息
|
||||
|
UserProductCartDTO updateUser = new UserProductCartDTO(); |
||||
|
updateUser.setUserId(user.getUserId()); |
||||
|
updateUser.setPhoneNumber(dto.getPhoneNumber()); |
||||
|
updateUser.setNickName(dto.getNickName()); |
||||
|
updateUser.setType(dto.getType()); |
||||
|
updateUser.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int rows = usersMapper.updateByPhone(updateUser); |
||||
|
System.out.println("更新用户基本信息影响行数: " + rows); |
||||
|
|
||||
|
// 3. 如果有产品信息需要更新
|
||||
|
if (("buyer".equals(dto.getType()) || "both".equals(dto.getType())) && |
||||
|
dto.getProductName() != null && !dto.getProductName().trim().isEmpty()) { |
||||
|
|
||||
|
System.out.println("更新产品信息"); |
||||
|
int productRows = usersMapper.updateProductBySellerId( |
||||
|
user.getUserId(), |
||||
|
dto.getProductName(), |
||||
|
dto.getVariety(), |
||||
|
dto.getSpecification(), |
||||
|
dto.getQuantity(), |
||||
|
dto.getGrossWeight(), |
||||
|
dto.getYolk() |
||||
|
); |
||||
|
System.out.println("更新产品信息影响行数: " + productRows); |
||||
|
} |
||||
|
|
||||
|
return rows > 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.entity.Contacts; |
||||
|
import com.example.web.entity.Users; |
||||
|
import com.example.web.mapper.ContactsMapper; |
||||
|
import com.example.web.mapper.SupplyContactsMapper; |
||||
|
import com.example.web.mapper.SupplyUsersMapper; |
||||
|
import com.example.web.mapper.UsersMapper; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
public class FollowUpService { |
||||
|
|
||||
|
private final ContactsMapper contactsMapper; |
||||
|
private final UsersMapper usersMapper; |
||||
|
private final SupplyContactsMapper supplyContactsMapper; |
||||
|
private final SupplyUsersMapper supplyUsersMapper; |
||||
|
|
||||
|
/** |
||||
|
* 根据电话号码查询跟进信息 |
||||
|
* @param phoneNumber 电话号码 |
||||
|
* @return 跟进信息 |
||||
|
*/ |
||||
|
public String getFollowUpByPhone(String phoneNumber) { |
||||
|
try { |
||||
|
// 先尝试在contacts表中查询
|
||||
|
String followup = contactsMapper.getFollowUpByPhone(phoneNumber); |
||||
|
if (followup != null) { |
||||
|
return followup; |
||||
|
} |
||||
|
// 如果contacts表中没有,尝试在users表中查询
|
||||
|
return supplyUsersMapper.getFollowUpByPhone(phoneNumber); |
||||
|
} catch (Exception e) { |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存跟进信息 |
||||
|
* @param phoneNumber 电话号码 |
||||
|
* @param followup 跟进信息 |
||||
|
* @return 是否成功 |
||||
|
*/ |
||||
|
public boolean saveFollowUp(String phoneNumber, String followup) { |
||||
|
try { |
||||
|
// 先尝试在contacts表中保存
|
||||
|
if (contactsMapper.updateFollowUpByPhone(phoneNumber, followup) > 0) { |
||||
|
return true; |
||||
|
} |
||||
|
// 如果contacts表中没有,尝试在users表中保存
|
||||
|
return supplyUsersMapper.updateFollowUpByPhone(phoneNumber, followup) > 0; |
||||
|
} catch (Exception e) { |
||||
|
throw e; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,259 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.entity.Login; |
||||
|
import com.example.web.entity.Rootdb; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.entity.Managers; |
||||
|
import com.example.web.mapper.LoginMapper; |
||||
|
import com.example.web.mapper.RootdbMapper; |
||||
|
import com.example.web.mapper.UsersManagementsMapper; |
||||
|
import com.example.web.mapper.SupplyUsersManagementsMapper; |
||||
|
import com.example.web.mapper.ManagersMapper; |
||||
|
import com.example.web.mapper.SupplyManagersMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Service |
||||
|
public class LoginService { |
||||
|
|
||||
|
@Autowired |
||||
|
private LoginMapper loginMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private RootdbMapper rootdbMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private UsersManagementsMapper usersManagementsMapper; // 销售端 usermanagements
|
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyUsersManagementsMapper supplyUsersManagementsMapper; // 采购端 usermanagements
|
||||
|
|
||||
|
@Autowired |
||||
|
private ManagersMapper managersMapper; // 销售端 managers
|
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyManagersMapper supplyManagersMapper; // 采购端 managers
|
||||
|
|
||||
|
public Map<String, Object> authenticate(String projectName, String userName, String password) { |
||||
|
Map<String, Object> result = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
System.out.println("=== 开始认证过程 ==="); |
||||
|
System.out.println("工位名: " + projectName + ", 用户名: " + userName); |
||||
|
|
||||
|
// 1. 验证登录信息
|
||||
|
Login loginInfo = loginMapper.findByProjectNameAndUserName(projectName, userName); |
||||
|
System.out.println("登录信息查询结果: " + (loginInfo != null ? "成功" : "失败")); |
||||
|
|
||||
|
if (loginInfo == null) { |
||||
|
result.put("success", false); |
||||
|
result.put("message", "用户名或工位名不存在"); |
||||
|
result.put("errorType", "user"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 2. 验证密码
|
||||
|
boolean passwordCorrect = loginInfo.getPassword().equals(password); |
||||
|
System.out.println("密码验证: " + (passwordCorrect ? "正确" : "错误")); |
||||
|
|
||||
|
if (!passwordCorrect) { |
||||
|
result.put("success", false); |
||||
|
result.put("message", "密码错误"); |
||||
|
result.put("errorType", "password"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 3. 获取权限信息
|
||||
|
Rootdb rootInfo = rootdbMapper.findByProjectName(projectName); |
||||
|
System.out.println("权限信息查询结果: " + (rootInfo != null ? "成功" : "失败")); |
||||
|
System.out.println("权限等级: " + (rootInfo != null ? rootInfo.getRoot() : "无")); |
||||
|
|
||||
|
if (rootInfo == null) { |
||||
|
result.put("success", false); |
||||
|
result.put("message", "未找到该职位的权限信息"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 4. 🔥 关键修改:使用 loginId 来查询负责人信息
|
||||
|
String loginId = String.valueOf(loginInfo.getId()); // 获取 login 表的 id
|
||||
|
System.out.println("登录ID (loginId): " + loginId); |
||||
|
|
||||
|
boolean isSupplySide = isSupplySideProject(projectName); |
||||
|
System.out.println("🔄 系统识别: " + (isSupplySide ? "采购端" : "销售端")); |
||||
|
|
||||
|
UsersManagements userManagement = null; |
||||
|
boolean fromManagersTable = false; |
||||
|
|
||||
|
// 4.1 首先尝试从 managers 表查询(使用 loginId 作为 managerId)
|
||||
|
List<Managers> managersList; |
||||
|
if (isSupplySide) { |
||||
|
managersList = supplyManagersMapper.selectByUserNameAndManagerId(userName, loginId); |
||||
|
} else { |
||||
|
managersList = managersMapper.selectByUserNameAndManagerId(userName, loginId); |
||||
|
} |
||||
|
|
||||
|
if (managersList != null && !managersList.isEmpty()) { |
||||
|
// 从 managers 表找到数据
|
||||
|
Managers manager = managersList.get(0); |
||||
|
if (managersList.size() > 1) { |
||||
|
System.out.println("找到多个 managers 记录,数量: " + managersList.size()); |
||||
|
// 选择最新的记录
|
||||
|
manager = managersList.stream() |
||||
|
.sorted((m1, m2) -> { |
||||
|
if (m1.getUpdated_at() != null && m2.getUpdated_at() != null) { |
||||
|
return m2.getUpdated_at().compareTo(m1.getUpdated_at()); |
||||
|
} |
||||
|
return 0; |
||||
|
}) |
||||
|
.findFirst() |
||||
|
.orElse(managersList.get(0)); |
||||
|
} |
||||
|
|
||||
|
// 将 Managers 转换为 UsersManagements
|
||||
|
userManagement = convertManagerToUserManagement(manager); |
||||
|
fromManagersTable = true; |
||||
|
System.out.println("✅ 从 managers 表获取用户管理信息"); |
||||
|
} else { |
||||
|
// 4.2 如果 managers 表没有数据,再从 usermanagements 表查询(使用 loginId 作为 managerId)
|
||||
|
List<UsersManagements> userManagementsList; |
||||
|
if (isSupplySide) { |
||||
|
userManagementsList = supplyUsersManagementsMapper.findByUserNameAndManagerId(userName, loginId); |
||||
|
} else { |
||||
|
userManagementsList = usersManagementsMapper.findByUserNameAndManagerId(userName, loginId); |
||||
|
} |
||||
|
|
||||
|
if (userManagementsList != null && !userManagementsList.isEmpty()) { |
||||
|
if (userManagementsList.size() > 1) { |
||||
|
System.out.println("找到多个 usermanagements 记录,数量: " + userManagementsList.size()); |
||||
|
userManagement = userManagementsList.stream() |
||||
|
.sorted((u1, u2) -> { |
||||
|
if (u1.getUpdated_at() != null && u2.getUpdated_at() != null) { |
||||
|
return u2.getUpdated_at().compareTo(u1.getUpdated_at()); |
||||
|
} |
||||
|
return 0; |
||||
|
}) |
||||
|
.findFirst() |
||||
|
.orElse(userManagementsList.get(0)); |
||||
|
} else { |
||||
|
userManagement = userManagementsList.get(0); |
||||
|
} |
||||
|
System.out.println("✅ 从 usermanagements 表获取用户管理信息"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (userManagement == null) { |
||||
|
result.put("success", false); |
||||
|
result.put("message", "未找到对应的负责人信息,请检查用户名和密码是否正确!"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 打印用户管理信息详情
|
||||
|
System.out.println("用户管理信息详情:"); |
||||
|
System.out.println(" - 数据来源: " + (fromManagersTable ? "managers表" : "usermanagements表")); |
||||
|
System.out.println(" - managerId: " + userManagement.getManagerId()); |
||||
|
System.out.println(" - managercompany: " + userManagement.getManagercompany()); |
||||
|
System.out.println(" - managerdepartment: " + userManagement.getManagerdepartment()); |
||||
|
System.out.println(" - organization: " + userManagement.getOrganization()); |
||||
|
System.out.println(" - role: " + userManagement.getRole()); |
||||
|
System.out.println(" - userName: " + userManagement.getUserName()); |
||||
|
System.out.println(" - assistant: " + userManagement.getAssistant()); |
||||
|
|
||||
|
// 5. 生成token(包含端信息)
|
||||
|
String token = generateToken(userName, projectName, isSupplySide); |
||||
|
System.out.println("生成的token: " + token); |
||||
|
|
||||
|
// 6. 构建返回结果
|
||||
|
result.put("success", true); |
||||
|
result.put("token", token); |
||||
|
result.put("root", rootInfo.getRoot()); |
||||
|
result.put("user", buildUserResponse(userManagement)); |
||||
|
result.put("isSupplySide", isSupplySide); |
||||
|
result.put("fromManagersTable", fromManagersTable); // 新增:标识数据来源
|
||||
|
result.put("loginId", loginId); // 返回 loginId
|
||||
|
|
||||
|
// 返回完整的认证信息供前端使用
|
||||
|
Map<String, Object> authInfo = new HashMap<>(); |
||||
|
authInfo.put("managerId", userManagement.getManagerId() != null ? userManagement.getManagerId() : ""); |
||||
|
authInfo.put("company", userManagement.getManagercompany() != null ? userManagement.getManagercompany() : ""); |
||||
|
authInfo.put("department", userManagement.getManagerdepartment() != null ? userManagement.getManagerdepartment() : ""); |
||||
|
authInfo.put("organization", userManagement.getOrganization() != null ? userManagement.getOrganization() : ""); |
||||
|
authInfo.put("role", userManagement.getRole() != null ? userManagement.getRole() : ""); |
||||
|
authInfo.put("userName", userManagement.getUserName() != null ? userManagement.getUserName() : ""); |
||||
|
authInfo.put("assistant", userManagement.getAssistant() != null ? userManagement.getAssistant() : ""); |
||||
|
|
||||
|
result.put("authInfo", authInfo); |
||||
|
System.out.println("✅ 返回完整认证信息: " + authInfo); |
||||
|
|
||||
|
System.out.println("最终返回结果: " + result); |
||||
|
System.out.println("=== 认证过程结束 ==="); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("认证过程中发生异常: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
result.put("success", false); |
||||
|
result.put("message", "登录过程中发生错误: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将 Managers 实体转换为 UsersManagements 实体 |
||||
|
*/ |
||||
|
private UsersManagements convertManagerToUserManagement(Managers manager) { |
||||
|
UsersManagements userManagement = new UsersManagements(); |
||||
|
userManagement.setId(manager.getManager_id()); |
||||
|
userManagement.setUserId(manager.getId()); // 使用企业id作为userId
|
||||
|
userManagement.setManagerId(manager.getManagerId()); |
||||
|
userManagement.setManagercompany(manager.getManagercompany()); |
||||
|
userManagement.setManagerdepartment(manager.getManagerdepartment()); |
||||
|
userManagement.setOrganization(manager.getOrganization()); |
||||
|
userManagement.setRole(manager.getRole()); |
||||
|
userManagement.setRoot(manager.getRoot()); |
||||
|
userManagement.setCreated_at(manager.getCreated_at()); |
||||
|
userManagement.setUpdated_at(manager.getUpdated_at()); |
||||
|
userManagement.setUserName(manager.getUserName()); |
||||
|
userManagement.setAssistant(manager.getAssistant()); |
||||
|
return userManagement; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否为采购端工位 |
||||
|
*/ |
||||
|
private boolean isSupplySideProject(String projectName) { |
||||
|
if (projectName == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
String lowerProjectName = projectName.toLowerCase(); |
||||
|
return lowerProjectName.contains("supply") || |
||||
|
lowerProjectName.contains("purchase") || |
||||
|
lowerProjectName.contains("procurement") || |
||||
|
lowerProjectName.contains("采购"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成token,包含端信息 |
||||
|
*/ |
||||
|
private String generateToken(String userName, String projectName, boolean isSupplySide) { |
||||
|
String side = isSupplySide ? "supply" : "sales"; |
||||
|
return System.currentTimeMillis() + "-" + userName + "-" + projectName + "-" + side; |
||||
|
} |
||||
|
|
||||
|
private Map<String, Object> buildUserResponse(UsersManagements userManagement) { |
||||
|
Map<String, Object> user = new HashMap<>(); |
||||
|
user.put("managerId", userManagement.getManagerId() != null ? userManagement.getManagerId() : ""); |
||||
|
user.put("managercompany", userManagement.getManagercompany() != null ? userManagement.getManagercompany() : ""); |
||||
|
user.put("managerdepartment", userManagement.getManagerdepartment() != null ? userManagement.getManagerdepartment() : ""); |
||||
|
user.put("organization", userManagement.getOrganization() != null ? userManagement.getOrganization() : ""); |
||||
|
user.put("role", userManagement.getRole() != null ? userManagement.getRole() : ""); |
||||
|
user.put("userName", userManagement.getUserName() != null ? userManagement.getUserName() : ""); |
||||
|
user.put("assistant", userManagement.getAssistant() != null ? userManagement.getAssistant() : ""); |
||||
|
System.out.println("构建的用户响应: " + user); |
||||
|
return user; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,805 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.mapper.UsersManagementsMapper; |
||||
|
import com.example.web.mapper.UsersMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.util.*; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Service |
||||
|
public class PoolCustomerService { |
||||
|
|
||||
|
@Autowired |
||||
|
private UsersMapper usersMapper; |
||||
|
@Autowired |
||||
|
private UsersManagementsMapper usersManagementsMapper; |
||||
|
|
||||
|
/** |
||||
|
* 公共方法:判断是否为公海池客户(供Controller调用) |
||||
|
*/ |
||||
|
public boolean isPublicSeaCustomerPublic(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
return isPublicSeaCustomer(userInfo, authInfo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号查询微信用户信息(销售端权限:只处理buyer和both类型)- 支持一对多 |
||||
|
*/ |
||||
|
public UserProductCartDTO getWechatCustomerByPhone(String phoneNumber) { |
||||
|
if (!StringUtils.hasText(phoneNumber)) { |
||||
|
throw new IllegalArgumentException("手机号不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 1. 根据手机号查询微信用户基本信息
|
||||
|
UserProductCartDTO userInfo = usersMapper.selectByPhone(phoneNumber); |
||||
|
if (userInfo == null) { |
||||
|
throw new RuntimeException("未找到手机号对应的微信用户:" + phoneNumber); |
||||
|
} |
||||
|
|
||||
|
System.out.println("获取到用户基础信息,用户ID: " + userInfo.getUserId() + |
||||
|
", 类型: " + userInfo.getType() + |
||||
|
", 公司: " + userInfo.getCompany() + |
||||
|
", 需求: " + userInfo.getDemand() + |
||||
|
", 规格: " + userInfo.getSpec()); |
||||
|
|
||||
|
// 2. 获取所有联系人信息(一对多)
|
||||
|
try { |
||||
|
List<UsersMapper.ContactInfo> contacts = usersMapper.getUserAllContacts(userInfo.getUserId()); |
||||
|
// 转换为UserProductCartDTO.UsersContacts格式以保持兼容
|
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
// 设置contactId
|
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setUsersContacts(userContacts); |
||||
|
} else { |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
System.out.println("获取用户所有联系人信息,数量: " + (userInfo.getUsersContacts() != null ? userInfo.getUsersContacts().size() : 0)); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 3. 获取所有购物车项信息(一对多)
|
||||
|
if ("buyer".equals(userInfo.getType()) || "both".equals(userInfo.getType())) { |
||||
|
try { |
||||
|
List<UsersMapper.CartItem> cartItems = usersMapper.getUserAllCartItems(userInfo.getUserId()); |
||||
|
// 转换为UserProductCartDTO.CartItem格式以保持兼容
|
||||
|
if (cartItems != null && !cartItems.isEmpty()) { |
||||
|
List<UserProductCartDTO.CartItem> userCartItems = cartItems.stream() |
||||
|
.map(item -> { |
||||
|
UserProductCartDTO.CartItem cartItem = new UserProductCartDTO.CartItem(); |
||||
|
cartItem.setCartItemId(item.getCartItemId()); |
||||
|
cartItem.setProductId(item.getProductId()); |
||||
|
cartItem.setProductName(item.getProductName()); |
||||
|
cartItem.setSpecification(item.getSpecification()); |
||||
|
cartItem.setQuantity(item.getQuantity()); |
||||
|
cartItem.setGrossWeight(item.getGrossWeight()); |
||||
|
cartItem.setYolk(item.getYolk()); |
||||
|
return cartItem; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setCartItems(userCartItems); |
||||
|
} else { |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
} |
||||
|
System.out.println("获取用户所有购物车项信息,数量: " + (userInfo.getCartItems() != null ? userInfo.getCartItems().size() : 0)); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("获取购物车信息失败: " + e.getMessage()); |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
} |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据用户ID获取用户信息和相关产品/购物车数据 |
||||
|
*/ |
||||
|
public UserProductCartDTO getCustomerInfo(String userId) { |
||||
|
if (!StringUtils.hasText(userId)) { |
||||
|
throw new IllegalArgumentException("用户ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 1. 获取用户基本信息
|
||||
|
UserProductCartDTO userInfo = usersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo == null) { |
||||
|
throw new RuntimeException("用户不存在: " + userId); |
||||
|
} |
||||
|
|
||||
|
// 2. 根据用户类型查询不同的数据
|
||||
|
if ("seller".equals(userInfo.getType())) { |
||||
|
// 卖家:查询产品信息
|
||||
|
List<UserProductCartDTO.ProductInfo> products = usersMapper.getSellerProducts(userId); |
||||
|
userInfo.setProducts(products != null ? products : Collections.emptyList()); |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
} else { |
||||
|
// 买家:查询购物车信息
|
||||
|
List<UserProductCartDTO.CartItem> cartItems = usersMapper.getBuyerCartItems(userId); |
||||
|
userInfo.setCartItems(cartItems != null ? cartItems : Collections.emptyList()); |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 3. 获取联系人信息 - 安全处理
|
||||
|
try { |
||||
|
List<UserProductCartDTO.UsersContacts> contacts = usersMapper.getUserContacts(userId); |
||||
|
userInfo.setUsersContacts(contacts != null ? contacts : Collections.emptyList()); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有客户信息 - 使用数据库层面权限过滤(销售端版本,支持分页) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO> getAllCustomers(ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🚀 开始获取所有微信用户数据(数据库权限过滤,销售端)..."); |
||||
|
|
||||
|
// 移除固定的分页限制,获取所有数据
|
||||
|
// 注意:这里可以根据实际需要调整,或者改为支持传入分页参数的方法
|
||||
|
int limit = Integer.MAX_VALUE; // 获取所有数据
|
||||
|
int offset = 0; // 从第一条开始
|
||||
|
|
||||
|
// 1. 获取授权客户总数
|
||||
|
System.out.println("📊 查询授权客户总数..."); |
||||
|
int totalCount = usersMapper.getAuthorizedCustomersCount(authInfo); |
||||
|
System.out.println("✅ 授权客户总数: " + totalCount); |
||||
|
|
||||
|
// 2. 使用数据库层面权限过滤并分页
|
||||
|
System.out.println("📋 查询授权客户基础信息(分页查询)..."); |
||||
|
List<UserProductCartDTO> authorizedUsers = usersMapper.getAuthorizedCustomers(authInfo, limit, offset); |
||||
|
|
||||
|
System.out.println("✅ 授权客户数据查询完成"); |
||||
|
System.out.println("📊 当前页获取到授权客户数据条数: " + (authorizedUsers != null ? authorizedUsers.size() : "null")); |
||||
|
|
||||
|
List<UserProductCartDTO> result = new ArrayList<>(); |
||||
|
|
||||
|
if (authorizedUsers != null && !authorizedUsers.isEmpty()) { |
||||
|
// 🔥 修改:收集所有用户ID用于批量查询
|
||||
|
List<String> userIds = authorizedUsers.stream() |
||||
|
.map(UserProductCartDTO::getUserId) |
||||
|
.filter(Objects::nonNull) |
||||
|
.filter(userId -> !userId.trim().isEmpty()) |
||||
|
.distinct() |
||||
|
.collect(Collectors.toList()); |
||||
|
|
||||
|
System.out.println("🔍 需要批量查询的用户数量: " + userIds.size()); |
||||
|
|
||||
|
// 🔥 修改:批量查询所有相关数据
|
||||
|
Map<String, UsersManagements> managerMap = batchQueryManagers(userIds); |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = batchQueryContacts(userIds); |
||||
|
Map<String, List<UsersMapper.CartItem>> cartItemsMap = batchQueryCartItems(userIds); |
||||
|
|
||||
|
// 2. 为每个授权用户构建完整信息
|
||||
|
System.out.println("🔄 开始处理 " + authorizedUsers.size() + " 条授权用户数据..."); |
||||
|
|
||||
|
for (int i = 0; i < authorizedUsers.size(); i++) { |
||||
|
UserProductCartDTO user = authorizedUsers.get(i); |
||||
|
try { |
||||
|
// 🔥 修改:使用批量查询的数据构建完整用户信息
|
||||
|
UserProductCartDTO fullUserInfo = buildUserInfoFromBatchData(user, managerMap, contactsMap, cartItemsMap); |
||||
|
if (fullUserInfo != null) { |
||||
|
result.add(fullUserInfo); |
||||
|
// 打印前几个客户的详细信息
|
||||
|
if (i < 3) { |
||||
|
System.out.println("📝 授权客户样例 " + (i + 1) + ": " + |
||||
|
"ID=" + fullUserInfo.getUserId() + |
||||
|
", 手机=" + fullUserInfo.getPhoneNumber() + |
||||
|
", 公司=" + fullUserInfo.getCompany() + |
||||
|
", 联系人数量=" + (fullUserInfo.getUsersContacts() != null ? fullUserInfo.getUsersContacts().size() : 0) + |
||||
|
", 购物车数量=" + (fullUserInfo.getCartItems() != null ? fullUserInfo.getCartItems().size() : 0)); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 构建用户 " + user.getUserId() + " 的详细信息时出错: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🎉 数据获取完成(数据库权限过滤,销售端)"); |
||||
|
System.out.println("📊 返回记录数: " + result.size()); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取授权客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否有权限查看客户 |
||||
|
*/ |
||||
|
private boolean hasPermissionToViewCustomer(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
// 使用新的公海池判断逻辑
|
||||
|
if (isPublicSeaCustomer(userInfo, authInfo)) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// 非公海池客户需要检查负责人权限
|
||||
|
return hasUserManagerPermission(userInfo.getUserId(), authInfo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否为公海池客户 - 根据负责人信息中的认证字段是否为空判断 |
||||
|
*/ |
||||
|
private boolean isPublicSeaCustomer(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
|
||||
|
// 检查等级是否为公海池
|
||||
|
boolean isPublicSeaLevel = publicSeaLevels.contains(userInfo.getLevel()); |
||||
|
System.out.println("🔍 PoolCustomerService - 客户等级检查: " + userInfo.getLevel() + " → 是否公海池等级: " + isPublicSeaLevel); |
||||
|
|
||||
|
if (!isPublicSeaLevel) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 根据不同类型的公海池使用不同判断逻辑
|
||||
|
String level = userInfo.getLevel(); |
||||
|
|
||||
|
if ("company-sea-pools".equals(level) || "公海池".equals(level)) { |
||||
|
// 公司公海池:必须没有负责人信息
|
||||
|
boolean result = !hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
System.out.println("🏢 公司公海池检查结果: " + result); |
||||
|
return result; |
||||
|
} else if ("organization-sea-pools".equals(level)) { |
||||
|
// 组织公海池:必须有负责人信息且组织匹配
|
||||
|
boolean hasManager = hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
if (!hasManager) { |
||||
|
System.out.println("🏢 组织公海池:无负责人信息,不允许查看"); |
||||
|
return false; |
||||
|
} |
||||
|
boolean sameOrganization = hasSameOrganization(userInfo.getUserId(), authInfo); |
||||
|
System.out.println("🏢 组织公海池检查结果 - 有负责人: " + hasManager + ", 组织匹配: " + sameOrganization + " → 结果: " + sameOrganization); |
||||
|
return sameOrganization; |
||||
|
} else if ("department-sea-pools".equals(level)) { |
||||
|
// 部门公海池:必须有负责人信息且部门匹配
|
||||
|
boolean hasManager = hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
if (!hasManager) { |
||||
|
System.out.println("🏢 部门公海池:无负责人信息,不允许查看"); |
||||
|
return false; |
||||
|
} |
||||
|
boolean sameDepartment = hasSameDepartment(userInfo.getUserId(), authInfo); |
||||
|
System.out.println("🏢 部门公海池检查结果 - 有负责人: " + hasManager + ", 部门匹配: " + sameDepartment + " → 结果: " + sameDepartment); |
||||
|
return sameDepartment; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否有负责人认证信息 |
||||
|
*/ |
||||
|
private boolean hasManagerAuthInfo(String userId) { |
||||
|
try { |
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 检查认证字段是否为空 - 只要有一个认证字段有值,就有负责人信息
|
||||
|
boolean hasAuthInfo = StringUtils.hasText(userManager.getManagerId()) || |
||||
|
StringUtils.hasText(userManager.getManagercompany()) || |
||||
|
StringUtils.hasText(userManager.getManagerdepartment()) || |
||||
|
StringUtils.hasText(userManager.getOrganization()) || |
||||
|
StringUtils.hasText(userManager.getRole()) || |
||||
|
StringUtils.hasText(userManager.getUserName()) || |
||||
|
StringUtils.hasText(userManager.getAssistant()); |
||||
|
|
||||
|
System.out.println("📋 负责人认证信息检查结果: " + (hasAuthInfo ? "有认证信息" : "无认证信息")); |
||||
|
return hasAuthInfo; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查负责人认证信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否同一组织 |
||||
|
*/ |
||||
|
private boolean hasSameOrganization(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
boolean sameOrganization = StringUtils.hasText(userManager.getOrganization()) && |
||||
|
userManager.getOrganization().equals(authInfo.getOrganization()); |
||||
|
|
||||
|
System.out.println("🏢 组织匹配检查: " + userManager.getOrganization() + " vs " + authInfo.getOrganization() + " → " + sameOrganization); |
||||
|
return sameOrganization; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查组织信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否同一部门 |
||||
|
*/ |
||||
|
private boolean hasSameDepartment(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
boolean sameDepartment = StringUtils.hasText(userManager.getManagerdepartment()) && |
||||
|
userManager.getManagerdepartment().equals(authInfo.getManagerdepartment()); |
||||
|
|
||||
|
System.out.println("🏢 部门匹配检查: " + userManager.getManagerdepartment() + " vs " + authInfo.getManagerdepartment() + " → " + sameDepartment); |
||||
|
return sameDepartment; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查部门信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查用户负责人权限 - 优化版本,数据库层面直接匹配 |
||||
|
*/ |
||||
|
private boolean hasUserManagerPermission(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
System.out.println("🔐 检查用户负责人权限,用户ID: " + userId); |
||||
|
|
||||
|
// 🔥 优化:直接在数据库层面查询匹配的负责人记录,避免内存比较
|
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserIdAndAuthInfo(userId, authInfo); |
||||
|
|
||||
|
// 🔥 优化:如果没有找到匹配的负责人记录,检查是否为公海池客户
|
||||
|
if (userManager == null) { |
||||
|
System.out.println("🔍 未找到匹配的负责人记录,检查客户等级..."); |
||||
|
|
||||
|
// 获取用户信息检查等级
|
||||
|
UserProductCartDTO userInfo = usersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo != null) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
boolean isPublicSea = publicSeaLevels.contains(userInfo.getLevel()); |
||||
|
|
||||
|
if (isPublicSea) { |
||||
|
System.out.println("✅ 公海池客户,允许查看"); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("❌ 非公海池客户且无匹配负责人,拒绝访问"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 🔥 优化:数据库已经完成匹配,直接返回true
|
||||
|
System.out.println("✅ 找到匹配的负责人记录,允许查看"); |
||||
|
System.out.println("📝 负责人信息: " + |
||||
|
"公司=" + userManager.getManagercompany() + |
||||
|
", 部门=" + userManager.getManagerdepartment() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 负责人=" + userManager.getUserName()); |
||||
|
|
||||
|
return true; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查用户负责人权限失败: " + e.getMessage()); |
||||
|
// 发生异常时,出于安全考虑返回false
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查负责人信息是否匹配(UsersManagements) |
||||
|
*/ |
||||
|
private boolean isManagerMatch(UsersManagements userManager, ManagerAuthInfo authInfo) { |
||||
|
boolean match = |
||||
|
(authInfo.getManagercompany() == null || authInfo.getManagercompany().equals(userManager.getManagercompany())) && |
||||
|
(authInfo.getManagerdepartment() == null || authInfo.getManagerdepartment().equals(userManager.getManagerdepartment())) && |
||||
|
(authInfo.getOrganization() == null || authInfo.getOrganization().equals(userManager.getOrganization())) && |
||||
|
(authInfo.getRole() == null || authInfo.getRole().equals(userManager.getRole())) && |
||||
|
(authInfo.getUserName() == null || authInfo.getUserName().equals(userManager.getUserName())); |
||||
|
|
||||
|
System.out.println("🔐 用户负责人权限检查: " + (match ? "✅ 匹配" : "❌ 不匹配")); |
||||
|
return match; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取公海池客户完整信息 - 支持一对多(单个查询版本) |
||||
|
*/ |
||||
|
public UserProductCartDTO getPublicSeaCustomerInfo(String userId) { |
||||
|
if (!StringUtils.hasText(userId)) { |
||||
|
System.out.println("⚠️ 用户ID为空"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 1. 获取用户基本信息
|
||||
|
UserProductCartDTO userInfo = usersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo == null) { |
||||
|
System.out.println("⚠️ 用户不存在: " + userId); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 销售端权限校验
|
||||
|
if (!"buyer".equals(userInfo.getType()) && !"both".equals(userInfo.getType())) { |
||||
|
System.out.println("🚫 过滤掉非客户端客户: " + userId + " (类型: " + userInfo.getType() + ")"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 🔥 恢复:原有的单个查询负责人信息逻辑
|
||||
|
try { |
||||
|
UsersManagements userManager = usersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 获取到负责人信息: " + |
||||
|
"负责人=" + userManager.getUserName() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 部门=" + userManager.getManagerdepartment()); |
||||
|
} else { |
||||
|
System.out.println("⚠️ 未找到负责人信息"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 2. 获取联系人信息 - 一对多
|
||||
|
try { |
||||
|
List<UsersMapper.ContactInfo> contacts = usersMapper.getUserAllContacts(userId); |
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setUsersContacts(userContacts); |
||||
|
} else { |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 3. 销售端:获取购物车信息(公海需求)- 一对多
|
||||
|
try { |
||||
|
List<UsersMapper.CartItem> cartItems = usersMapper.getUserAllCartItems(userId); |
||||
|
System.out.println("🔍 查询到的购物车数据条数: " + (cartItems != null ? cartItems.size() : 0)); |
||||
|
|
||||
|
if (cartItems != null && !cartItems.isEmpty()) { |
||||
|
List<UserProductCartDTO.CartItem> userCartItems = cartItems.stream() |
||||
|
.map(item -> { |
||||
|
UserProductCartDTO.CartItem cartItem = new UserProductCartDTO.CartItem(); |
||||
|
cartItem.setCartItemId(item.getCartItemId()); |
||||
|
cartItem.setProductId(item.getProductId()); |
||||
|
cartItem.setProductName(item.getProductName()); |
||||
|
cartItem.setSpecification(item.getSpecification()); |
||||
|
cartItem.setQuantity(item.getQuantity()); |
||||
|
cartItem.setGrossWeight(item.getGrossWeight()); |
||||
|
cartItem.setYolk(item.getYolk()); |
||||
|
|
||||
|
// 调试日志
|
||||
|
System.out.println("📦 转换购物车项: " + |
||||
|
"ID=" + cartItem.getCartItemId() + |
||||
|
", 产品=" + cartItem.getProductName() + |
||||
|
", 规格=" + cartItem.getSpecification()); |
||||
|
|
||||
|
return cartItem; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setCartItems(userCartItems); |
||||
|
System.out.println("✅ 成功设置购物车数据,数量: " + userCartItems.size()); |
||||
|
} else { |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
System.out.println("⚠️ 购物车数据为空"); |
||||
|
} |
||||
|
userInfo.setProducts(Collections.emptyList()); // 销售端不使用产品信息
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取购物车信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 最终调试信息
|
||||
|
System.out.println("🎯 最终返回的用户数据: " + |
||||
|
"cartItems数量=" + (userInfo.getCartItems() != null ? userInfo.getCartItems().size() : "null") + |
||||
|
", contacts数量=" + (userInfo.getUsersContacts() != null ? userInfo.getUsersContacts().size() : "null")); |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有客户信息 - 不进行负责人过滤,直接返回所有数据(销售端版本) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO> getAllCustomersWithoutFilter() { |
||||
|
try { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🚀 开始获取所有微信用户数据(无过滤,销售端)..."); |
||||
|
|
||||
|
// 1. 获取所有用户的基本信息
|
||||
|
System.out.println("📋 查询用户基础信息..."); |
||||
|
List<UserProductCartDTO> allUsers = usersMapper.getAllUserBasicInfo(); |
||||
|
|
||||
|
System.out.println("✅ 基础用户数据查询完成"); |
||||
|
System.out.println("📊 获取到基础用户数据条数: " + (allUsers != null ? allUsers.size() : "null")); |
||||
|
|
||||
|
List<UserProductCartDTO> result = new ArrayList<>(); |
||||
|
|
||||
|
if (allUsers != null && !allUsers.isEmpty()) { |
||||
|
// 🔥 修改:收集所有用户ID用于批量查询
|
||||
|
List<String> userIds = allUsers.stream() |
||||
|
.map(UserProductCartDTO::getUserId) |
||||
|
.filter(Objects::nonNull) |
||||
|
.filter(userId -> !userId.trim().isEmpty()) |
||||
|
.distinct() |
||||
|
.collect(Collectors.toList()); |
||||
|
|
||||
|
System.out.println("🔍 需要批量查询的用户数量: " + userIds.size()); |
||||
|
|
||||
|
// 🔥 修改:批量查询所有相关数据
|
||||
|
Map<String, UsersManagements> managerMap = batchQueryManagers(userIds); |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = batchQueryContacts(userIds); |
||||
|
Map<String, List<UsersMapper.CartItem>> cartItemsMap = batchQueryCartItems(userIds); |
||||
|
|
||||
|
// 2. 为每个用户构建完整信息
|
||||
|
System.out.println("🔄 开始处理 " + allUsers.size() + " 条用户数据..."); |
||||
|
|
||||
|
for (int i = 0; i < allUsers.size(); i++) { |
||||
|
UserProductCartDTO user = allUsers.get(i); |
||||
|
try { |
||||
|
// 销售端权限:只处理buyer和both类型
|
||||
|
if (!"buyer".equals(user.getType()) && !"both".equals(user.getType())) { |
||||
|
System.out.println("🚫 过滤掉非供应端客户: " + user.getUserId() + " (类型: " + user.getType() + ")"); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 🔥 修改:使用批量查询的数据构建完整用户信息
|
||||
|
UserProductCartDTO fullUserInfo = buildUserInfoFromBatchData(user, managerMap, contactsMap, cartItemsMap); |
||||
|
if (fullUserInfo != null) { |
||||
|
result.add(fullUserInfo); |
||||
|
// 打印前几个客户的详细信息
|
||||
|
if (i < 3) { |
||||
|
System.out.println("📝 客户样例 " + (i + 1) + ": " + |
||||
|
"ID=" + fullUserInfo.getUserId() + |
||||
|
", 手机=" + fullUserInfo.getPhoneNumber() + |
||||
|
", 公司=" + fullUserInfo.getCompany() + |
||||
|
", 联系人数量=" + (fullUserInfo.getUsersContacts() != null ? fullUserInfo.getUsersContacts().size() : 0) + |
||||
|
", 购物车数量=" + (fullUserInfo.getCartItems() != null ? fullUserInfo.getCartItems().size() : 0)); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 构建用户 " + user.getUserId() + " 的详细信息时出错: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🎉 数据获取完成(无过滤,销售端)"); |
||||
|
System.out.println("📊 返回记录数: " + result.size()); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取所有客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 1.批量查询负责人信息 |
||||
|
*/ |
||||
|
private Map<String, UsersManagements> batchQueryManagers(List<String> userIds) { |
||||
|
Map<String, UsersManagements> managerMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
List<UsersManagements> allManagers = usersManagementsMapper.findByUserIds(userIds); |
||||
|
for (UsersManagements manager : allManagers) { |
||||
|
if (manager.getUserId() != null) { |
||||
|
managerMap.put(manager.getUserId(), manager); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 批量查询负责人信息完成,共获取 " + allManagers.size() + " 条记录"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 批量查询负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return managerMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 2.批量查询联系人信息 |
||||
|
*/ |
||||
|
private Map<String, List<UsersMapper.ContactInfo>> batchQueryContacts(List<String> userIds) { |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
List<UsersMapper.ContactInfo> allContacts = usersMapper.getUserContactsByUserIds(userIds); |
||||
|
// 按用户ID分组
|
||||
|
for (UsersMapper.ContactInfo contact : allContacts) { |
||||
|
String userId = contact.getUserId(); |
||||
|
if (userId != null) { |
||||
|
contactsMap.computeIfAbsent(userId, k -> new ArrayList<>()).add(contact); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 批量查询联系人信息完成,共获取 " + allContacts.size() + " 条记录,涉及 " + contactsMap.size() + " 个用户"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 批量查询联系人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return contactsMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 3.批量查询购物车信息 |
||||
|
*/ |
||||
|
private Map<String, List<UsersMapper.CartItem>> batchQueryCartItems(List<String> userIds) { |
||||
|
Map<String, List<UsersMapper.CartItem>> cartItemsMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
List<UsersMapper.CartItem> allCartItems = usersMapper.getCartItemsByUserIds(userIds); |
||||
|
// 按用户ID分组
|
||||
|
for (UsersMapper.CartItem cartItem : allCartItems) { |
||||
|
String userId = cartItem.getUserId(); |
||||
|
if (userId != null) { |
||||
|
cartItemsMap.computeIfAbsent(userId, k -> new ArrayList<>()).add(cartItem); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 批量查询购物车信息完成,共获取 " + allCartItems.size() + " 条记录,涉及 " + cartItemsMap.size() + " 个用户"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 批量查询购物车信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return cartItemsMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 4.从批量查询的数据构建用户完整信息 |
||||
|
*/ |
||||
|
private UserProductCartDTO buildUserInfoFromBatchData(UserProductCartDTO basicUserInfo, |
||||
|
Map<String, UsersManagements> managerMap, |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap, |
||||
|
Map<String, List<UsersMapper.CartItem>> cartItemsMap) { |
||||
|
String userId = basicUserInfo.getUserId(); |
||||
|
|
||||
|
// 销售端权限校验
|
||||
|
if (!"buyer".equals(basicUserInfo.getType()) && !"both".equals(basicUserInfo.getType())) { |
||||
|
System.out.println("🚫 过滤掉非客户端客户: " + userId + " (类型: " + basicUserInfo.getType() + ")"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 🔥 设置负责人信息(记录日志,但不设置到DTO中,因为UserProductCartDTO没有负责人字段)
|
||||
|
try { |
||||
|
UsersManagements userManager = managerMap.get(userId); |
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 从批量Map中获取到负责人信息: " + |
||||
|
"负责人=" + userManager.getUserName() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 部门=" + userManager.getManagerdepartment()); |
||||
|
} else { |
||||
|
System.out.println("⚠️ 未在批量Map中找到负责人信息,用户ID: " + userId); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 从Map获取负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 🔥 设置联系人信息 - 从批量查询的Map中获取
|
||||
|
try { |
||||
|
List<UsersMapper.ContactInfo> contacts = contactsMap.get(userId); |
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
basicUserInfo.setUsersContacts(userContacts); |
||||
|
System.out.println("✅ 成功设置联系人数据,数量: " + userContacts.size() + ",用户ID: " + userId); |
||||
|
} else { |
||||
|
basicUserInfo.setUsersContacts(Collections.emptyList()); |
||||
|
System.out.println("⚠️ 未找到联系人信息,用户ID: " + userId); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 设置联系人信息失败: " + e.getMessage()); |
||||
|
basicUserInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 🔥 设置购物车信息 - 从批量查询的Map中获取
|
||||
|
try { |
||||
|
List<UsersMapper.CartItem> cartItems = cartItemsMap.get(userId); |
||||
|
if (cartItems != null && !cartItems.isEmpty()) { |
||||
|
List<UserProductCartDTO.CartItem> userCartItems = cartItems.stream() |
||||
|
.map(item -> { |
||||
|
UserProductCartDTO.CartItem cartItem = new UserProductCartDTO.CartItem(); |
||||
|
cartItem.setCartItemId(item.getCartItemId()); |
||||
|
cartItem.setProductId(item.getProductId()); |
||||
|
cartItem.setProductName(item.getProductName()); |
||||
|
cartItem.setSpecification(item.getSpecification()); |
||||
|
cartItem.setQuantity(item.getQuantity()); |
||||
|
cartItem.setGrossWeight(item.getGrossWeight()); |
||||
|
cartItem.setYolk(item.getYolk()); |
||||
|
return cartItem; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
basicUserInfo.setCartItems(userCartItems); |
||||
|
System.out.println("✅ 成功设置购物车数据,数量: " + userCartItems.size() + ",用户ID: " + userId); |
||||
|
} else { |
||||
|
basicUserInfo.setCartItems(Collections.emptyList()); |
||||
|
System.out.println("⚠️ 购物车数据为空,用户ID: " + userId); |
||||
|
} |
||||
|
basicUserInfo.setProducts(Collections.emptyList()); // 销售端不使用产品信息
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 设置购物车信息失败: " + e.getMessage()); |
||||
|
basicUserInfo.setCartItems(Collections.emptyList()); |
||||
|
basicUserInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
return basicUserInfo; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 只检查等级是否为公海池等级(不检查负责人信息) |
||||
|
*/ |
||||
|
private boolean isPublicSeaLevel(String level) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
|
||||
|
boolean isPublicSeaLevel = publicSeaLevels.contains(level); |
||||
|
System.out.println("🔍 等级检查: " + level + " → 是否公海池等级: " + isPublicSeaLevel); |
||||
|
|
||||
|
return isPublicSeaLevel; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 销售端:获取客户的购物车信息(公海需求) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO.ProductInfo> getCustomerProducts(String phoneNumber) { |
||||
|
try { |
||||
|
UserProductCartDTO user = usersMapper.selectByPhone(phoneNumber); |
||||
|
if (user != null && ("buyer".equals(user.getType()) || "both".equals(user.getType()))) { |
||||
|
return usersMapper.getSellerProducts(user.getUserId()); |
||||
|
} |
||||
|
return new ArrayList<>(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.mapper.RootdbMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
@Service |
||||
|
public class RootService { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,204 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.mapper.SupplyUsersMapper; |
||||
|
import com.example.web.mapper.SupplyUsersManagementsMapper; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
public class SupplyCustomerRecycleService { |
||||
|
|
||||
|
private static final Logger log = LoggerFactory.getLogger(SupplyCustomerRecycleService.class); |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyUsersManagementsMapper supplyUsersManagementsMapper; |
||||
|
@Autowired |
||||
|
private SupplyUsersMapper supplyUsersMapper; |
||||
|
|
||||
|
// 从配置文件注入回流时间配置
|
||||
|
@Value("${app.recycle.unclassified-to-organization-days:30}") |
||||
|
private int unclassifiedToOrganizationDays; |
||||
|
|
||||
|
@Value("${app.recycle.organization-to-department-days:30}") |
||||
|
private int organizationToDepartmentDays; |
||||
|
|
||||
|
/** |
||||
|
* 客户回流定时任务 - 每天凌晨2点执行 |
||||
|
*/ |
||||
|
@Scheduled(cron = "0 0 2 * * ?") |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void autoRecycleCustomers() { |
||||
|
log.info("🎯 开始执行客户回流任务..."); |
||||
|
log.info("📅 回流配置 - 未分级->组织公海池: {}天, 组织->部门公海池: {}天", |
||||
|
unclassifiedToOrganizationDays, organizationToDepartmentDays); |
||||
|
|
||||
|
try { |
||||
|
// 1. 未分级客户回流到组织公海池
|
||||
|
recycleUnclassifiedToOrganization(); |
||||
|
|
||||
|
// 2. 组织公海池客户回流到部门公海池
|
||||
|
recycleOrganizationToDepartment(); |
||||
|
|
||||
|
log.info("✅ 客户回流任务执行完成"); |
||||
|
} catch (Exception e) { |
||||
|
log.error("❌ 客户回流任务执行失败", e); |
||||
|
throw e; // 抛出异常确保事务回滚
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 未分级客户回流到组织公海池 - 修复:保留负责人信息 |
||||
|
*/ |
||||
|
private void recycleUnclassifiedToOrganization() { |
||||
|
log.info("🔄 开始处理未分级客户回流..."); |
||||
|
|
||||
|
LocalDateTime thresholdTime = LocalDateTime.now().minusDays(unclassifiedToOrganizationDays); |
||||
|
|
||||
|
// 查询超过指定天数未更新的未分级客户
|
||||
|
List<UserProductCartDTO> unclassifiedCustomers = supplyUsersMapper.findUnclassifiedCustomersOlderThan(thresholdTime); |
||||
|
|
||||
|
log.info("📊 找到 {} 个需要回流的未分级客户 (阈值: {}天前)", |
||||
|
unclassifiedCustomers.size(), unclassifiedToOrganizationDays); |
||||
|
|
||||
|
int recycledCount = 0; |
||||
|
for (UserProductCartDTO customer : unclassifiedCustomers) { |
||||
|
try { |
||||
|
// 🔥 关键修改:先查询当前的负责人信息
|
||||
|
UsersManagements currentManager = supplyUsersManagementsMapper.findByUserId(customer.getUserId()); |
||||
|
|
||||
|
log.info("🔍 客户 {} 当前负责人信息: {}", customer.getUserId(), |
||||
|
currentManager != null ? currentManager.getUserName() : "无负责人"); |
||||
|
|
||||
|
// 更新客户等级为组织公海池
|
||||
|
boolean success = supplyUsersMapper.updateCustomerLevel( |
||||
|
customer.getUserId(), |
||||
|
"organization-sea-pools", |
||||
|
LocalDateTime.now() |
||||
|
); |
||||
|
|
||||
|
if (success) { |
||||
|
// 🔥 关键修改:确保负责人信息保留
|
||||
|
if (currentManager != null) { |
||||
|
// 更新负责人信息的更新时间,但不改变负责人本身
|
||||
|
boolean managerUpdated = supplyUsersManagementsMapper.updateManagerUpdateTime( |
||||
|
customer.getUserId(), LocalDateTime.now()); |
||||
|
log.info("✅ 客户 {} 负责人信息已保留: {}", customer.getUserId(), |
||||
|
managerUpdated ? "成功" : "失败"); |
||||
|
} |
||||
|
|
||||
|
recycledCount++; |
||||
|
log.info("🔄 客户 {} 从未分级回流到组织公海池, 负责人: {}", |
||||
|
customer.getUserId(), |
||||
|
currentManager != null ? currentManager.getUserName() : "无"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.error("❌ 回流客户失败: {}", customer.getUserId(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
log.info("✅ 未分级客户回流完成: {} 个客户已回流到组织公海池", recycledCount); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 组织公海池客户回流到部门公海池 - 修复:保留负责人信息 |
||||
|
*/ |
||||
|
private void recycleOrganizationToDepartment() { |
||||
|
log.info("🔄 开始处理组织公海池客户回流..."); |
||||
|
|
||||
|
LocalDateTime thresholdTime = LocalDateTime.now().minusDays(organizationToDepartmentDays); |
||||
|
|
||||
|
// 查询超过指定天数未更新的组织公海池客户
|
||||
|
List<UserProductCartDTO> organizationCustomers = supplyUsersMapper.findOrganizationSeaPoolsCustomersOlderThan(thresholdTime); |
||||
|
|
||||
|
log.info("📊 找到 {} 个需要回流的组织公海池客户 (阈值: {}天前)", |
||||
|
organizationCustomers.size(), organizationToDepartmentDays); |
||||
|
|
||||
|
int recycledCount = 0; |
||||
|
for (UserProductCartDTO customer : organizationCustomers) { |
||||
|
try { |
||||
|
// 🔥 关键修改:先查询当前的负责人信息
|
||||
|
UsersManagements currentManager = supplyUsersManagementsMapper.findByUserId(customer.getUserId()); |
||||
|
|
||||
|
log.info("🔍 客户 {} 当前负责人信息: {}", customer.getUserId(), |
||||
|
currentManager != null ? currentManager.getUserName() : "无负责人"); |
||||
|
|
||||
|
// 更新客户等级为部门公海池
|
||||
|
boolean success = supplyUsersMapper.updateCustomerLevel( |
||||
|
customer.getUserId(), |
||||
|
"department-sea-pools", |
||||
|
LocalDateTime.now() |
||||
|
); |
||||
|
|
||||
|
if (success) { |
||||
|
// 🔥 关键修改:确保负责人信息保留
|
||||
|
if (currentManager != null) { |
||||
|
// 更新负责人信息的更新时间,但不改变负责人本身
|
||||
|
boolean managerUpdated = supplyUsersManagementsMapper.updateManagerUpdateTime( |
||||
|
customer.getUserId(), LocalDateTime.now()); |
||||
|
log.info("✅ 客户 {} 负责人信息已保留: {}", customer.getUserId(), |
||||
|
managerUpdated ? "成功" : "失败"); |
||||
|
} |
||||
|
|
||||
|
recycledCount++; |
||||
|
log.info("🔄 客户 {} 从组织公海池回流到部门公海池, 负责人: {}", |
||||
|
customer.getUserId(), |
||||
|
currentManager != null ? currentManager.getUserName() : "无"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.error("❌ 回流客户失败: {}", customer.getUserId(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
log.info("✅ 组织公海池客户回流完成: {} 个客户已回流到部门公海池", recycledCount); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 手动触发回流任务(用于测试或手动执行) |
||||
|
*/ |
||||
|
public void manualRecycle() { |
||||
|
log.info("🔧 手动触发客户回流任务..."); |
||||
|
autoRecycleCustomers(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前回流配置信息(用于调试或监控) |
||||
|
*/ |
||||
|
public String getRecycleConfigInfo() { |
||||
|
return String.format("回流配置 - 未分级->组织公海池: %d天, 组织->部门公海池: %d天", |
||||
|
unclassifiedToOrganizationDays, organizationToDepartmentDays); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 🔥 新增:获取回流客户完整信息(用于前端显示) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO> getRecycledCustomersWithManagerInfo() { |
||||
|
log.info("🔍 获取回流客户完整信息(包含负责人信息)"); |
||||
|
|
||||
|
// 获取最近回流的客户(例如最近1天内回流的)
|
||||
|
LocalDateTime sinceTime = LocalDateTime.now().minusDays(1); |
||||
|
List<UserProductCartDTO> recycledCustomers = supplyUsersMapper.findRecentlyRecycledCustomers(sinceTime); |
||||
|
|
||||
|
// 为每个客户加载负责人信息
|
||||
|
for (UserProductCartDTO customer : recycledCustomers) { |
||||
|
UsersManagements manager = supplyUsersManagementsMapper.findByUserId(customer.getUserId()); |
||||
|
if (manager != null) { |
||||
|
// 将负责人信息设置到DTO中(需要扩展UserProductCartDTO或使用其他方式)
|
||||
|
log.info("✅ 客户 {} 回流后负责人信息: {}", customer.getUserId(), manager.getUserName()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
log.info("📊 获取到 {} 个回流客户的完整信息", recycledCustomers.size()); |
||||
|
return recycledCustomers; |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,515 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.EnterpriseInfoDTO; |
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UnifiedCustomerDTO; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.Contacts; |
||||
|
import com.example.web.entity.Enterprise; |
||||
|
import com.example.web.entity.Managers; |
||||
|
import com.example.web.mapper.*; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
import java.util.UUID; |
||||
|
|
||||
|
@Service |
||||
|
public class SupplyEnterpriseService { |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyEnterpriseMapper supplyenterpriseMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyContactsMapper supplycontactsMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyManagersMapper supplymanagersMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyUsersMapper supplyusersMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyPoolCustomerService supplypoolCustomerService; |
||||
|
|
||||
|
|
||||
|
// 修改:检查电话号码是否重复(同时检查两个数据源)
|
||||
|
public boolean isPhoneNumberDuplicate(String phoneNumber) { |
||||
|
// 1. 检查微信数据源中的电话号码是否重复
|
||||
|
boolean wechatDuplicate = false; |
||||
|
try { |
||||
|
UserProductCartDTO existingUser = supplyusersMapper.selectByPhone(phoneNumber); |
||||
|
wechatDuplicate = existingUser != null; |
||||
|
if (wechatDuplicate) { |
||||
|
System.out.println("❌ [采购端] 电话号码在微信数据源中已存在: " + phoneNumber); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 查询微信数据源电话号码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 2. 检查默认数据源(userlogin)中的电话号码是否重复
|
||||
|
boolean defaultDuplicate = false; |
||||
|
try { |
||||
|
int count = supplycontactsMapper.countByPhoneNumber(phoneNumber); |
||||
|
defaultDuplicate = count > 0; |
||||
|
if (defaultDuplicate) { |
||||
|
System.out.println("❌ [采购端] 电话号码在默认数据源中已存在: " + phoneNumber); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 查询默认数据源电话号码失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 3. 返回最终结果:任意一个数据源中存在都算重复
|
||||
|
boolean isDuplicate = wechatDuplicate || defaultDuplicate; |
||||
|
System.out.println("📞 [采购端] 电话号码重复检查结果: " + phoneNumber + |
||||
|
" -> 微信数据源:" + wechatDuplicate + |
||||
|
", 默认数据源:" + defaultDuplicate + |
||||
|
", 最终结果:" + isDuplicate); |
||||
|
|
||||
|
return isDuplicate; |
||||
|
} |
||||
|
|
||||
|
// 类型转换方法(保持与销售端一致)
|
||||
|
private String convertFrontendTypeToDatabase(String frontendType) { |
||||
|
if (frontendType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (frontendType) { |
||||
|
case "供应端": |
||||
|
return "seller"; |
||||
|
case "客户端": |
||||
|
return "buyer"; |
||||
|
case "BOTH": |
||||
|
return "both"; // 改为小写
|
||||
|
default: |
||||
|
return frontendType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private String convertDatabaseTypeToFrontend(String databaseType) { |
||||
|
if (databaseType == null) { |
||||
|
return null; |
||||
|
} |
||||
|
switch (databaseType) { |
||||
|
case "seller": |
||||
|
return "供应端"; |
||||
|
case "buyer": |
||||
|
return "客户端"; |
||||
|
case "both": // 匹配小写的数据库存储
|
||||
|
return "BOTH"; |
||||
|
default: |
||||
|
return databaseType; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
// 新增客户:保存企业、联系人、负责人信息(默认数据源)
|
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public boolean addCustomer(UnifiedCustomerDTO dto) { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("➕ [采购端] 开始新增客户到默认数据源"); |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("📋 客户信息: 手机=" + dto.getPhoneNumber() + |
||||
|
", 公司=" + dto.getCompany() + |
||||
|
", 类型=" + dto.getType() + |
||||
|
", 等级=" + dto.getLevel()); |
||||
|
|
||||
|
// 1. 转换前端类型为数据库类型
|
||||
|
String databaseType = convertFrontendTypeToDatabase(dto.getType()); |
||||
|
dto.setType(databaseType); |
||||
|
System.out.println("🔄 [采购端] 类型转换: 前端=" + dto.getType() + " → 数据库=" + databaseType); |
||||
|
|
||||
|
// 2. 权限校验(采购端:仅允许seller/both)
|
||||
|
if (!"seller".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
System.out.println("❌ [采购端] 权限校验失败: 采购端只能新增供应端类型客户和BOTH类型客户"); |
||||
|
throw new IllegalArgumentException("采购端权限只能新增供应端类型客户和BOTH类型客户"); |
||||
|
} |
||||
|
System.out.println("✅ [采购端] 权限校验通过"); |
||||
|
|
||||
|
// 3. 等级校验
|
||||
|
if (!StringUtils.hasText(dto.getLevel())) { |
||||
|
System.out.println("❌ [采购端] 等级校验失败: 客户等级不能为空"); |
||||
|
throw new IllegalArgumentException("客户等级不能为空"); |
||||
|
} |
||||
|
System.out.println("✅ [采购端] 等级校验通过"); |
||||
|
|
||||
|
// 4. 检查电话号码是否重复
|
||||
|
System.out.println("🔍 [采购端] 检查电话号码重复性..."); |
||||
|
if (isPhoneNumberDuplicate(dto.getPhoneNumber())) { |
||||
|
System.out.println("❌ [采购端] 电话号码重复: " + dto.getPhoneNumber()); |
||||
|
throw new IllegalArgumentException("电话号码已存在"); |
||||
|
} |
||||
|
System.out.println("✅ [采购端] 电话号码检查通过"); |
||||
|
|
||||
|
// 5. 封装并保存企业信息
|
||||
|
System.out.println("💾 [采购端] 保存企业信息..."); |
||||
|
Enterprise enterprise = new Enterprise(); |
||||
|
enterprise.setId(dto.getId()); |
||||
|
enterprise.setCompany(dto.getCompany()); |
||||
|
enterprise.setRegion(dto.getRegion()); |
||||
|
enterprise.setLevel(dto.getLevel()); |
||||
|
enterprise.setType(dto.getType()); |
||||
|
enterprise.setDemand(dto.getDemand()); |
||||
|
enterprise.setSpec(dto.getSpec()); |
||||
|
|
||||
|
int enterpriseRows = supplyenterpriseMapper.insertEnterprise(enterprise); |
||||
|
System.out.println("✅ [采购端] 企业信息保存结果: " + enterpriseRows + " 行受影响"); |
||||
|
|
||||
|
// 6. 封装联系人信息
|
||||
|
System.out.println("💾 [采购端] 保存联系人信息..."); |
||||
|
Contacts contacts = new Contacts(); |
||||
|
String contactId = UUID.randomUUID().toString().replaceAll("-", ""); |
||||
|
contacts.setContact_id(contactId); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
contacts.setPhoneNumber(dto.getPhoneNumber()); |
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
contacts.setCreated_at(dto.getCreated_at() != null ? dto.getCreated_at() : LocalDateTime.now()); |
||||
|
contacts.setUpdated_at(dto.getUpdated_at() != null ? dto.getUpdated_at() : LocalDateTime.now()); |
||||
|
|
||||
|
int contactsRows = supplycontactsMapper.insertContacts(contacts); |
||||
|
System.out.println("✅ [采购端] 联系人信息保存结果: " + contactsRows + " 行受影响"); |
||||
|
|
||||
|
// 7. 封装负责人信息 - 使用前端传递的认证信息(更新为新表结构)
|
||||
|
System.out.println("💾 [采购端] 保存负责人信息..."); |
||||
|
Managers managers = new Managers(); |
||||
|
managers.setId(dto.getId()); |
||||
|
managers.setManagerId(StringUtils.hasText(dto.getManagerId()) ? dto.getManagerId() : "未分配"); |
||||
|
managers.setManagercompany(StringUtils.hasText(dto.getManagercompany()) ? dto.getManagercompany() : "未分配"); |
||||
|
managers.setManagerdepartment(StringUtils.hasText(dto.getManagerdepartment()) ? dto.getManagerdepartment() : "未分配"); |
||||
|
managers.setOrganization(StringUtils.hasText(dto.getOrganization()) ? dto.getOrganization() : "未分配"); |
||||
|
managers.setRole(StringUtils.hasText(dto.getRole()) ? dto.getRole() : "未分配"); |
||||
|
managers.setRoot("2"); // 采购端默认权限
|
||||
|
managers.setUserName(StringUtils.hasText(dto.getUserName()) ? dto.getUserName() : "未分配"); |
||||
|
managers.setAssistant(StringUtils.hasText(dto.getAssistant()) ? dto.getAssistant() : "无"); |
||||
|
managers.setCreated_at(LocalDateTime.now()); |
||||
|
managers.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int managersRows = supplymanagersMapper.insertManagers(managers); |
||||
|
System.out.println("✅ [采购端] 负责人信息保存结果: " + managersRows + " 行受影响"); |
||||
|
|
||||
|
boolean success = enterpriseRows > 0 && contactsRows > 0 && managersRows > 0; |
||||
|
|
||||
|
if (success) { |
||||
|
System.out.println("🎉 [采购端] 新增客户成功,负责人信息已自动填充"); |
||||
|
// 记录负责人信息详情
|
||||
|
System.out.println("📝 [采购端] 负责人信息详情: " + |
||||
|
"负责人id=" + managers.getManagerId() + |
||||
|
"负责公司=" + managers.getManagercompany() + |
||||
|
", 负责部门=" + managers.getManagerdepartment() + |
||||
|
", 组织=" + managers.getOrganization() + |
||||
|
", 角色=" + managers.getRole() + |
||||
|
", 负责人=" + managers.getUserName() + |
||||
|
", 协助人=" + managers.getAssistant()); |
||||
|
} else { |
||||
|
System.out.println("❌ [采购端] 新增客户失败"); |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 获取所有企业的完整信息(企业信息 + 联系人信息 + 负责人信息) |
||||
|
*/ |
||||
|
public List<EnterpriseInfoDTO> getAllEnterpriseInfo() { |
||||
|
try { |
||||
|
return supplyenterpriseMapper.selectAllEnterpriseInfo(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 获取所有企业信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取详细信息 |
||||
|
*/ |
||||
|
public EnterpriseInfoDTO getEnterpriseInfoById(String id) { |
||||
|
try { |
||||
|
System.out.println("🔍 [采购端] 根据企业ID查询信息: " + id); |
||||
|
return supplyenterpriseMapper.selectEnterpriseInfoById(id); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 根据企业ID查询信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有企业基本信息 |
||||
|
*/ |
||||
|
public List<Enterprise> getAllEnterprises() { |
||||
|
try { |
||||
|
return supplyenterpriseMapper.selectAllEnterprises(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 获取所有企业基本信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取联系人信息 |
||||
|
*/ |
||||
|
public List<Contacts> getContactsByEnterpriseId(String id) { |
||||
|
try { |
||||
|
return supplycontactsMapper.selectContactsByEnterpriseId(id); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 根据企业ID获取联系人信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据企业ID获取负责人信息 |
||||
|
*/ |
||||
|
public List<Managers> getManagersByEnterpriseId(String id) { |
||||
|
try { |
||||
|
return supplymanagersMapper.selectManagersByEnterpriseId(id); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 根据企业ID获取负责人信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 搜索企业信息(根据企业名称、地区、类型等) |
||||
|
*/ |
||||
|
public List<EnterpriseInfoDTO> searchEnterprises(String keyword) { |
||||
|
try { |
||||
|
System.out.println("🔍 [采购端] 搜索企业信息,关键词: " + keyword); |
||||
|
// 这里可以扩展更复杂的搜索逻辑
|
||||
|
List<EnterpriseInfoDTO> allInfo = supplyenterpriseMapper.selectAllEnterpriseInfo(); |
||||
|
if (keyword == null || keyword.trim().isEmpty()) { |
||||
|
return allInfo; |
||||
|
} |
||||
|
|
||||
|
List<EnterpriseInfoDTO> result = new ArrayList<>(); |
||||
|
for (EnterpriseInfoDTO info : allInfo) { |
||||
|
if (info.getEnterprise() != null) { |
||||
|
String company = info.getEnterprise().getCompany() != null ? info.getEnterprise().getCompany().toLowerCase() : ""; |
||||
|
String region = info.getEnterprise().getRegion() != null ? info.getEnterprise().getRegion().toLowerCase() : ""; |
||||
|
String type = info.getEnterprise().getType() != null ? info.getEnterprise().getType().toLowerCase() : ""; |
||||
|
|
||||
|
if (company.contains(keyword.toLowerCase()) || |
||||
|
region.contains(keyword.toLowerCase()) || |
||||
|
type.contains(keyword.toLowerCase())) { |
||||
|
result.add(info); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("[采购端] 搜索企业信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新默认数据源客户信息(企业、联系人、负责人)- 同步销售端,增加ManagerAuthInfo参数 |
||||
|
*/ |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public boolean updateDefaultCustomer(UnifiedCustomerDTO dto, ManagerAuthInfo authInfo) { |
||||
|
// 转换前端类型为数据库类型
|
||||
|
String databaseType = convertFrontendTypeToDatabase(dto.getType()); |
||||
|
dto.setType(databaseType); |
||||
|
|
||||
|
// 采购员权限:校验客户类型,只允许seller和both
|
||||
|
if (!"seller".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
throw new IllegalArgumentException("采购员权限只能更新为供应端类型客户和BOTH类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 1. 更新企业信息
|
||||
|
Enterprise enterprise = new Enterprise(); |
||||
|
enterprise.setId(dto.getId()); |
||||
|
enterprise.setCompany(dto.getCompany()); |
||||
|
enterprise.setRegion(dto.getRegion()); |
||||
|
enterprise.setLevel(dto.getLevel()); |
||||
|
enterprise.setType(dto.getType()); |
||||
|
enterprise.setDemand(dto.getDemand()); |
||||
|
enterprise.setSpec(dto.getSpec()); |
||||
|
int enterpriseRows = supplyenterpriseMapper.updateEnterprise(enterprise); |
||||
|
|
||||
|
if (enterpriseRows <= 0) { |
||||
|
throw new RuntimeException("更新企业信息失败,企业ID: " + dto.getId()); |
||||
|
} |
||||
|
|
||||
|
// 2. 更新联系人信息 - 修复逻辑(与销售端一致)
|
||||
|
Contacts contacts = new Contacts(); |
||||
|
// 先根据企业ID查询原始联系人信息
|
||||
|
List<Contacts> originalContactsList = supplycontactsMapper.selectContactsByEnterpriseId(dto.getId()); |
||||
|
if (originalContactsList != null && !originalContactsList.isEmpty()) { |
||||
|
Contacts originalContacts = originalContactsList.get(0); |
||||
|
contacts.setContact_id(originalContacts.getContact_id()); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
// 关键:使用原始电话号码,禁止修改
|
||||
|
contacts.setPhoneNumber(originalContacts.getPhoneNumber()); |
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
|
||||
|
int contactsRows = supplycontactsMapper.updateContacts(contacts); |
||||
|
if (contactsRows <= 0) { |
||||
|
throw new RuntimeException("更新联系人信息失败,联系人ID: " + originalContacts.getContact_id()); |
||||
|
} |
||||
|
} else { |
||||
|
// 如果没有找到联系人记录,创建新的联系人
|
||||
|
System.out.println("[采购端] 未找到现有联系人,创建新的联系人记录"); |
||||
|
contacts.setContact_id(UUID.randomUUID().toString().replaceAll("-", "")); |
||||
|
contacts.setId(dto.getId()); |
||||
|
contacts.setNickName(dto.getNickName()); |
||||
|
contacts.setPhoneNumber(""); // 新创建的联系人电话号码为空
|
||||
|
contacts.setWechat(dto.getWechat()); |
||||
|
contacts.setAccount(dto.getAccount()); |
||||
|
contacts.setAccountNumber(dto.getAccountNumber()); |
||||
|
contacts.setBank(dto.getBank()); |
||||
|
contacts.setAddress(dto.getAddress()); |
||||
|
contacts.setCreated_at(LocalDateTime.now()); |
||||
|
contacts.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int contactsRows = supplycontactsMapper.insertContacts(contacts); |
||||
|
if (contactsRows <= 0) { |
||||
|
throw new RuntimeException("创建联系人信息失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 3. 更新负责人信息 - 只有非公海池客户且前端提交了负责人信息时才更新
|
||||
|
// 定义公海池和非公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
Set<String> nonPublicSeaLevels = Set.of("important", "normal", "low-value", "logistics", "unclassified"); |
||||
|
|
||||
|
// 检查是否是非公海池客户且前端提交了负责人信息
|
||||
|
boolean isNonPublicSeaCustomer = nonPublicSeaLevels.contains(dto.getLevel()); |
||||
|
boolean hasFrontendManagerInfo = StringUtils.hasText(dto.getManagercompany()) || |
||||
|
StringUtils.hasText(dto.getManagerdepartment()) || |
||||
|
StringUtils.hasText(dto.getOrganization()) || |
||||
|
StringUtils.hasText(dto.getRole()) || |
||||
|
StringUtils.hasText(dto.getUserName()) || |
||||
|
StringUtils.hasText(dto.getAssistant()); |
||||
|
|
||||
|
System.out.println("🎯 [采购端] 默认数据源负责人更新检查: " + |
||||
|
"客户等级=" + dto.getLevel() + |
||||
|
", 是否非公海池=" + isNonPublicSeaCustomer + |
||||
|
", 前端提交负责人信息=" + hasFrontendManagerInfo); |
||||
|
|
||||
|
// 只有非公海池客户且前端提交了负责人信息时才更新
|
||||
|
if (isNonPublicSeaCustomer && hasFrontendManagerInfo) { |
||||
|
System.out.println("✅ [采购端] 更新默认数据源负责人信息"); |
||||
|
|
||||
|
Managers managers = new Managers(); |
||||
|
managers.setId(dto.getId()); |
||||
|
|
||||
|
// 使用前端提交的数据
|
||||
|
managers.setManagercompany(dto.getManagercompany()); |
||||
|
managers.setManagerdepartment(dto.getManagerdepartment()); |
||||
|
managers.setOrganization(dto.getOrganization()); |
||||
|
managers.setRole(dto.getRole()); |
||||
|
managers.setUserName(dto.getUserName()); |
||||
|
managers.setAssistant(dto.getAssistant()); |
||||
|
|
||||
|
managers.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int managersRows = supplymanagersMapper.updateManagers(managers); |
||||
|
if (managersRows <= 0) { |
||||
|
// 如果没有更新到记录,尝试插入
|
||||
|
System.out.println("[采购端] 未找到现有负责人记录,创建新的负责人记录"); |
||||
|
managers.setManagerId(authInfo.getManagerId()); |
||||
|
managers.setRoot("2"); // 采购端默认权限
|
||||
|
managers.setCreated_at(LocalDateTime.now()); |
||||
|
managersRows = supplymanagersMapper.insertManagers(managers); |
||||
|
if (managersRows <= 0) { |
||||
|
throw new RuntimeException("更新负责人信息失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("✅ [采购端] 默认数据源负责人信息更新完成,影响行数: " + managersRows); |
||||
|
} else { |
||||
|
System.out.println("ℹ️ [采购端] 跳过默认数据源负责人信息更新"); |
||||
|
if (!isNonPublicSeaCustomer) { |
||||
|
System.out.println(" 原因: 客户是公海池客户,等级=" + dto.getLevel()); |
||||
|
} else if (!hasFrontendManagerInfo) { |
||||
|
System.out.println(" 原因: 前端未提交负责人信息"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新wechat数据源的客户信息(用户和产品信息) |
||||
|
*/ |
||||
|
public boolean updateWechatCustomer(UnifiedCustomerDTO dto) { |
||||
|
// 修复:确保类型转换正确
|
||||
|
String type = dto.getType(); |
||||
|
if ("BOTH".equals(type)) { |
||||
|
type = "both"; |
||||
|
dto.setType(type); |
||||
|
} else if ("客户端".equals(type)) { |
||||
|
type = "buyer"; |
||||
|
dto.setType(type); |
||||
|
} else if ("供应端".equals(type)) { |
||||
|
type = "seller"; |
||||
|
dto.setType(type); |
||||
|
} |
||||
|
|
||||
|
// 采购员权限:校验客户类型,只允许seller和both
|
||||
|
if (!"seller".equals(dto.getType()) && !"both".equals(dto.getType())) { |
||||
|
throw new IllegalArgumentException("采购权限只能更新为供应端类型客户和BOTH类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 1. 根据手机号查询wechat用户ID(关联用户与产品)
|
||||
|
UserProductCartDTO user = supplyusersMapper.selectByPhone(dto.getPhoneNumber()); |
||||
|
if (user == null) { |
||||
|
// 若该用户在wechat数据源中不存在,无需更新
|
||||
|
return true; |
||||
|
} |
||||
|
// 2. 更新用户基本信息
|
||||
|
UserProductCartDTO updateUser = new UserProductCartDTO(); |
||||
|
updateUser.setUserId(user.getUserId()); |
||||
|
updateUser.setPhoneNumber(dto.getPhoneNumber()); |
||||
|
updateUser.setNickName(dto.getNickName()); |
||||
|
updateUser.setType(dto.getType()); |
||||
|
updateUser.setUpdated_at(LocalDateTime.now()); |
||||
|
|
||||
|
int rows = supplyusersMapper.updateByPhone(updateUser); |
||||
|
System.out.println("[采购端] 更新用户基本信息影响行数: " + rows); |
||||
|
|
||||
|
// 3. 如果有产品信息需要更新
|
||||
|
if (("seller".equals(dto.getType()) || "both".equals(dto.getType())) && |
||||
|
dto.getProductName() != null && !dto.getProductName().trim().isEmpty()) { |
||||
|
|
||||
|
System.out.println("[采购端] 更新产品信息"); |
||||
|
int productRows = supplyusersMapper.updateProductBySellerId( |
||||
|
user.getUserId(), |
||||
|
dto.getProductName(), |
||||
|
dto.getVariety(), |
||||
|
dto.getSpecification(), |
||||
|
dto.getQuantity(), |
||||
|
dto.getGrossWeight(), |
||||
|
dto.getYolk() |
||||
|
); |
||||
|
System.out.println("[采购端] 更新产品信息影响行数: " + productRows); |
||||
|
} |
||||
|
|
||||
|
return rows > 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,799 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.ManagerAuthInfo; |
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.entity.UsersManagements; |
||||
|
import com.example.web.mapper.SupplyUsersManagementsMapper; |
||||
|
import com.example.web.mapper.SupplyUsersMapper; |
||||
|
import com.example.web.mapper.UsersManagementsMapper; |
||||
|
import com.example.web.mapper.UsersMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.util.StringUtils; |
||||
|
|
||||
|
import java.util.*; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Service |
||||
|
public class SupplyPoolCustomerService { |
||||
|
|
||||
|
@Autowired |
||||
|
private SupplyUsersMapper supplyusersMapper; |
||||
|
@Autowired |
||||
|
private SupplyUsersManagementsMapper supplyUsersManagementsMapper; |
||||
|
|
||||
|
/** |
||||
|
* 根据手机号查询微信用户信息(采购端权限:只处理seller和both类型)- 支持一对多 |
||||
|
*/ |
||||
|
public UserProductCartDTO getWechatCustomerByPhone(String phoneNumber) { |
||||
|
if (!StringUtils.hasText(phoneNumber)) { |
||||
|
throw new IllegalArgumentException("手机号不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 1. 根据手机号查询微信用户基本信息
|
||||
|
UserProductCartDTO userInfo = supplyusersMapper.selectByPhone(phoneNumber); |
||||
|
if (userInfo == null) { |
||||
|
throw new RuntimeException("未找到手机号对应的微信用户:" + phoneNumber); |
||||
|
} |
||||
|
|
||||
|
System.out.println("🔍 获取到用户基础信息,用户ID: " + userInfo.getUserId() + |
||||
|
", 类型: " + userInfo.getType() + |
||||
|
", 公司: " + userInfo.getCompany() + |
||||
|
", 需求: " + userInfo.getDemand() + |
||||
|
", 规格: " + userInfo.getSpec()); |
||||
|
|
||||
|
// 采购端权限校验:只处理seller和both类型
|
||||
|
if (!"seller".equals(userInfo.getType()) && !"both".equals(userInfo.getType())) { |
||||
|
System.out.println("❌ 权限校验失败: 采购端只能处理供应端和BOTH类型客户"); |
||||
|
throw new IllegalArgumentException("采购端权限只能处理供应端和BOTH类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 2. 获取所有联系人信息(一对多)
|
||||
|
try { |
||||
|
List<SupplyUsersMapper.ContactInfo> contacts = supplyusersMapper.getUserAllContacts(userInfo.getUserId()); |
||||
|
// 转换为UserProductCartDTO.UsersContacts格式以保持兼容
|
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
// 设置contactId
|
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setUsersContacts(userContacts); |
||||
|
} else { |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
System.out.println("✅ 获取用户所有联系人信息,数量: " + (userInfo.getUsersContacts() != null ? userInfo.getUsersContacts().size() : 0)); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 3. 采购端:获取所有产品项信息(一对多)- 公海需求
|
||||
|
if ("seller".equals(userInfo.getType()) || "both".equals(userInfo.getType())) { |
||||
|
try { |
||||
|
List<SupplyUsersMapper.ProductInfo> products = supplyusersMapper.getUserAllProducts(userInfo.getUserId()); |
||||
|
// 转换为UserProductCartDTO.ProductInfo格式以保持兼容
|
||||
|
if (products != null && !products.isEmpty()) { |
||||
|
List<UserProductCartDTO.ProductInfo> userProducts = products.stream() |
||||
|
.map(item -> { |
||||
|
UserProductCartDTO.ProductInfo product = new UserProductCartDTO.ProductInfo(); |
||||
|
product.setProductId(item.getProductId()); |
||||
|
product.setProductName(item.getProductName()); |
||||
|
product.setVariety(item.getVariety()); |
||||
|
product.setSpecification(item.getSpecification()); |
||||
|
product.setQuantity(item.getQuantity()); |
||||
|
product.setGrossWeight(item.getGrossWeight()); |
||||
|
product.setYolk(item.getYolk()); |
||||
|
return product; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setProducts(userProducts); |
||||
|
} else { |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
System.out.println("✅ 获取用户所有产品项信息,数量: " + (userInfo.getProducts() != null ? userInfo.getProducts().size() : 0)); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取产品信息失败: " + e.getMessage()); |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
userInfo.setCartItems(Collections.emptyList()); // 采购端不使用购物车信息
|
||||
|
} |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据用户ID获取用户信息和相关产品数据(采购端版本) |
||||
|
*/ |
||||
|
public UserProductCartDTO getCustomerInfo(String userId) { |
||||
|
if (!StringUtils.hasText(userId)) { |
||||
|
throw new IllegalArgumentException("用户ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 1. 获取用户基本信息
|
||||
|
UserProductCartDTO userInfo = supplyusersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo == null) { |
||||
|
throw new RuntimeException("用户不存在: " + userId); |
||||
|
} |
||||
|
|
||||
|
// 采购端权限校验
|
||||
|
if (!"seller".equals(userInfo.getType()) && !"both".equals(userInfo.getType())) { |
||||
|
throw new IllegalArgumentException("采购端权限只能查看供应端和BOTH类型客户"); |
||||
|
} |
||||
|
|
||||
|
// 2. 采购端:查询产品信息(公海需求)
|
||||
|
List<UserProductCartDTO.ProductInfo> products = supplyusersMapper.getSellerProducts(userId); |
||||
|
userInfo.setProducts(products != null ? products : Collections.emptyList()); |
||||
|
userInfo.setCartItems(Collections.emptyList()); // 采购端不使用购物车
|
||||
|
|
||||
|
// 3. 获取联系人信息 - 安全处理
|
||||
|
try { |
||||
|
List<UserProductCartDTO.UsersContacts> contacts = supplyusersMapper.getUserContacts(userId); |
||||
|
userInfo.setUsersContacts(contacts != null ? contacts : Collections.emptyList()); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有客户信息 - 使用数据库层面权限过滤(采购端版本)- 优化版(支持分页) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO> getAllCustomers(ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🚀 开始获取所有微信用户数据(数据库权限过滤,采购端)..."); |
||||
|
System.out.println("🔐 负责人过滤条件: " + |
||||
|
"公司=" + authInfo.getManagercompany() + |
||||
|
", 部门=" + authInfo.getManagerdepartment()); |
||||
|
|
||||
|
// 移除固定的分页限制,获取所有数据
|
||||
|
int limit = Integer.MAX_VALUE; // 获取所有数据
|
||||
|
int offset = 0; // 从第一条开始
|
||||
|
|
||||
|
// 1. 获取授权客户总数
|
||||
|
System.out.println("📊 查询授权客户总数..."); |
||||
|
int totalCount = supplyusersMapper.getAuthorizedCustomersCount(authInfo); |
||||
|
System.out.println("✅ 授权客户总数: " + totalCount); |
||||
|
|
||||
|
// 2. 使用数据库层面权限过滤并分页
|
||||
|
System.out.println("📋 查询授权客户基础信息(分页查询)..."); |
||||
|
List<UserProductCartDTO> authorizedUsers = supplyusersMapper.getAuthorizedCustomers(authInfo, limit, offset); |
||||
|
|
||||
|
System.out.println("✅ 授权客户数据查询完成"); |
||||
|
System.out.println("📊 当前页获取到授权客户数据条数: " + (authorizedUsers != null ? authorizedUsers.size() : "null")); |
||||
|
|
||||
|
List<UserProductCartDTO> result = new ArrayList<>(); |
||||
|
|
||||
|
if (authorizedUsers != null && !authorizedUsers.isEmpty()) { |
||||
|
// 🔥 新增:收集所有用户ID用于批量查询
|
||||
|
List<String> userIds = authorizedUsers.stream() |
||||
|
.map(UserProductCartDTO::getUserId) |
||||
|
.filter(Objects::nonNull) |
||||
|
.filter(userId -> !userId.trim().isEmpty()) |
||||
|
.distinct() |
||||
|
.collect(Collectors.toList()); |
||||
|
|
||||
|
System.out.println("🔍 需要批量查询的授权用户数量: " + userIds.size()); |
||||
|
|
||||
|
// 🔥 新增:批量查询所有相关数据
|
||||
|
Map<String, UsersManagements> managerMap = batchQueryManagers(userIds); |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = batchQueryContacts(userIds); |
||||
|
Map<String, List<UserProductCartDTO.ProductInfo>> productsMap = batchQueryProducts(userIds); |
||||
|
|
||||
|
// 2. 为每个授权用户构建完整信息(使用批量数据)
|
||||
|
System.out.println("🔄 开始处理 " + authorizedUsers.size() + " 条授权用户数据..."); |
||||
|
|
||||
|
for (int i = 0; i < authorizedUsers.size(); i++) { |
||||
|
UserProductCartDTO user = authorizedUsers.get(i); |
||||
|
try { |
||||
|
// 🎯 关键修改:使用批量查询的数据构建完整用户信息
|
||||
|
UserProductCartDTO fullUserInfo = buildSupplyUserInfoFromBatchData(user, managerMap, contactsMap, productsMap); |
||||
|
if (fullUserInfo != null) { |
||||
|
// 数据库已经过滤了权限,这里直接添加
|
||||
|
result.add(fullUserInfo); |
||||
|
|
||||
|
// 打印前几个客户的详细信息
|
||||
|
if (i < 3) { |
||||
|
System.out.println("📝 授权客户样例 " + (i + 1) + ": " + |
||||
|
"ID=" + fullUserInfo.getUserId() + |
||||
|
", 手机=" + fullUserInfo.getPhoneNumber() + |
||||
|
", 公司=" + fullUserInfo.getCompany() + |
||||
|
", 类型=" + fullUserInfo.getType() + |
||||
|
", 联系人数量=" + (fullUserInfo.getUsersContacts() != null ? fullUserInfo.getUsersContacts().size() : 0) + |
||||
|
", 产品数量=" + (fullUserInfo.getProducts() != null ? fullUserInfo.getProducts().size() : 0) + |
||||
|
", 是否公海池=" + isPublicSeaCustomer(fullUserInfo, authInfo)); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 构建用户 " + user.getUserId() + " 的详细信息时出错: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🎉 数据获取完成(数据库权限过滤,采购端)"); |
||||
|
System.out.println("📊 返回记录数: " + result.size()); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取授权客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否有权限查看客户 |
||||
|
*/ |
||||
|
private boolean hasPermissionToViewCustomer(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
// 公海池客户使用特殊权限检查
|
||||
|
if (isPublicSeaCustomer(userInfo, authInfo)) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// 非公海池客户需要检查负责人权限
|
||||
|
return hasUserManagerPermission(userInfo.getUserId(), authInfo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断是否为公海池客户 - 根据不同类型使用不同逻辑 |
||||
|
*/ |
||||
|
private boolean isPublicSeaCustomer(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
|
||||
|
// 检查等级是否为公海池
|
||||
|
boolean isPublicSeaLevel = publicSeaLevels.contains(userInfo.getLevel()); |
||||
|
System.out.println("🔍 客户等级检查: " + userInfo.getLevel() + " → 是否公海池等级: " + isPublicSeaLevel); |
||||
|
|
||||
|
if (!isPublicSeaLevel) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 根据不同类型的公海池使用不同判断逻辑
|
||||
|
String level = userInfo.getLevel(); |
||||
|
|
||||
|
if ("company-sea-pools".equals(level) || "公海池".equals(level)) { |
||||
|
// 公司公海池:必须没有负责人信息
|
||||
|
boolean result = !hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
System.out.println("🏢 公司公海池检查结果: " + result); |
||||
|
return result; |
||||
|
} else if ("organization-sea-pools".equals(level)) { |
||||
|
// 组织公海池:必须有负责人信息且组织匹配
|
||||
|
boolean hasManager = hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
if (!hasManager) { |
||||
|
System.out.println("🏢 组织公海池:无负责人信息,不允许查看"); |
||||
|
return false; |
||||
|
} |
||||
|
boolean sameOrganization = hasSameOrganization(userInfo.getUserId(), authInfo); |
||||
|
System.out.println("🏢 组织公海池检查结果 - 有负责人: " + hasManager + ", 组织匹配: " + sameOrganization + " → 结果: " + sameOrganization); |
||||
|
return sameOrganization; |
||||
|
} else if ("department-sea-pools".equals(level)) { |
||||
|
// 部门公海池:必须有负责人信息且部门匹配
|
||||
|
boolean hasManager = hasManagerAuthInfo(userInfo.getUserId()); |
||||
|
if (!hasManager) { |
||||
|
System.out.println("🏢 部门公海池:无负责人信息,不允许查看"); |
||||
|
return false; |
||||
|
} |
||||
|
boolean sameDepartment = hasSameDepartment(userInfo.getUserId(), authInfo); |
||||
|
System.out.println("🏢 部门公海池检查结果 - 有负责人: " + hasManager + ", 部门匹配: " + sameDepartment + " → 结果: " + sameDepartment); |
||||
|
return sameDepartment; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 公共方法:判断是否为公海池客户(供Controller调用) |
||||
|
*/ |
||||
|
public boolean isPublicSeaCustomerPublic(UserProductCartDTO userInfo, ManagerAuthInfo authInfo) { |
||||
|
return isPublicSeaCustomer(userInfo, authInfo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否有负责人认证信息 |
||||
|
*/ |
||||
|
private boolean hasManagerAuthInfo(String userId) { |
||||
|
try { |
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 检查认证字段是否为空 - 只要有一个认证字段有值,就有负责人信息
|
||||
|
boolean hasAuthInfo = StringUtils.hasText(userManager.getManagerId()) || |
||||
|
StringUtils.hasText(userManager.getManagercompany()) || |
||||
|
StringUtils.hasText(userManager.getManagerdepartment()) || |
||||
|
StringUtils.hasText(userManager.getOrganization()) || |
||||
|
StringUtils.hasText(userManager.getRole()) || |
||||
|
StringUtils.hasText(userManager.getUserName()) || |
||||
|
StringUtils.hasText(userManager.getAssistant()); |
||||
|
|
||||
|
System.out.println("📋 负责人认证信息检查结果: " + (hasAuthInfo ? "有认证信息" : "无认证信息")); |
||||
|
return hasAuthInfo; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查负责人认证信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否同一组织 |
||||
|
*/ |
||||
|
private boolean hasSameOrganization(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
boolean sameOrganization = StringUtils.hasText(userManager.getOrganization()) && |
||||
|
userManager.getOrganization().equals(authInfo.getOrganization()); |
||||
|
|
||||
|
System.out.println("🏢 组织匹配检查: " + userManager.getOrganization() + " vs " + authInfo.getOrganization() + " → " + sameOrganization); |
||||
|
return sameOrganization; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查组织信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否同一部门 |
||||
|
*/ |
||||
|
private boolean hasSameDepartment(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager == null) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
boolean sameDepartment = StringUtils.hasText(userManager.getManagerdepartment()) && |
||||
|
userManager.getManagerdepartment().equals(authInfo.getManagerdepartment()); |
||||
|
|
||||
|
System.out.println("🏢 部门匹配检查: " + userManager.getManagerdepartment() + " vs " + authInfo.getManagerdepartment() + " → " + sameDepartment); |
||||
|
return sameDepartment; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查部门信息失败: " + e.getMessage()); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查用户负责人权限 - 优化版本,数据库层面直接匹配 |
||||
|
*/ |
||||
|
private boolean hasUserManagerPermission(String userId, ManagerAuthInfo authInfo) { |
||||
|
try { |
||||
|
System.out.println("🔐 检查用户负责人权限,用户ID: " + userId); |
||||
|
|
||||
|
// 🔥 优化:直接在数据库层面查询匹配的负责人记录,避免内存比较
|
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserIdAndAuthInfo(userId, authInfo); |
||||
|
|
||||
|
// 🔥 优化:如果没有找到匹配的负责人记录,检查是否为公海池客户
|
||||
|
if (userManager == null) { |
||||
|
System.out.println("🔍 未找到匹配的负责人记录,检查客户等级..."); |
||||
|
|
||||
|
// 获取用户信息检查等级
|
||||
|
UserProductCartDTO userInfo = supplyusersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo != null) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
boolean isPublicSea = publicSeaLevels.contains(userInfo.getLevel()); |
||||
|
|
||||
|
if (isPublicSea) { |
||||
|
System.out.println("✅ 公海池客户,允许查看"); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("❌ 非公海池客户且无匹配负责人,拒绝访问"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 🔥 优化:数据库已经完成匹配,直接返回true
|
||||
|
System.out.println("✅ 找到匹配的负责人记录,允许查看"); |
||||
|
System.out.println("📝 负责人信息: " + |
||||
|
"公司=" + userManager.getManagercompany() + |
||||
|
", 部门=" + userManager.getManagerdepartment() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 负责人=" + userManager.getUserName()); |
||||
|
|
||||
|
return true; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 检查用户负责人权限失败: " + e.getMessage()); |
||||
|
// 发生异常时,出于安全考虑返回false
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查负责人信息是否匹配(UsersManagements) |
||||
|
*/ |
||||
|
private boolean isManagerMatch(UsersManagements userManager, ManagerAuthInfo authInfo) { |
||||
|
boolean match = |
||||
|
(authInfo.getManagerId() == null || authInfo.getManagerId().equals(userManager.getManagerId())) && |
||||
|
(authInfo.getManagercompany() == null || authInfo.getManagercompany().equals(userManager.getManagercompany())) && |
||||
|
(authInfo.getManagerdepartment() == null || authInfo.getManagerdepartment().equals(userManager.getManagerdepartment())) && |
||||
|
(authInfo.getOrganization() == null || authInfo.getOrganization().equals(userManager.getOrganization())) && |
||||
|
(authInfo.getRole() == null || authInfo.getRole().equals(userManager.getRole())) && |
||||
|
(authInfo.getUserName() == null || authInfo.getUserName().equals(userManager.getUserName())); |
||||
|
|
||||
|
System.out.println("🔐 用户负责人权限检查: " + (match ? "✅ 匹配" : "❌ 不匹配")); |
||||
|
return match; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取公海池客户完整信息 - 支持一对多(采购端版本) |
||||
|
*/ |
||||
|
public UserProductCartDTO getPublicSeaCustomerInfo(String userId) { |
||||
|
if (!StringUtils.hasText(userId)) { |
||||
|
System.out.println("⚠️ 用户ID为空"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 1. 获取用户基本信息
|
||||
|
UserProductCartDTO userInfo = supplyusersMapper.getUserBasicInfo(userId); |
||||
|
if (userInfo == null) { |
||||
|
System.out.println("⚠️ 用户不存在: " + userId); |
||||
|
return null; // 返回null而不是抛出异常
|
||||
|
} |
||||
|
|
||||
|
// 采购端权限校验
|
||||
|
if (!"seller".equals(userInfo.getType()) && !"both".equals(userInfo.getType())) { |
||||
|
System.out.println("🚫 过滤掉非供应端客户: " + userId + " (类型: " + userInfo.getType() + ")"); |
||||
|
return null; // 返回null而不是抛出异常
|
||||
|
} |
||||
|
// 🔥 新增:查询负责人信息
|
||||
|
try { |
||||
|
UsersManagements userManager = supplyUsersManagementsMapper.findByUserId(userId); |
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 获取到负责人信息: " + |
||||
|
"负责人=" + userManager.getUserName() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 部门=" + userManager.getManagerdepartment()); |
||||
|
|
||||
|
// 将负责人信息设置到DTO中(需要扩展UserProductCartDTO或使用其他方式)
|
||||
|
// 这里可以创建一个新的字段来存储负责人信息,或者使用现有的扩展机制
|
||||
|
// 暂时记录日志,后续需要DTO支持负责人字段
|
||||
|
} else { |
||||
|
System.out.println("⚠️ 未找到负责人信息"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
// 2. 获取联系人信息 - 一对多
|
||||
|
try { |
||||
|
List<SupplyUsersMapper.ContactInfo> contacts = supplyusersMapper.getUserAllContacts(userId); |
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setUsersContacts(userContacts); |
||||
|
} else { |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取用户联系人信息失败: " + e.getMessage()); |
||||
|
userInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 3. 采购端:获取产品信息(公海需求)- 一对多
|
||||
|
try { |
||||
|
List<SupplyUsersMapper.ProductInfo> products = supplyusersMapper.getUserAllProducts(userId); |
||||
|
System.out.println("🔍 查询到的产品数据条数: " + (products != null ? products.size() : 0)); |
||||
|
|
||||
|
if (products != null && !products.isEmpty()) { |
||||
|
List<UserProductCartDTO.ProductInfo> userProducts = products.stream() |
||||
|
.map(item -> { |
||||
|
UserProductCartDTO.ProductInfo product = new UserProductCartDTO.ProductInfo(); |
||||
|
product.setProductId(item.getProductId()); |
||||
|
product.setProductName(item.getProductName()); |
||||
|
product.setVariety(item.getVariety()); |
||||
|
product.setSpecification(item.getSpecification()); |
||||
|
product.setQuantity(item.getQuantity()); |
||||
|
product.setGrossWeight(item.getGrossWeight()); |
||||
|
product.setYolk(item.getYolk()); |
||||
|
|
||||
|
// 调试日志
|
||||
|
System.out.println("📦 转换产品项: " + |
||||
|
"ID=" + product.getProductId() + |
||||
|
", 产品=" + product.getProductName() + |
||||
|
", 规格=" + product.getSpecification()); |
||||
|
|
||||
|
return product; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
userInfo.setProducts(userProducts); |
||||
|
System.out.println("✅ 成功设置产品数据,数量: " + userProducts.size()); |
||||
|
} else { |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
System.out.println("⚠️ 产品数据为空"); |
||||
|
} |
||||
|
userInfo.setCartItems(Collections.emptyList()); // 采购端不使用购物车信息
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取产品信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
userInfo.setProducts(Collections.emptyList()); |
||||
|
userInfo.setCartItems(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 最终调试信息
|
||||
|
System.out.println("🎯 最终返回的用户数据: " + |
||||
|
"products数量=" + (userInfo.getProducts() != null ? userInfo.getProducts().size() : "null") + |
||||
|
", contacts数量=" + (userInfo.getUsersContacts() != null ? userInfo.getUsersContacts().size() : "null")); |
||||
|
|
||||
|
return userInfo; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取所有客户信息 - 不进行负责人过滤,直接返回所有数据(采购端版本 - 优化版) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO> getAllCustomersWithoutFilter() { |
||||
|
try { |
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🚀 开始获取所有微信用户数据(无过滤,采购端)..."); |
||||
|
|
||||
|
// 1. 获取所有用户的基本信息(采购端:只获取seller和both类型)
|
||||
|
System.out.println("📋 查询用户基础信息..."); |
||||
|
List<UserProductCartDTO> allUsers = supplyusersMapper.getAllUserBasicInfo(); |
||||
|
|
||||
|
System.out.println("✅ 基础用户数据查询完成"); |
||||
|
System.out.println("📊 获取到基础用户数据条数: " + (allUsers != null ? allUsers.size() : "null")); |
||||
|
|
||||
|
List<UserProductCartDTO> result = new ArrayList<>(); |
||||
|
|
||||
|
if (allUsers != null && !allUsers.isEmpty()) { |
||||
|
// 🔥 修改:收集所有用户ID用于批量查询
|
||||
|
List<String> userIds = allUsers.stream() |
||||
|
.map(UserProductCartDTO::getUserId) |
||||
|
.filter(Objects::nonNull) |
||||
|
.filter(userId -> !userId.trim().isEmpty()) |
||||
|
.distinct() |
||||
|
.collect(Collectors.toList()); |
||||
|
|
||||
|
System.out.println("🔍 需要批量查询的用户数量: " + userIds.size()); |
||||
|
|
||||
|
// 🔥 修改:批量查询所有相关数据(采购端需要产品信息)
|
||||
|
Map<String, UsersManagements> managerMap = batchQueryManagers(userIds); |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = batchQueryContacts(userIds); |
||||
|
Map<String, List<UserProductCartDTO.ProductInfo>> productsMap = batchQueryProducts(userIds); // 采购端需要产品信息
|
||||
|
|
||||
|
// 2. 为每个用户构建完整信息
|
||||
|
System.out.println("🔄 开始处理 " + allUsers.size() + " 条用户数据..."); |
||||
|
|
||||
|
for (int i = 0; i < allUsers.size(); i++) { |
||||
|
UserProductCartDTO user = allUsers.get(i); |
||||
|
try { |
||||
|
// 采购端权限:只处理seller和both类型
|
||||
|
if (!"seller".equals(user.getType()) && !"both".equals(user.getType())) { |
||||
|
System.out.println("🚫 过滤掉非供应端客户: " + user.getUserId() + " (类型: " + user.getType() + ")"); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 🔥 修改:使用批量查询的数据构建完整用户信息(采购端版本)
|
||||
|
UserProductCartDTO fullUserInfo = buildSupplyUserInfoFromBatchData(user, managerMap, contactsMap, productsMap); |
||||
|
if (fullUserInfo != null) { |
||||
|
result.add(fullUserInfo); |
||||
|
// 打印前几个客户的详细信息
|
||||
|
if (i < 3) { |
||||
|
System.out.println("📝 采购端客户样例 " + (i + 1) + ": " + |
||||
|
"ID=" + fullUserInfo.getUserId() + |
||||
|
", 手机=" + fullUserInfo.getPhoneNumber() + |
||||
|
", 公司=" + fullUserInfo.getCompany() + |
||||
|
", 类型=" + fullUserInfo.getType() + |
||||
|
", 联系人数量=" + (fullUserInfo.getUsersContacts() != null ? fullUserInfo.getUsersContacts().size() : 0) + |
||||
|
", 产品数量=" + (fullUserInfo.getProducts() != null ? fullUserInfo.getProducts().size() : 0)); |
||||
|
} |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 构建用户 " + user.getUserId() + " 的详细信息时出错: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("===================================================="); |
||||
|
System.out.println("🎉 数据获取完成(无过滤,采购端)"); |
||||
|
System.out.println("📊 返回记录数: " + result.size()); |
||||
|
System.out.println("===================================================="); |
||||
|
|
||||
|
return result; |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 获取所有客户信息失败: " + e.getMessage()); |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 1.批量查询负责人信息(与销售端复用) |
||||
|
*/ |
||||
|
private Map<String, UsersManagements> batchQueryManagers(List<String> userIds) { |
||||
|
Map<String, UsersManagements> managerMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
// 🔥 注意:采购端可能需要使用不同的Mapper
|
||||
|
List<UsersManagements> allManagers = supplyUsersManagementsMapper.findByUserIds(userIds); |
||||
|
for (UsersManagements manager : allManagers) { |
||||
|
if (manager.getUserId() != null) { |
||||
|
managerMap.put(manager.getUserId(), manager); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 采购端批量查询负责人信息完成,共获取 " + allManagers.size() + " 条记录"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 采购端批量查询负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return managerMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 2.批量查询联系人信息(与销售端复用) |
||||
|
*/ |
||||
|
private Map<String, List<UsersMapper.ContactInfo>> batchQueryContacts(List<String> userIds) { |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
// 🔥 注意:采购端需要使用采购端的Mapper
|
||||
|
List<UsersMapper.ContactInfo> allContacts = supplyusersMapper.getUserContactsByUserIds(userIds); |
||||
|
for (UsersMapper.ContactInfo contact : allContacts) { |
||||
|
String userId = contact.getUserId(); |
||||
|
if (userId != null) { |
||||
|
contactsMap.computeIfAbsent(userId, k -> new ArrayList<>()).add(contact); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 采购端批量查询联系人信息完成,共获取 " + allContacts.size() + " 条记录"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 采购端批量查询联系人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return contactsMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 3.批量查询产品信息(采购端专用) |
||||
|
*/ |
||||
|
private Map<String, List<UserProductCartDTO.ProductInfo>> batchQueryProducts(List<String> userIds) { |
||||
|
Map<String, List<UserProductCartDTO.ProductInfo>> productsMap = new HashMap<>(); |
||||
|
if (userIds != null && !userIds.isEmpty()) { |
||||
|
try { |
||||
|
List<UserProductCartDTO.ProductInfo> allProducts = supplyusersMapper.getSellerProductsByUserIds(userIds); |
||||
|
for (UserProductCartDTO.ProductInfo product : allProducts) { |
||||
|
String userId = product.getSellerId(); |
||||
|
if (userId != null) { |
||||
|
productsMap.computeIfAbsent(userId, k -> new ArrayList<>()).add(product); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("✅ 批量查询产品信息完成,共获取 " + allProducts.size() + " 条记录"); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 批量查询产品信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
return productsMap; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 4.从批量查询的数据构建采购端用户完整信息(采购端专用) |
||||
|
*/ |
||||
|
private UserProductCartDTO buildSupplyUserInfoFromBatchData(UserProductCartDTO basicUserInfo, |
||||
|
Map<String, UsersManagements> managerMap, |
||||
|
Map<String, List<UsersMapper.ContactInfo>> contactsMap, |
||||
|
Map<String, List<UserProductCartDTO.ProductInfo>> productsMap) { |
||||
|
String userId = basicUserInfo.getUserId(); |
||||
|
|
||||
|
// 采购端权限校验
|
||||
|
if (!"seller".equals(basicUserInfo.getType()) && !"both".equals(basicUserInfo.getType())) { |
||||
|
System.out.println("🚫 过滤掉非供应端客户: " + userId + " (类型: " + basicUserInfo.getType() + ")"); |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
// 设置负责人信息
|
||||
|
try { |
||||
|
UsersManagements userManager = managerMap.get(userId); |
||||
|
if (userManager != null) { |
||||
|
System.out.println("✅ 从批量Map中获取到负责人信息: " + |
||||
|
"负责人=" + userManager.getUserName() + |
||||
|
", 组织=" + userManager.getOrganization() + |
||||
|
", 部门=" + userManager.getManagerdepartment()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 从Map获取负责人信息失败: " + e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 设置联系人信息
|
||||
|
try { |
||||
|
List<UsersMapper.ContactInfo> contacts = contactsMap.get(userId); |
||||
|
if (contacts != null && !contacts.isEmpty()) { |
||||
|
List<UserProductCartDTO.UsersContacts> userContacts = contacts.stream() |
||||
|
.map(contact -> { |
||||
|
UserProductCartDTO.UsersContacts userContact = new UserProductCartDTO.UsersContacts( |
||||
|
contact.getWechat(), |
||||
|
contact.getAccount(), |
||||
|
contact.getAccountNumber(), |
||||
|
contact.getBank(), |
||||
|
contact.getAddress() |
||||
|
); |
||||
|
userContact.setContactId(contact.getContactId()); |
||||
|
return userContact; |
||||
|
}) |
||||
|
.collect(Collectors.toList()); |
||||
|
basicUserInfo.setUsersContacts(userContacts); |
||||
|
} else { |
||||
|
basicUserInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 设置联系人信息失败: " + e.getMessage()); |
||||
|
basicUserInfo.setUsersContacts(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
// 设置产品信息(采购端关键)
|
||||
|
try { |
||||
|
List<UserProductCartDTO.ProductInfo> products = productsMap.get(userId); |
||||
|
if (products != null && !products.isEmpty()) { |
||||
|
basicUserInfo.setProducts(products); |
||||
|
} else { |
||||
|
basicUserInfo.setProducts(Collections.emptyList()); |
||||
|
} |
||||
|
basicUserInfo.setCartItems(Collections.emptyList()); // 采购端不使用购物车信息
|
||||
|
} catch (Exception e) { |
||||
|
System.err.println("❌ 设置产品信息失败: " + e.getMessage()); |
||||
|
basicUserInfo.setProducts(Collections.emptyList()); |
||||
|
basicUserInfo.setCartItems(Collections.emptyList()); |
||||
|
} |
||||
|
|
||||
|
return basicUserInfo; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 只检查等级是否为公海池等级(不检查负责人信息) |
||||
|
*/ |
||||
|
private boolean isPublicSeaLevel(String level) { |
||||
|
// 定义公海池等级
|
||||
|
Set<String> publicSeaLevels = Set.of("company-sea-pools", "organization-sea-pools", "department-sea-pools", "公海池"); |
||||
|
|
||||
|
boolean isPublicSeaLevel = publicSeaLevels.contains(level); |
||||
|
System.out.println("🔍 等级检查: " + level + " → 是否公海池等级: " + isPublicSeaLevel); |
||||
|
|
||||
|
return isPublicSeaLevel; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 采购端:获取客户的产品信息(公海需求) |
||||
|
*/ |
||||
|
public List<UserProductCartDTO.ProductInfo> getCustomerProducts(String phoneNumber) { |
||||
|
try { |
||||
|
UserProductCartDTO user = supplyusersMapper.selectByPhone(phoneNumber); |
||||
|
if (user != null && ("seller".equals(user.getType()) || "both".equals(user.getType()))) { |
||||
|
return supplyusersMapper.getSellerProducts(user.getUserId()); |
||||
|
} |
||||
|
return new ArrayList<>(); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return new ArrayList<>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
@Service |
||||
|
public class SupplyUserService { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
package com.example.web.service; |
||||
|
|
||||
|
import com.example.web.dto.UserProductCartDTO; |
||||
|
import com.example.web.mapper.UsersMapper; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Service |
||||
|
public class UserService { |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
spring: |
||||
|
datasource: |
||||
|
# userlogin数据库 |
||||
|
primary: |
||||
|
jdbc-url: jdbc:mysql://1.95.162.61:3306/userlogin?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true |
||||
|
username: root |
||||
|
password: schl@2025 |
||||
|
driver-class-name: com.mysql.cj.jdbc.Driver |
||||
|
# wechat_app数据库 |
||||
|
wechat: |
||||
|
jdbc-url: jdbc:mysql://1.95.162.61:3306/wechat_app?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true |
||||
|
username: root |
||||
|
password: schl@2025 |
||||
|
driver-class-name: com.mysql.cj.jdbc.Driver |
||||
|
|
||||
|
# 应用配置 |
||||
|
app: |
||||
|
recycle: |
||||
|
# 未分级客户回流到组织公海池的天数阈值 |
||||
|
unclassified-to-organization-days: 30 |
||||
|
# 组织公海池客户回流到部门公海池的天数阈值 |
||||
|
organization-to-department-days: 30 |
||||
|
|
||||
|
server: |
||||
|
servlet: |
||||
|
context-path: /DL |
||||
|
# 在Tomcat中部署时,端口由Tomcat配置决定,这里不需要指定 |
||||
|
# address属性在Tomcat部署中不生效,由容器控制 |
||||
|
|
||||
|
mybatis: |
||||
|
type-aliases-package: com.example.web.entity |
||||
|
mapper-locations: classpath:mapper/*.xml |
||||
|
configuration: |
||||
|
# 确保这些配置存在 |
||||
|
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
||||
|
call-setters-on-nulls: true |
||||
|
jdbc-type-for-null: null |
||||
|
|
||||
|
logging: |
||||
|
level: |
||||
|
com.example.web.mapper: DEBUG |
||||
|
com.example.web.config: DEBUG |
||||
|
com.example.web.aspect: DEBUG |
||||
|
|
||||
@ -0,0 +1,21 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.Cart_itemsMapper"> |
||||
|
|
||||
|
<resultMap id="cart_timeMap" type="com.example.web.entity.Cart_items"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="selected" property="selected"/> |
||||
|
<result column="added_at" property="added_at"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,63 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.ContactsMapper"> |
||||
|
|
||||
|
<resultMap id="contactsMap" type="com.example.web.entity.Contacts"> |
||||
|
<id column="contact_id" property="contact_id"/> |
||||
|
<result column="id" property="id"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="wechat" property="wechat"/> |
||||
|
<result column="account" property="account"/> |
||||
|
<result column="accountNumber" property="accountNumber"/> |
||||
|
<result column="bank" property="bank"/> |
||||
|
<result column="address" property="address"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 根据企业ID查询联系人信息 --> |
||||
|
<select id="selectContactsByEnterpriseId" parameterType="String" resultMap="contactsMap"> |
||||
|
SELECT * FROM contacts WHERE id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有联系人信息 --> |
||||
|
<select id="selectAllContacts" resultMap="contactsMap"> |
||||
|
SELECT * FROM contacts ORDER BY nickName |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertContacts" parameterType="com.example.web.entity.Contacts"> |
||||
|
INSERT INTO contacts ( |
||||
|
contact_id, |
||||
|
id, nickName, phoneNumber, wechat, account, accountNumber, bank, address,created_at,updated_at |
||||
|
) VALUES ( |
||||
|
#{contact_id}, |
||||
|
#{id}, #{nickName}, #{phoneNumber}, #{wechat}, #{account}, #{accountNumber}, #{bank}, #{address}, #{created_at}, #{updated_at} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 新增:根据电话号码查询记录数(用于判断是否重复) --> |
||||
|
<select id="countByPhoneNumber" parameterType="String" resultType="int"> |
||||
|
SELECT COUNT(*) FROM contacts WHERE phoneNumber = #{phoneNumber} |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectByPhoneNumber" parameterType="String" resultType="com.example.web.entity.Contacts"> |
||||
|
SELECT * FROM contacts WHERE phoneNumber = #{phoneNumber} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 修复更新语句 --> |
||||
|
<update id="updateContacts" parameterType="com.example.web.entity.Contacts"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
id = #{id}, |
||||
|
nickName = #{nickName}, |
||||
|
wechat = #{wechat}, |
||||
|
account = #{account}, |
||||
|
accountNumber = #{accountNumber}, |
||||
|
bank = #{bank}, |
||||
|
address = #{address} |
||||
|
WHERE contact_id = #{contact_id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,79 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.EnterpriseMapper"> |
||||
|
|
||||
|
<resultMap id="enterpriseMap" type="com.example.web.entity.Enterprise"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="company" property="company"/> |
||||
|
<result column="region" property="region"/> |
||||
|
<result column="level" property="level"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="demand" property="demand"/> |
||||
|
<result column="spec" property="spec"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<resultMap id="enterpriseInfoDTOMap" type="com.example.web.dto.EnterpriseInfoDTO"> |
||||
|
<association property="enterprise" resultMap="enterpriseMap"/> |
||||
|
<association property="contacts" resultMap="com.example.web.mapper.ContactsMapper.contactsMap"/> |
||||
|
<association property="managers" resultMap="com.example.web.mapper.ManagersMapper.managersMap"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 查询所有企业及其联系人和负责人信息(销售端:只查询buyer和both类型) --> |
||||
|
<select id="selectAllEnterpriseInfo" resultMap="enterpriseInfoDTOMap"> |
||||
|
SELECT |
||||
|
e.*, |
||||
|
c.contact_id, c.nickName, c.phoneNumber, c.wechat, c.account, c.accountNumber, c.bank, c.address, |
||||
|
c.created_at, c.updated_at, |
||||
|
m.manager_id, m.managerId, m.managercompany, m.managerdepartment, m.organization, m.role, m.root, |
||||
|
m.created_at as manager_created_at, m.updated_at as manager_updated_at, m.userName, m.assistant |
||||
|
FROM enterprise e |
||||
|
LEFT JOIN contacts c ON e.id = c.id |
||||
|
LEFT JOIN managers m ON e.id = m.id |
||||
|
WHERE e.type IN ('buyer', 'both') <!-- 销售端:只查询buyer和both类型 --> |
||||
|
ORDER BY e.company |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据企业ID查询详细信息 --> |
||||
|
<select id="selectEnterpriseInfoById" parameterType="String" resultMap="enterpriseInfoDTOMap"> |
||||
|
SELECT |
||||
|
e.*, |
||||
|
c.contact_id, c.nickName, c.phoneNumber, c.wechat, c.account, c.accountNumber, c.bank, c.address, |
||||
|
c.created_at, c.updated_at, |
||||
|
m.manager_id, m.managerId, m.managercompany, m.managerdepartment, m.organization, m.role, m.root, |
||||
|
m.created_at as manager_created_at, m.updated_at as manager_updated_at, m.userName, m.assistant |
||||
|
FROM enterprise e |
||||
|
LEFT JOIN contacts c ON e.id = c.id |
||||
|
LEFT JOIN managers m ON e.id = m.id |
||||
|
WHERE e.id = #{id} |
||||
|
AND e.type IN ('buyer', 'both') <!-- 销售端:只查询buyer和both类型 --> |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有企业基本信息(销售员权限:只查询buyer和both类型) --> |
||||
|
<select id="selectAllEnterprises" resultMap="enterpriseMap"> |
||||
|
SELECT * FROM enterprise |
||||
|
WHERE type IN ('buyer', 'both') <!-- 销售员权限:只查询buyer和both类型 --> |
||||
|
ORDER BY company |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertEnterprise" parameterType="com.example.web.entity.Enterprise"> |
||||
|
INSERT INTO enterprise ( |
||||
|
id, company, region, level, type, demand, spec |
||||
|
) VALUES ( |
||||
|
#{id}, #{company}, #{region}, #{level}, #{type}, #{demand}, #{spec} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<update id="updateEnterprise" parameterType="com.example.web.entity.Enterprise"> |
||||
|
UPDATE enterprise |
||||
|
SET |
||||
|
company = #{company}, |
||||
|
region = #{region}, |
||||
|
level = #{level}, |
||||
|
type = #{type}, |
||||
|
demand = #{demand}, |
||||
|
spec = #{spec} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,34 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.LoginMapper"> |
||||
|
|
||||
|
<resultMap id="LoginResultMap" type="com.example.web.entity.Login"> |
||||
|
<id property="id" column="id"/> |
||||
|
<result property="projectName" column="projectName"/> |
||||
|
<result property="userName" column="userName"/> |
||||
|
<result property="password" column="password"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<select id="findByProjectNameAndUserName" resultMap="LoginResultMap"> |
||||
|
SELECT id, projectName, userName, password |
||||
|
FROM login |
||||
|
WHERE projectName = #{projectName} AND userName = #{userName} |
||||
|
</select> |
||||
|
|
||||
|
<select id="findByConditions" resultMap="LoginResultMap"> |
||||
|
SELECT id, projectName, userName, password |
||||
|
FROM login |
||||
|
<where> |
||||
|
<if test="projectName != null"> |
||||
|
AND projectName = #{projectName} |
||||
|
</if> |
||||
|
<if test="userName != null"> |
||||
|
AND userName = #{userName} |
||||
|
</if> |
||||
|
</where> |
||||
|
ORDER BY id DESC |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,97 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.ManagersMapper"> |
||||
|
<!-- 添加二级缓存 --> |
||||
|
<cache |
||||
|
eviction="LRU" |
||||
|
flushInterval="60000" |
||||
|
size="512" |
||||
|
readOnly="true"/> |
||||
|
|
||||
|
<resultMap id="managersMap" type="com.example.web.entity.Managers"> |
||||
|
<id column="manager_id" property="manager_id"/> |
||||
|
<result column="id" property="id"/> |
||||
|
<result column="managerId" property="managerId"/> |
||||
|
<result column="managercompany" property="managercompany"/> |
||||
|
<result column="managerdepartment" property="managerdepartment"/> |
||||
|
<result column="organization" property="organization"/> |
||||
|
<result column="role" property="role"/> |
||||
|
<result column="root" property="root"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result column="userName" property="userName"/> |
||||
|
<result column="assistant" property="assistant"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 在 ManagersMapper.xml 中添加 --> |
||||
|
<select id="selectByUserNameAndManagerId" parameterType="map" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
WHERE userName = #{userName} AND managerId = #{managerId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据企业ID查询负责人信息 --> |
||||
|
<select id="selectManagersByEnterpriseId" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有负责人信息 --> |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
|
||||
|
<!-- 分页查询负责人信息 --> |
||||
|
<select id="selectAllManagersWithPagination" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
ORDER BY userName |
||||
|
LIMIT #{limit} OFFSET #{offset} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取负责人总数 --> |
||||
|
<select id="getManagersCount" resultType="int"> |
||||
|
SELECT COUNT(*) FROM managers |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据负责人姓名查询 --> |
||||
|
<select id="selectByUserName" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE userName = #{userName} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 插入负责人信息 --> |
||||
|
<insert id="insertManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
INSERT INTO managers ( |
||||
|
id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, |
||||
|
userName, assistant |
||||
|
) VALUES ( |
||||
|
#{id}, #{managerId}, #{managercompany}, #{managerdepartment}, |
||||
|
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at}, |
||||
|
#{userName}, #{assistant} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 更新负责人信息 --> |
||||
|
<update id="updateManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
UPDATE managers |
||||
|
SET |
||||
|
managercompany = #{managercompany}, |
||||
|
managerdepartment = #{managerdepartment}, |
||||
|
organization = #{organization}, |
||||
|
role = #{role}, |
||||
|
userName = #{userName}, |
||||
|
assistant = #{assistant}, |
||||
|
updated_at = #{updated_at} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,26 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.ProductsMapper"> |
||||
|
|
||||
|
<resultMap id="productsMap" type="com.example.web.entity.Products"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="sellerId" property="sellerId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="variety" property="variety"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="status" property="status"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="rejectReason" property="rejectReason"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
|
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,42 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.RootdbMapper"> |
||||
|
|
||||
|
<resultMap id="RootdbResultMap" type="com.example.web.entity.Rootdb"> |
||||
|
<result property="root" column="root"/> |
||||
|
<result property="projectName" column="projectName"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<select id="findByProjectName" resultMap="RootdbResultMap"> |
||||
|
SELECT root, projectName |
||||
|
FROM rootdb |
||||
|
WHERE projectName = #{projectName} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:获取所有权限信息 --> |
||||
|
<select id="findAll" resultMap="RootdbResultMap"> |
||||
|
SELECT root, projectName |
||||
|
FROM rootdb |
||||
|
ORDER BY root ASC |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:根据权限等级查询 --> |
||||
|
<select id="findByRootLevel" parameterType="int" resultMap="RootdbResultMap"> |
||||
|
SELECT root, projectName |
||||
|
FROM rootdb |
||||
|
WHERE root = #{root} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:批量查询权限信息 --> |
||||
|
<select id="findByProjectNames" parameterType="list" resultMap="RootdbResultMap"> |
||||
|
SELECT root, projectName |
||||
|
FROM rootdb |
||||
|
WHERE projectName IN |
||||
|
<foreach collection="projectNames" item="projectName" open="(" separator="," close=")"> |
||||
|
#{projectName} |
||||
|
</foreach> |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,21 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyCart_itemsMapper"> |
||||
|
|
||||
|
<resultMap id="cart_timeMap" type="com.example.web.entity.Cart_items"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="selected" property="selected"/> |
||||
|
<result column="added_at" property="added_at"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,63 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyContactsMapper"> |
||||
|
|
||||
|
<resultMap id="contactsMap" type="com.example.web.entity.Contacts"> |
||||
|
<id column="contact_id" property="contact_id"/> |
||||
|
<result column="id" property="id"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="wechat" property="wechat"/> |
||||
|
<result column="account" property="account"/> |
||||
|
<result column="accountNumber" property="accountNumber"/> |
||||
|
<result column="bank" property="bank"/> |
||||
|
<result column="address" property="address"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 根据企业ID查询联系人信息 --> |
||||
|
<select id="selectContactsByEnterpriseId" parameterType="String" resultMap="contactsMap"> |
||||
|
SELECT * FROM contacts WHERE id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有联系人信息 --> |
||||
|
<select id="selectAllContacts" resultMap="contactsMap"> |
||||
|
SELECT * FROM contacts ORDER BY nickName |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertContacts" parameterType="com.example.web.entity.Contacts"> |
||||
|
INSERT INTO contacts ( |
||||
|
contact_id, |
||||
|
id, nickName, phoneNumber, wechat, account, accountNumber, bank, address,created_at,updated_at |
||||
|
) VALUES ( |
||||
|
#{contact_id}, |
||||
|
#{id}, #{nickName}, #{phoneNumber}, #{wechat}, #{account}, #{accountNumber}, #{bank}, #{address}, #{created_at}, #{updated_at} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 新增:查询指定电话号码的记录数 --> |
||||
|
<select id="countByPhoneNumber" parameterType="String" resultType="int"> |
||||
|
SELECT COUNT(*) FROM contacts WHERE phoneNumber = #{phoneNumber} |
||||
|
</select> |
||||
|
|
||||
|
<select id="selectByPhoneNumber" parameterType="String" resultType="com.example.web.entity.Contacts"> |
||||
|
SELECT * FROM contacts WHERE phoneNumber = #{phoneNumber} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 修复:移除注释中的SQL语句,避免解析问题 --> |
||||
|
<update id="updateContacts" parameterType="com.example.web.entity.Contacts"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
id = #{id}, |
||||
|
nickName = #{nickName}, |
||||
|
wechat = #{wechat}, |
||||
|
account = #{account}, |
||||
|
accountNumber = #{accountNumber}, |
||||
|
bank = #{bank}, |
||||
|
address = #{address} |
||||
|
WHERE contact_id = #{contact_id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,79 @@ |
|||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyEnterpriseMapper"> |
||||
|
|
||||
|
|
||||
|
<resultMap id="enterpriseMap" type="com.example.web.entity.Enterprise"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="company" property="company"/> |
||||
|
<result column="region" property="region"/> |
||||
|
<result column="level" property="level"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="demand" property="demand"/> |
||||
|
<result column="spec" property="spec"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<resultMap id="enterpriseInfoDTOMap" type="com.example.web.dto.EnterpriseInfoDTO"> |
||||
|
<association property="enterprise" resultMap="enterpriseMap"/> |
||||
|
<association property="contacts" resultMap="com.example.web.mapper.ContactsMapper.contactsMap"/> |
||||
|
<association property="managers" resultMap="com.example.web.mapper.ManagersMapper.managersMap"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 查询所有企业及其联系人和负责人信息(销售端:只查询seller和both类型) --> |
||||
|
<select id="selectAllEnterpriseInfo" resultMap="enterpriseInfoDTOMap"> |
||||
|
SELECT |
||||
|
e.*, |
||||
|
c.contact_id, c.nickName, c.phoneNumber, c.wechat, c.account, c.accountNumber, c.bank, c.address, |
||||
|
c.created_at, c.updated_at, |
||||
|
m.manager_id, m.managerId, m.managercompany, m.managerdepartment, m.organization, m.role, m.root, |
||||
|
m.created_at as manager_created_at, m.updated_at as manager_updated_at, m.userName, m.assistant |
||||
|
FROM enterprise e |
||||
|
LEFT JOIN contacts c ON e.id = c.id |
||||
|
LEFT JOIN managers m ON e.id = m.id |
||||
|
WHERE e.type IN ('seller', 'both') <!-- 销售端:只查询seller和both类型 --> |
||||
|
ORDER BY e.company |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据企业ID查询详细信息 --> |
||||
|
<select id="selectEnterpriseInfoById" parameterType="String" resultMap="enterpriseInfoDTOMap"> |
||||
|
SELECT |
||||
|
e.*, |
||||
|
c.contact_id, c.nickName, c.phoneNumber, c.wechat, c.account, c.accountNumber, c.bank, c.address, |
||||
|
c.created_at, c.updated_at, |
||||
|
m.manager_id, m.managerId, m.managercompany, m.managerdepartment, m.organization, m.role, m.root, |
||||
|
m.created_at as manager_created_at, m.updated_at as manager_updated_at, m.userName, m.assistant |
||||
|
FROM enterprise e |
||||
|
LEFT JOIN contacts c ON e.id = c.id |
||||
|
LEFT JOIN managers m ON e.id = m.id |
||||
|
WHERE e.id = #{id} |
||||
|
AND e.type IN ('seller', 'both') <!-- 销售端:只查询seller和both类型 --> |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有企业基本信息(销售员权限:只查询seller和both类型) --> |
||||
|
<select id="selectAllEnterprises" resultMap="enterpriseMap"> |
||||
|
SELECT * FROM enterprise |
||||
|
WHERE type IN ('seller', 'both') <!-- 销售员权限:只查询seller和both类型 --> |
||||
|
ORDER BY company |
||||
|
</select> |
||||
|
|
||||
|
<insert id="insertEnterprise" parameterType="com.example.web.entity.Enterprise"> |
||||
|
INSERT INTO enterprise ( |
||||
|
id, company, region, level, type, demand, spec |
||||
|
) VALUES ( |
||||
|
#{id}, #{company}, #{region}, #{level}, #{type}, #{demand}, #{spec} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<update id="updateEnterprise" parameterType="com.example.web.entity.Enterprise"> |
||||
|
UPDATE enterprise |
||||
|
SET |
||||
|
company = #{company}, |
||||
|
region = #{region}, |
||||
|
level = #{level}, |
||||
|
type = #{type}, |
||||
|
demand = #{demand}, |
||||
|
spec = #{spec} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,79 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyManagersMapper"> |
||||
|
<!-- 添加二级缓存 --> |
||||
|
<cache |
||||
|
eviction="LRU" |
||||
|
flushInterval="60000" |
||||
|
size="512" |
||||
|
readOnly="true"/> |
||||
|
|
||||
|
<resultMap id="managersMap" type="com.example.web.entity.Managers"> |
||||
|
<id column="manager_id" property="manager_id"/> |
||||
|
<result column="id" property="id"/> |
||||
|
<result column="managerId" property="managerId"/> |
||||
|
<result column="managercompany" property="managercompany"/> |
||||
|
<result column="managerdepartment" property="managerdepartment"/> |
||||
|
<result column="organization" property="organization"/> |
||||
|
<result column="role" property="role"/> |
||||
|
<result column="root" property="root"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result column="userName" property="userName"/> |
||||
|
<result column="assistant" property="assistant"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 在 SupplyManagersMapper.xml 中添加 --> |
||||
|
<select id="selectByUserNameAndManagerId" parameterType="map" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers |
||||
|
WHERE userName = #{userName} AND managerId = #{managerId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据企业ID查询负责人信息 --> |
||||
|
<select id="selectManagersByEnterpriseId" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT manager_id, id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, userName, assistant |
||||
|
FROM managers WHERE id = #{id} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询所有负责人信息 --> |
||||
|
<select id="selectAllManagers" resultMap="managersMap"> |
||||
|
SELECT * FROM managers ORDER BY userName |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据负责人姓名查询 --> |
||||
|
<select id="selectByUserName" parameterType="String" resultMap="managersMap"> |
||||
|
SELECT * FROM managers WHERE userName = #{userName} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 插入负责人信息 --> |
||||
|
<insert id="insertManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
INSERT INTO managers ( |
||||
|
id, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, |
||||
|
userName, assistant |
||||
|
) VALUES ( |
||||
|
#{id}, #{managerId}, #{managercompany}, #{managerdepartment}, |
||||
|
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at}, |
||||
|
#{userName}, #{assistant} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 更新负责人信息 --> |
||||
|
<update id="updateManagers" parameterType="com.example.web.entity.Managers"> |
||||
|
UPDATE managers |
||||
|
SET |
||||
|
managercompany = #{managercompany}, |
||||
|
managerdepartment = #{managerdepartment}, |
||||
|
organization = #{organization}, |
||||
|
role = #{role}, |
||||
|
userName = #{userName}, |
||||
|
assistant = #{assistant}, |
||||
|
updated_at = #{updated_at} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
</mapper> |
||||
@ -0,0 +1,26 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyProductsMapper"> |
||||
|
|
||||
|
<resultMap id="productsMap" type="com.example.web.entity.Products"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="sellerId" property="sellerId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="variety" property="variety"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="status" property="status"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="rejectReason" property="rejectReason"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
|
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,136 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyUsersManagementsMapper"> |
||||
|
|
||||
|
<resultMap id="UsersManagementsResultMap" type="com.example.web.entity.UsersManagements"> |
||||
|
<id property="id" column="id"/> |
||||
|
<result property="userId" column="userId"/> |
||||
|
<result property="managerId" column="managerId"/> |
||||
|
<result property="managercompany" column="managercompany"/> |
||||
|
<result property="managerdepartment" column="managerdepartment"/> |
||||
|
<result property="organization" column="organization"/> |
||||
|
<result property="role" column="role"/> |
||||
|
<result property="root" column="root"/> |
||||
|
<result property="created_at" column="created_at"/> |
||||
|
<result property="updated_at" column="updated_at"/> |
||||
|
<result property="userName" column="userName"/> |
||||
|
<result property="assistant" column="assistant"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 在 SupplyUsersManagementsMapper.xml 中添加 --> |
||||
|
<select id="findByUserNameAndManagerId" parameterType="map" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE userName = #{userName} AND managerId = #{managerId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:支持部门查询 --> |
||||
|
<select id="findByDepartment" parameterType="string" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE managerdepartment = #{department} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:组合条件查询 --> |
||||
|
<select id="findByConditions" parameterType="map" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
<where> |
||||
|
<if test="userName != null">AND userName = #{userName}</if> |
||||
|
<if test="department != null">AND managerdepartment = #{department}</if> |
||||
|
<if test="company != null">AND managercompany = #{company}</if> |
||||
|
<if test="role != null">AND role = #{role}</if> |
||||
|
</where> |
||||
|
ORDER BY created_at DESC |
||||
|
</select> |
||||
|
<!-- 根据用户ID查询负责人信息 --> |
||||
|
<select id="findByUserId" parameterType="string" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT * FROM usermanagements |
||||
|
WHERE userId = #{userId} |
||||
|
ORDER BY id DESC |
||||
|
</select> |
||||
|
|
||||
|
<!-- 插入负责人信息 --> |
||||
|
<insert id="insertUsersManagements" parameterType="com.example.web.entity.UsersManagements"> |
||||
|
INSERT INTO usermanagements ( |
||||
|
userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, |
||||
|
userName, assistant |
||||
|
) VALUES ( |
||||
|
#{userId}, #{managerId}, #{managercompany}, #{managerdepartment}, |
||||
|
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at}, |
||||
|
#{userName}, #{assistant} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 更新负责人信息 --> |
||||
|
<update id="updateUsersManagements" parameterType="com.example.web.entity.UsersManagements"> |
||||
|
UPDATE usermanagements |
||||
|
SET managerId = #{managerId}, |
||||
|
managercompany = #{managercompany}, |
||||
|
managerdepartment = #{managerdepartment}, |
||||
|
organization = #{organization}, |
||||
|
role = #{role}, |
||||
|
root = #{root}, |
||||
|
updated_at = #{updated_at}, |
||||
|
userName = #{userName}, |
||||
|
assistant = #{assistant} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新负责人信息的更新时间 --> |
||||
|
<update id="updateManagerUpdateTime"> |
||||
|
UPDATE users_managements |
||||
|
SET updated_at = #{updatedAt} |
||||
|
WHERE user_id = #{userId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 查询完整负责人信息 --> |
||||
|
<select id="findCompleteManagerInfoByUserId" resultType="com.example.web.entity.UsersManagements"> |
||||
|
SELECT |
||||
|
manager_id, |
||||
|
managercompany, |
||||
|
managerdepartment, |
||||
|
organization, |
||||
|
role, |
||||
|
user_name, |
||||
|
assistant, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users_managements |
||||
|
WHERE user_id = #{userId} |
||||
|
</select> |
||||
|
<select id="findByUserIdAndAuthInfo" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT * FROM usermanagements |
||||
|
WHERE userId = #{userId} |
||||
|
AND (managercompany = #{authInfo.managercompany} OR #{authInfo.managercompany} IS NULL) |
||||
|
AND (managerdepartment = #{authInfo.managerdepartment} OR #{authInfo.managerdepartment} IS NULL) |
||||
|
AND (organization = #{authInfo.organization} OR #{authInfo.organization} IS NULL) |
||||
|
AND (userName = #{authInfo.userName} OR #{authInfo.userName} IS NULL) |
||||
|
LIMIT 1 |
||||
|
</select> |
||||
|
|
||||
|
<select id="findAuthorizedUserIds" resultType="string"> |
||||
|
SELECT userId FROM usermanagements |
||||
|
WHERE (managercompany = #{authInfo.managercompany} OR #{authInfo.managercompany} IS NULL) |
||||
|
AND (managerdepartment = #{authInfo.managerdepartment} OR #{authInfo.managerdepartment} IS NULL) |
||||
|
AND (organization = #{authInfo.organization} OR #{authInfo.organization} IS NULL) |
||||
|
AND (userName = #{authInfo.userName} OR #{authInfo.userName} IS NULL) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:批量查询用户负责人信息 --> |
||||
|
<select id="findByUserIds" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,700 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.SupplyUsersMapper"> |
||||
|
|
||||
|
<resultMap id="userMap" type="com.example.web.entity.Users"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="openid" property="openid"/> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="avatarUrl" property="avatarUrl"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="gender" property="gender"/> |
||||
|
<result column="country" property="country"/> |
||||
|
<result column="province" property="province"/> |
||||
|
<result column="city" property="city"/> |
||||
|
<result column="language" property="language"/> |
||||
|
<result column="session_key" property="session_key"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result property="company" column="company"/> |
||||
|
<result property="region" column="region"/> |
||||
|
<result property="level" column="level"/> |
||||
|
<result property="demand" column="demand" jdbcType="VARCHAR"/> |
||||
|
<result property="spec" column="spec" jdbcType="VARCHAR"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 用户基本信息映射 --> |
||||
|
<resultMap id="userBasicInfoMap" type="com.example.web.dto.UserProductCartDTO"> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result property="company" column="company"/> |
||||
|
<result property="region" column="region"/> |
||||
|
<result property="level" column="level"/> |
||||
|
<result property="demand" column="demand" jdbcType="VARCHAR"/> |
||||
|
<result property="spec" column="spec" jdbcType="VARCHAR"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 产品信息映射 --> |
||||
|
<resultMap id="productInfoMap" type="com.example.web.dto.UserProductCartDTO$ProductInfo"> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="variety" property="variety"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="sellerId" property="sellerId"/> |
||||
|
<result column="sellerPhone" property="sellerPhone"/> |
||||
|
<result column="sellerNickName" property="sellerNickName"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 购物车信息映射 --> |
||||
|
<resultMap id="cartItemMap" type="com.example.web.dto.UserProductCartDTO$CartItem"> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="selected" property="selected"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 🚀 新增:采购端获取授权客户列表(数据库层面过滤) --> |
||||
|
<select id="getAuthorizedCustomers" resultMap="userBasicInfoMap" parameterType="map"> |
||||
|
SELECT DISTINCT |
||||
|
u.userId, |
||||
|
u.phoneNumber, |
||||
|
u.type, |
||||
|
u.nickName, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'seller' OR u.type = 'both') <!-- 采购端:关注seller和both类型 --> |
||||
|
AND ( |
||||
|
<!-- 公海池客户权限规则 --> |
||||
|
(u.level IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND ( |
||||
|
<!-- 公司公海池:无负责人信息 --> |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
<!-- 组织公海池:组织匹配 --> |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
<!-- 部门公海池:部门匹配 --> |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
)) |
||||
|
OR |
||||
|
<!-- 非公海池客户:完全匹配负责人信息 --> |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
ORDER BY u.created_at DESC |
||||
|
<if test="limit != null and offset != null"> |
||||
|
LIMIT #{limit} OFFSET #{offset} |
||||
|
</if> |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 新增:采购端获取授权客户总数 --> |
||||
|
<select id="getAuthorizedCustomersCount" resultType="int" parameterType="map"> |
||||
|
SELECT COUNT(DISTINCT u.userId) |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'seller' OR u.type = 'both') <!-- 采购端:关注seller和both类型 --> |
||||
|
AND ( |
||||
|
<!-- 公海池客户权限规则 --> |
||||
|
(u.level IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND ( |
||||
|
<!-- 公司公海池:无负责人信息 --> |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
<!-- 组织公海池:组织匹配 --> |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
<!-- 部门公海池:部门匹配 --> |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
)) |
||||
|
OR |
||||
|
<!-- 非公海池客户:完全匹配负责人信息 --> |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 新增:采购端根据认证信息获取有权限的用户ID列表 --> |
||||
|
<select id="getAuthorizedUserIds" resultType="string" parameterType="map"> |
||||
|
SELECT DISTINCT u.userId |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'seller' OR u.type = 'both') <!-- 采购端:关注seller和both类型 --> |
||||
|
AND ( |
||||
|
<!-- 公海池客户权限规则 --> |
||||
|
(u.level IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND ( |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
)) |
||||
|
OR |
||||
|
<!-- 非公海池客户权限规则 --> |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 新增:采购端根据手机号和权限查询用户 --> |
||||
|
<select id="selectByPhoneWithAuth" parameterType="map" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
u.userId, |
||||
|
u.phoneNumber, |
||||
|
u.type, |
||||
|
u.nickName, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber = #{phoneNumber} |
||||
|
AND (u.type = 'seller' OR u.type = 'both') <!-- 采购端:关注seller和both类型 --> |
||||
|
AND ( |
||||
|
<!-- 公海池客户权限规则 --> |
||||
|
(u.level IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND ( |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
)) |
||||
|
OR |
||||
|
<!-- 非公海池客户权限规则 --> |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
LIMIT 1 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取用户基本信息 --> |
||||
|
<select id="getUserBasicInfo" resultMap="userBasicInfoMap" parameterType="string"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 采购端:获取卖家的产品信息(公海需求) --> |
||||
|
<select id="getSellerProducts" resultMap="productInfoMap" parameterType="string"> |
||||
|
SELECT |
||||
|
productName, |
||||
|
variety, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk, |
||||
|
productId, |
||||
|
price, |
||||
|
sellerId, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM products |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
ORDER BY created_at DESC |
||||
|
LIMIT 10 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🎯 修改:保留原方法,但建议使用新的授权查询 --> |
||||
|
<select id="getAllUserBasicInfo" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE phoneNumber IS NOT NULL |
||||
|
AND phoneNumber != '' |
||||
|
AND (type = 'seller' OR type = 'both') |
||||
|
ORDER BY created_at DESC |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🎯 修改:保留原方法,但建议使用新的授权查询 --> |
||||
|
<select id="selectByPhone" parameterType="string" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE phoneNumber = #{phoneNumber} |
||||
|
AND (type = 'seller' OR type = 'both') |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:根据用户ID精确查询用户 --> |
||||
|
<select id="selectByUserId" parameterType="string" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId = #{userId} |
||||
|
AND (type = 'seller' OR type = 'both') |
||||
|
</select> |
||||
|
|
||||
|
<!-- 采购端:更新公海需求信息 --> |
||||
|
<update id="updateProduct"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
productName = #{product.productName}, |
||||
|
specification = #{product.specification}, |
||||
|
yolk = #{product.yolk}, |
||||
|
quantity = #{product.quantity}, |
||||
|
variety = #{product.variety}, |
||||
|
grossWeight = #{product.grossWeight}, |
||||
|
price = #{product.price}, |
||||
|
updated_at = NOW() |
||||
|
WHERE |
||||
|
sellerId = #{sellerId} |
||||
|
AND productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 根据手机号更新用户信息 --> |
||||
|
<update id="updateByPhone" parameterType="com.example.web.dto.UserProductCartDTO"> |
||||
|
UPDATE users |
||||
|
SET |
||||
|
<if test="nickName != null and nickName != ''"> |
||||
|
nickName = #{nickName}, |
||||
|
</if> |
||||
|
<if test="type != null and type != ''"> |
||||
|
type = #{type}, |
||||
|
</if> |
||||
|
<if test="company != null"> |
||||
|
company = #{company}, |
||||
|
</if> |
||||
|
<if test="region != null"> |
||||
|
region = #{region}, |
||||
|
</if> |
||||
|
<if test="level != null and level != ''"> |
||||
|
level = #{level}, |
||||
|
</if> |
||||
|
<if test="demand != null"> |
||||
|
demand = #{demand}, |
||||
|
</if> |
||||
|
<if test="spec != null"> |
||||
|
spec = #{spec}, |
||||
|
</if> |
||||
|
updated_at = #{updated_at} |
||||
|
WHERE phoneNumber = #{phoneNumber} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 采购端:更新卖家产品信息 --> |
||||
|
<update id="updateProductBySellerId"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
<if test="productName != null and productName != ''"> |
||||
|
productName = #{productName}, |
||||
|
</if> |
||||
|
<if test="variety != null and variety != ''"> |
||||
|
variety = #{variety}, |
||||
|
</if> |
||||
|
<if test="specification != null and specification != ''"> |
||||
|
specification = #{specification}, |
||||
|
</if> |
||||
|
<if test="quantity != null"> |
||||
|
quantity = #{quantity}, |
||||
|
</if> |
||||
|
<if test="grossWeight != null"> |
||||
|
grossWeight = #{grossWeight}, |
||||
|
</if> |
||||
|
<if test="yolk != null and yolk != ''"> |
||||
|
yolk = #{yolk}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 采购端:更新或插入产品信息 --> |
||||
|
<update id="updateOrInsertProduct"> |
||||
|
INSERT INTO products ( |
||||
|
productId, |
||||
|
sellerId, |
||||
|
productName, |
||||
|
variety, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk, |
||||
|
price, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
) VALUES ( |
||||
|
COALESCE(#{productId}, UUID()), |
||||
|
#{sellerId}, |
||||
|
#{productName}, |
||||
|
#{variety}, |
||||
|
#{specification}, |
||||
|
#{quantity}, |
||||
|
#{grossWeight}, |
||||
|
#{yolk}, |
||||
|
#{price}, |
||||
|
NOW(), |
||||
|
NOW() |
||||
|
) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
productName = VALUES(productName), |
||||
|
variety = VALUES(variety), |
||||
|
specification = VALUES(specification), |
||||
|
quantity = VALUES(quantity), |
||||
|
grossWeight = VALUES(grossWeight), |
||||
|
yolk = VALUES(yolk), |
||||
|
price = VALUES(price), |
||||
|
updated_at = NOW() |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取用户联系人信息 --> |
||||
|
<select id="getUserContacts" resultType="com.example.web.dto.UserProductCartDTO$UsersContacts"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 更新用户联系人信息 --> |
||||
|
<update id="updateContactsByUserId"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
<if test="wechat != null and wechat != ''"> |
||||
|
wechat = #{wechat}, |
||||
|
</if> |
||||
|
<if test="account != null and account != ''"> |
||||
|
account = #{account}, |
||||
|
</if> |
||||
|
<if test="accountNumber != null and accountNumber != ''"> |
||||
|
accountNumber = #{accountNumber}, |
||||
|
</if> |
||||
|
<if test="bank != null and bank != ''"> |
||||
|
bank = #{bank}, |
||||
|
</if> |
||||
|
<if test="address != null and address != ''"> |
||||
|
address = #{address}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE userId = #{userId} |
||||
|
LIMIT 1 |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新或插入联系人信息 --> |
||||
|
<update id="updateOrInsertContact"> |
||||
|
INSERT INTO contacts (id, userId, wechat, account, accountNumber, bank, address, updated_at) |
||||
|
VALUES ( |
||||
|
COALESCE(#{contactId}, UUID()), |
||||
|
#{userId}, |
||||
|
#{wechat}, |
||||
|
#{account}, |
||||
|
#{accountNumber}, |
||||
|
#{bank}, |
||||
|
#{address}, |
||||
|
NOW() |
||||
|
) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
wechat = VALUES(wechat), |
||||
|
account = VALUES(account), |
||||
|
accountNumber = VALUES(accountNumber), |
||||
|
bank = VALUES(bank), |
||||
|
address = VALUES(address), |
||||
|
updated_at = NOW() |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新特定联系人信息 --> |
||||
|
<update id="updateSpecificContact"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
<if test="wechat != null"> |
||||
|
wechat = #{wechat}, |
||||
|
</if> |
||||
|
<if test="account != null"> |
||||
|
account = #{account}, |
||||
|
</if> |
||||
|
<if test="accountNumber != null"> |
||||
|
accountNumber = #{accountNumber}, |
||||
|
</if> |
||||
|
<if test="bank != null"> |
||||
|
bank = #{bank}, |
||||
|
</if> |
||||
|
<if test="address != null"> |
||||
|
address = #{address}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE userId = #{userId} |
||||
|
AND id = #{contactId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 采购端:更新特定产品信息 --> |
||||
|
<update id="updateSpecificProduct"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
<if test="productName != null"> |
||||
|
productName = #{productName}, |
||||
|
</if> |
||||
|
<if test="variety != null"> |
||||
|
variety = #{variety}, |
||||
|
</if> |
||||
|
<if test="specification != null"> |
||||
|
specification = #{specification}, |
||||
|
</if> |
||||
|
<if test="quantity != null"> |
||||
|
quantity = #{quantity}, |
||||
|
</if> |
||||
|
<if test="grossWeight != null"> |
||||
|
grossWeight = #{grossWeight}, |
||||
|
</if> |
||||
|
<if test="yolk != null"> |
||||
|
yolk = #{yolk}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
AND productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取用户所有联系人 --> |
||||
|
<select id="getUserAllContacts" resultType="com.example.web.mapper.SupplyUsersMapper$ContactInfo"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 采购端:获取用户所有产品信息 --> |
||||
|
<select id="getUserAllProducts" resultType="com.example.web.mapper.SupplyUsersMapper$ProductInfo"> |
||||
|
SELECT |
||||
|
productId, |
||||
|
productName, |
||||
|
variety, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk |
||||
|
FROM products |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🔥 新增:批量查询用户联系人信息 --> |
||||
|
<select id="getUserContactsByUserIds" resultType="com.example.web.mapper.UsersMapper$ContactInfo"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
userId as userId, <!-- 关键:添加userId字段用于分组 --> |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber as accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
ORDER BY userId, id |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🔥 新增:批量查询卖家产品信息(采购端专用) --> |
||||
|
<select id="getSellerProductsByUserIds" resultType="com.example.web.dto.UserProductCartDTO$ProductInfo"> |
||||
|
SELECT |
||||
|
productId as productId, |
||||
|
sellerId as sellerId, |
||||
|
productName as productName, |
||||
|
variety, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight as grossWeight, |
||||
|
yolk |
||||
|
FROM products |
||||
|
WHERE sellerId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
ORDER BY sellerId, productId |
||||
|
</select> |
||||
|
|
||||
|
|
||||
|
<!-- 🔥 新增:批量查询用户基本信息 --> |
||||
|
<select id="getUserBasicInfoByUserIds" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
AND phoneNumber IS NOT NULL |
||||
|
AND phoneNumber != '' |
||||
|
AND (type = 'seller' OR type = 'both') |
||||
|
ORDER BY userId |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据产品ID精确更新产品信息 --> |
||||
|
<update id="updateProductByProductId"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
productName = #{productName}, |
||||
|
variety = #{variety}, |
||||
|
specification = #{specification}, |
||||
|
quantity = #{quantity}, |
||||
|
grossWeight = #{grossWeight}, |
||||
|
yolk = #{yolk}, |
||||
|
updated_at = NOW() |
||||
|
WHERE productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 查询超过指定时间的未分级客户 --> |
||||
|
<select id="findUnclassifiedCustomersOlderThan" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
user_id as userId, |
||||
|
phone_number as phoneNumber, |
||||
|
type, |
||||
|
nick_name as nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE level = 'unclassified' |
||||
|
AND updated_at <= #{thresholdTime} |
||||
|
AND deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询超过指定时间的组织公海池客户 --> |
||||
|
<select id="findOrganizationSeaPoolsCustomersOlderThan" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
user_id as userId, |
||||
|
phone_number as phoneNumber, |
||||
|
type, |
||||
|
nick_name as nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE level = 'organization-sea-pools' |
||||
|
AND updated_at <= #{thresholdTime} |
||||
|
AND deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<select id="findRecentlyRecycledCustomers" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
u.user_id, |
||||
|
u.phone_number, |
||||
|
u.type, |
||||
|
u.nick_name, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
WHERE u.updated_at >= #{sinceTime} |
||||
|
AND u.level IN ('organization-sea-pools', 'department-sea-pools') |
||||
|
ORDER BY u.updated_at DESC |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,140 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.UsersManagementsMapper"> |
||||
|
|
||||
|
<resultMap id="UsersManagementsResultMap" type="com.example.web.entity.UsersManagements"> |
||||
|
<id property="id" column="id"/> |
||||
|
<result property="userId" column="userId"/> |
||||
|
<result property="managerId" column="managerId"/> |
||||
|
<result property="managercompany" column="managercompany"/> |
||||
|
<result property="managerdepartment" column="managerdepartment"/> |
||||
|
<result property="organization" column="organization"/> |
||||
|
<result property="role" column="role"/> |
||||
|
<result property="root" column="root"/> |
||||
|
<result property="created_at" column="created_at"/> |
||||
|
<result property="updated_at" column="updated_at"/> |
||||
|
<result property="userName" column="userName"/> |
||||
|
<result property="assistant" column="assistant"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
|
||||
|
<!-- 在 UsersManagementsMapper.xml 中添加 --> |
||||
|
<select id="findByUserNameAndManagerId" parameterType="map" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE userName = #{userName} AND managerId = #{managerId} |
||||
|
</select> |
||||
|
|
||||
|
|
||||
|
<!-- 新增:支持部门查询 --> |
||||
|
<select id="findByDepartment" parameterType="string" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE managerdepartment = #{department} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:组合条件查询 --> |
||||
|
<select id="findByConditions" parameterType="map" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
<where> |
||||
|
<if test="userName != null">AND userName = #{userName}</if> |
||||
|
<if test="department != null">AND managerdepartment = #{department}</if> |
||||
|
<if test="company != null">AND managercompany = #{company}</if> |
||||
|
<if test="role != null">AND role = #{role}</if> |
||||
|
</where> |
||||
|
ORDER BY created_at DESC |
||||
|
</select> |
||||
|
<!-- 根据用户ID查询负责人信息 --> |
||||
|
<select id="findByUserId" parameterType="string" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE userId = #{userId} |
||||
|
ORDER BY id DESC |
||||
|
LIMIT 1 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 插入负责人信息 --> |
||||
|
<insert id="insertUsersManagements" parameterType="com.example.web.entity.UsersManagements"> |
||||
|
INSERT INTO usermanagements ( |
||||
|
userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, |
||||
|
userName, assistant |
||||
|
) VALUES ( |
||||
|
#{userId}, #{managerId}, #{managercompany}, #{managerdepartment}, |
||||
|
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at}, |
||||
|
#{userName}, #{assistant} |
||||
|
) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 更新负责人信息 --> |
||||
|
<update id="updateUsersManagements" parameterType="com.example.web.entity.UsersManagements"> |
||||
|
UPDATE usermanagements |
||||
|
SET managerId = #{managerId}, |
||||
|
managercompany = #{managercompany}, |
||||
|
managerdepartment = #{managerdepartment}, |
||||
|
organization = #{organization}, |
||||
|
role = #{role}, |
||||
|
root = #{root}, |
||||
|
updated_at = #{updated_at}, |
||||
|
userName = #{userName}, |
||||
|
assistant = #{assistant} |
||||
|
WHERE id = #{id} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新负责人信息的更新时间 --> |
||||
|
<update id="updateManagerUpdateTime"> |
||||
|
UPDATE users_managements |
||||
|
SET updated_at = #{updatedAt} |
||||
|
WHERE user_id = #{userId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 查询完整负责人信息 --> |
||||
|
<select id="findCompleteManagerInfoByUserId" resultType="com.example.web.entity.UsersManagements"> |
||||
|
SELECT |
||||
|
manager_id, |
||||
|
managercompany, |
||||
|
managerdepartment, |
||||
|
organization, |
||||
|
role, |
||||
|
user_name, |
||||
|
assistant, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users_managements |
||||
|
WHERE user_id = #{userId} |
||||
|
</select> |
||||
|
<select id="findByUserIdAndAuthInfo" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT * FROM usermanagements |
||||
|
WHERE userId = #{userId} |
||||
|
AND (managercompany = #{authInfo.managercompany} OR #{authInfo.managercompany} IS NULL) |
||||
|
AND (managerdepartment = #{authInfo.managerdepartment} OR #{authInfo.managerdepartment} IS NULL) |
||||
|
AND (organization = #{authInfo.organization} OR #{authInfo.organization} IS NULL) |
||||
|
AND (userName = #{authInfo.userName} OR #{authInfo.userName} IS NULL) |
||||
|
LIMIT 1 |
||||
|
</select> |
||||
|
|
||||
|
<select id="findAuthorizedUserIds" resultType="string"> |
||||
|
SELECT userId FROM usermanagements |
||||
|
WHERE (managercompany = #{authInfo.managercompany} OR #{authInfo.managercompany} IS NULL) |
||||
|
AND (managerdepartment = #{authInfo.managerdepartment} OR #{authInfo.managerdepartment} IS NULL) |
||||
|
AND (organization = #{authInfo.organization} OR #{authInfo.organization} IS NULL) |
||||
|
AND (userName = #{authInfo.userName} OR #{authInfo.userName} IS NULL) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:批量查询用户负责人信息 --> |
||||
|
<select id="findByUserIds" resultMap="UsersManagementsResultMap"> |
||||
|
SELECT id, userId, managerId, managercompany, managerdepartment, |
||||
|
organization, role, root, created_at, updated_at, userName, assistant |
||||
|
FROM usermanagements |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
</select> |
||||
|
</mapper> |
||||
@ -0,0 +1,715 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" ?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
<mapper namespace="com.example.web.mapper.UsersMapper"> |
||||
|
<!-- 添加二级缓存 --> |
||||
|
<cache |
||||
|
eviction="LRU" |
||||
|
flushInterval="60000" |
||||
|
size="512" |
||||
|
readOnly="true"/> |
||||
|
|
||||
|
<resultMap id="userMap" type="com.example.web.entity.Users"> |
||||
|
<id column="id" property="id"/> |
||||
|
<result column="openid" property="openid"/> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="avatarUrl" property="avatarUrl"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="gender" property="gender"/> |
||||
|
<result column="country" property="country"/> |
||||
|
<result column="province" property="province"/> |
||||
|
<result column="city" property="city"/> |
||||
|
<result column="language" property="language"/> |
||||
|
<result column="session_key" property="session_key"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result property="company" column="company"/> |
||||
|
<result property="region" column="region"/> |
||||
|
<result property="level" column="level"/> |
||||
|
<result property="demand" column="demand" jdbcType="VARCHAR"/> |
||||
|
<result property="spec" column="spec" jdbcType="VARCHAR"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 用户基本信息映射 --> |
||||
|
<resultMap id="userBasicInfoMap" type="com.example.web.dto.UserProductCartDTO"> |
||||
|
<result column="userId" property="userId"/> |
||||
|
<result column="nickName" property="nickName"/> |
||||
|
<result column="phoneNumber" property="phoneNumber"/> |
||||
|
<result column="type" property="type"/> |
||||
|
<result column="created_at" property="created_at"/> |
||||
|
<result column="updated_at" property="updated_at"/> |
||||
|
<result property="company" column="company"/> |
||||
|
<result property="region" column="region"/> |
||||
|
<result property="level" column="level"/> |
||||
|
<result property="demand" column="demand" jdbcType="VARCHAR"/> |
||||
|
<result property="spec" column="spec" jdbcType="VARCHAR"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 产品信息映射 --> |
||||
|
<resultMap id="productInfoMap" type="com.example.web.dto.UserProductCartDTO$ProductInfo"> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="variety" property="variety"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="sellerId" property="sellerId"/> |
||||
|
<result column="sellerPhone" property="sellerPhone"/> |
||||
|
<result column="sellerNickName" property="sellerNickName"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 购物车信息映射 --> |
||||
|
<resultMap id="cartItemMap" type="com.example.web.dto.UserProductCartDTO$CartItem"> |
||||
|
<result column="specification" property="specification"/> |
||||
|
<result column="quantity" property="quantity"/> |
||||
|
<result column="grossWeight" property="grossWeight"/> |
||||
|
<result column="yolk" property="yolk"/> |
||||
|
<result column="productId" property="productId"/> |
||||
|
<result column="productName" property="productName"/> |
||||
|
<result column="price" property="price"/> |
||||
|
<result column="selected" property="selected"/> |
||||
|
</resultMap> |
||||
|
|
||||
|
<!-- 🚀 优化:获取授权客户列表 --> |
||||
|
<select id="getAuthorizedCustomers" resultMap="userBasicInfoMap" parameterType="map" useCache="true"> |
||||
|
SELECT DISTINCT |
||||
|
u.userId, |
||||
|
u.phoneNumber, |
||||
|
u.type, |
||||
|
u.nickName, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'buyer' OR u.type = 'both') |
||||
|
AND ( |
||||
|
-- 先按level分类减少条件复杂度 |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
OR |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
ORDER BY u.created_at DESC |
||||
|
<if test="limit != null and offset != null"> |
||||
|
LIMIT #{limit} OFFSET #{offset} |
||||
|
</if> |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 优化:获取授权客户总数 --> |
||||
|
<select id="getAuthorizedCustomersCount" resultType="int" parameterType="map" useCache="true"> |
||||
|
SELECT COUNT(DISTINCT u.userId) |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'buyer' OR u.type = 'both') |
||||
|
AND ( |
||||
|
-- 简化条件,提高执行效率 |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
OR |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 优化:根据认证信息获取有权限的用户ID列表 --> |
||||
|
<select id="getAuthorizedUserIds" resultType="string" parameterType="map" useCache="true"> |
||||
|
SELECT DISTINCT u.userId |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber IS NOT NULL |
||||
|
AND u.phoneNumber != '' |
||||
|
AND (u.type = 'buyer' OR u.type = 'both') |
||||
|
AND ( |
||||
|
-- 简化条件结构,提高查询效率 |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
OR |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取用户基本信息 --> |
||||
|
<select id="getUserBasicInfo" resultMap="userBasicInfoMap" parameterType="string"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取卖家的产品信息 --> |
||||
|
<select id="getSellerProducts" resultMap="productInfoMap" parameterType="string"> |
||||
|
SELECT productName, variety, specification, quantity, grossWeight, yolk, productId, price, sellerId |
||||
|
FROM products |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
ORDER BY created_at DESC |
||||
|
LIMIT 10 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取买家的购物车信息 --> |
||||
|
<select id="getBuyerCartItems" resultMap="cartItemMap" parameterType="string"> |
||||
|
SELECT |
||||
|
productName, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk, |
||||
|
productId, |
||||
|
price, |
||||
|
selected |
||||
|
FROM cart_items |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🎯 修改:保留原方法,但建议使用新的授权查询 --> |
||||
|
<select id="getAllUserBasicInfo" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE phoneNumber IS NOT NULL |
||||
|
AND phoneNumber != '' |
||||
|
AND (type = 'buyer' OR type = 'both') |
||||
|
ORDER BY created_at DESC |
||||
|
</select> |
||||
|
|
||||
|
<!-- 根据手机号查询用户 --> |
||||
|
<select id="selectByPhone" parameterType="string" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE phoneNumber = #{phoneNumber} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增:根据用户ID精确查询用户 --> |
||||
|
<select id="selectByUserId" parameterType="string" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🚀 新增:根据手机号和权限查询用户 --> |
||||
|
<select id="selectByPhoneWithAuth" parameterType="map" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
u.userId, |
||||
|
u.phoneNumber, |
||||
|
u.type, |
||||
|
u.nickName, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
LEFT JOIN usermanagements um ON u.userId = um.userId |
||||
|
WHERE u.phoneNumber = #{phoneNumber} |
||||
|
AND (u.type = 'buyer' OR u.type = 'both') |
||||
|
AND ( |
||||
|
<!-- 公海池客户权限规则 --> |
||||
|
(u.level IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND ( |
||||
|
(u.level IN ('company-sea-pools', '公海池') AND (um.userId IS NULL OR um.managerId IS NULL OR um.managerId = '')) |
||||
|
OR |
||||
|
(u.level = 'organization-sea-pools' AND um.organization = #{authInfo.organization}) |
||||
|
OR |
||||
|
(u.level = 'department-sea-pools' AND um.managerdepartment = #{authInfo.managerdepartment}) |
||||
|
)) |
||||
|
OR |
||||
|
<!-- 非公海池客户权限规则 --> |
||||
|
(u.level NOT IN ('company-sea-pools', 'organization-sea-pools', 'department-sea-pools', '公海池') |
||||
|
AND um.managercompany = #{authInfo.managercompany} |
||||
|
AND um.managerdepartment = #{authInfo.managerdepartment} |
||||
|
AND um.organization = #{authInfo.organization} |
||||
|
AND um.userName = #{authInfo.userName} |
||||
|
) |
||||
|
) |
||||
|
LIMIT 1 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 更新产品 --> |
||||
|
<update id="updateProduct"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
productName = #{product.productName}, |
||||
|
specification = #{product.specification}, |
||||
|
yolk = #{product.yolk}, |
||||
|
quantity = #{product.quantity}, |
||||
|
variety = #{product.variety}, |
||||
|
grossWeight = #{product.grossWeight}, |
||||
|
updated_at = NOW() |
||||
|
WHERE |
||||
|
sellerId = #{sellerId} |
||||
|
AND productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 根据手机号更新用户信息 --> |
||||
|
<update id="updateByPhone" parameterType="com.example.web.dto.UserProductCartDTO"> |
||||
|
UPDATE users |
||||
|
SET |
||||
|
<if test="nickName != null and nickName != ''"> |
||||
|
nickName = #{nickName}, |
||||
|
</if> |
||||
|
<if test="type != null and type != ''"> |
||||
|
type = #{type}, |
||||
|
</if> |
||||
|
<if test="company != null"> |
||||
|
company = #{company}, |
||||
|
</if> |
||||
|
<if test="region != null"> |
||||
|
region = #{region}, |
||||
|
</if> |
||||
|
<if test="level != null and level != ''"> |
||||
|
level = #{level}, |
||||
|
</if> |
||||
|
<if test="demand != null"> |
||||
|
demand = #{demand}, |
||||
|
</if> |
||||
|
<if test="spec != null"> |
||||
|
spec = #{spec}, |
||||
|
</if> |
||||
|
updated_at = #{updated_at} |
||||
|
WHERE phoneNumber = #{phoneNumber} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新产品信息 --> |
||||
|
<update id="updateProductBySellerId"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
<if test="productName != null and productName != ''"> |
||||
|
productName = #{productName}, |
||||
|
</if> |
||||
|
<if test="variety != null and variety != ''"> |
||||
|
variety = #{variety}, |
||||
|
</if> |
||||
|
<if test="specification != null and specification != ''"> |
||||
|
specification = #{specification}, |
||||
|
</if> |
||||
|
<if test="quantity != null"> |
||||
|
quantity = #{quantity}, |
||||
|
</if> |
||||
|
<if test="grossWeight != null"> |
||||
|
grossWeight = #{grossWeight}, |
||||
|
</if> |
||||
|
<if test="yolk != null and yolk != ''"> |
||||
|
yolk = #{yolk}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE sellerId = #{sellerId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新买家购物车信息 --> |
||||
|
<update id="updateCartItemByBuyerId"> |
||||
|
UPDATE cart_items |
||||
|
SET |
||||
|
productName = #{productName}, |
||||
|
specification = #{specification}, |
||||
|
quantity = #{quantity}, |
||||
|
grossWeight = #{grossWeight}, |
||||
|
yolk = #{yolk}, |
||||
|
added_at = NOW() |
||||
|
WHERE userId = #{buyerId} |
||||
|
AND productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取用户联系人信息 --> |
||||
|
<select id="getUserContacts" resultType="com.example.web.dto.UserProductCartDTO$UsersContacts"> |
||||
|
SELECT |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 更新用户联系人信息 --> |
||||
|
<update id="updateContactsByUserId"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
<if test="wechat != null and wechat != ''"> |
||||
|
wechat = #{wechat}, |
||||
|
</if> |
||||
|
<if test="account != null and account != ''"> |
||||
|
account = #{account}, |
||||
|
</if> |
||||
|
<if test="accountNumber != null and accountNumber != ''"> |
||||
|
accountNumber = #{accountNumber}, |
||||
|
</if> |
||||
|
<if test="bank != null and bank != ''"> |
||||
|
bank = #{bank}, |
||||
|
</if> |
||||
|
<if test="address != null and address != ''"> |
||||
|
address = #{address}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE userId = #{userId} |
||||
|
LIMIT 1 |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新或插入联系人信息 --> |
||||
|
<update id="updateOrInsertContact"> |
||||
|
INSERT INTO contacts (id, userId, wechat, account, accountNumber, bank, address, updated_at) |
||||
|
VALUES ( |
||||
|
COALESCE(#{contactId}, UUID()), |
||||
|
#{userId}, |
||||
|
#{wechat}, |
||||
|
#{account}, |
||||
|
#{accountNumber}, |
||||
|
#{bank}, |
||||
|
#{address}, |
||||
|
NOW() |
||||
|
) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
wechat = VALUES(wechat), |
||||
|
account = VALUES(account), |
||||
|
accountNumber = VALUES(accountNumber), |
||||
|
bank = VALUES(bank), |
||||
|
address = VALUES(address), |
||||
|
updated_at = NOW() |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新或插入购物车项 --> |
||||
|
<update id="updateOrInsertCartItem"> |
||||
|
INSERT INTO cart_items (id, userId, productId, productName, specification, quantity, grossWeight, yolk, added_at) |
||||
|
VALUES ( |
||||
|
COALESCE(#{cartItemId}, UUID()), |
||||
|
#{userId}, |
||||
|
#{productId}, |
||||
|
#{productName}, |
||||
|
#{specification}, |
||||
|
#{quantity}, |
||||
|
#{grossWeight}, |
||||
|
#{yolk}, |
||||
|
NOW() |
||||
|
) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
productName = VALUES(productName), |
||||
|
specification = VALUES(specification), |
||||
|
quantity = VALUES(quantity), |
||||
|
grossWeight = VALUES(grossWeight), |
||||
|
yolk = VALUES(yolk), |
||||
|
added_at = NOW() |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取用户所有联系人 --> |
||||
|
<select id="getAllUserContacts" resultType="com.example.web.dto.UnifiedCustomerDTO$ContactInfo"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取用户所有购物车项 --> |
||||
|
<select id="getAllUserCartItems" resultType="com.example.web.dto.UnifiedCustomerDTO$CartItem"> |
||||
|
SELECT |
||||
|
id as cartItemId, |
||||
|
productId, |
||||
|
productName, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk |
||||
|
FROM cart_items |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 更新特定联系人信息 --> |
||||
|
<update id="updateSpecificContact"> |
||||
|
UPDATE contacts |
||||
|
SET |
||||
|
<if test="wechat != null"> |
||||
|
wechat = #{wechat}, |
||||
|
</if> |
||||
|
<if test="account != null"> |
||||
|
account = #{account}, |
||||
|
</if> |
||||
|
<if test="accountNumber != null"> |
||||
|
accountNumber = #{accountNumber}, |
||||
|
</if> |
||||
|
<if test="bank != null"> |
||||
|
bank = #{bank}, |
||||
|
</if> |
||||
|
<if test="address != null"> |
||||
|
address = #{address}, |
||||
|
</if> |
||||
|
updated_at = NOW() |
||||
|
WHERE userId = #{userId} |
||||
|
AND id = #{contactId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 更新特定购物车项信息 --> |
||||
|
<update id="updateSpecificCartItem"> |
||||
|
UPDATE cart_items |
||||
|
SET |
||||
|
<if test="productId != null"> |
||||
|
productId = #{productId}, |
||||
|
</if> |
||||
|
<if test="productName != null"> |
||||
|
productName = #{productName}, |
||||
|
</if> |
||||
|
<if test="specification != null"> |
||||
|
specification = #{specification}, |
||||
|
</if> |
||||
|
<if test="quantity != null"> |
||||
|
quantity = #{quantity}, |
||||
|
</if> |
||||
|
<if test="grossWeight != null"> |
||||
|
grossWeight = #{grossWeight}, |
||||
|
</if> |
||||
|
<if test="yolk != null"> |
||||
|
yolk = #{yolk}, |
||||
|
</if> |
||||
|
added_at = NOW() |
||||
|
WHERE userId = #{userId} |
||||
|
AND id = #{cartItemId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 获取用户所有联系人 --> |
||||
|
<select id="getUserAllContacts" resultType="com.example.web.mapper.UsersMapper$ContactInfo"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 获取用户所有购物车项 --> |
||||
|
<select id="getUserAllCartItems" resultType="com.example.web.mapper.UsersMapper$CartItem"> |
||||
|
SELECT |
||||
|
id as cartItemId, |
||||
|
productId, |
||||
|
productName, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight, |
||||
|
yolk |
||||
|
FROM cart_items |
||||
|
WHERE userId = #{userId} |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🔥 新增:批量查询用户联系人信息 --> |
||||
|
<select id="getUserContactsByUserIds" resultType="com.example.web.mapper.UsersMapper$ContactInfo"> |
||||
|
SELECT |
||||
|
id as contactId, |
||||
|
userId as userId, <!-- 关键:添加userId字段用于分组 --> |
||||
|
wechat, |
||||
|
account, |
||||
|
accountNumber as accountNumber, |
||||
|
bank, |
||||
|
address |
||||
|
FROM contacts |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
ORDER BY userId, id |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🔥 新增:批量查询用户购物车信息 --> |
||||
|
<select id="getCartItemsByUserIds" resultType="com.example.web.mapper.UsersMapper$CartItem"> |
||||
|
SELECT |
||||
|
id as cartItemId, |
||||
|
userId as userId, <!-- 关键:添加userId字段用于分组 --> |
||||
|
productId as productId, |
||||
|
productName as productName, |
||||
|
specification, |
||||
|
quantity, |
||||
|
grossWeight as grossWeight, |
||||
|
yolk |
||||
|
FROM cart_items |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
ORDER BY userId, id |
||||
|
</select> |
||||
|
|
||||
|
<!-- 🔥 新增:批量查询用户基本信息 --> |
||||
|
<select id="getUserBasicInfoByUserIds" resultMap="userBasicInfoMap"> |
||||
|
SELECT |
||||
|
userId, |
||||
|
phoneNumber, |
||||
|
type, |
||||
|
nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE userId IN |
||||
|
<foreach collection="userIds" item="userId" open="(" separator="," close=")"> |
||||
|
#{userId} |
||||
|
</foreach> |
||||
|
AND phoneNumber IS NOT NULL |
||||
|
AND phoneNumber != '' |
||||
|
AND (type = 'buyer' OR type = 'both') |
||||
|
ORDER BY userId |
||||
|
</select> |
||||
|
|
||||
|
|
||||
|
|
||||
|
<!-- 根据产品ID精确更新产品信息 --> |
||||
|
<update id="updateProductByProductId"> |
||||
|
UPDATE products |
||||
|
SET |
||||
|
productName = #{productName}, |
||||
|
variety = #{variety}, |
||||
|
specification = #{specification}, |
||||
|
quantity = #{quantity}, |
||||
|
grossWeight = #{grossWeight}, |
||||
|
yolk = #{yolk}, |
||||
|
updated_at = NOW() |
||||
|
WHERE productId = #{productId} |
||||
|
</update> |
||||
|
|
||||
|
<!-- 查询超过指定时间的未分级客户 --> |
||||
|
<select id="findUnclassifiedCustomersOlderThan" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
user_id as userId, |
||||
|
phone_number as phoneNumber, |
||||
|
type, |
||||
|
nick_name as nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE level = 'unclassified' |
||||
|
AND updated_at <= #{thresholdTime} |
||||
|
AND deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 查询超过指定时间的组织公海池客户 --> |
||||
|
<select id="findOrganizationSeaPoolsCustomersOlderThan" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
user_id as userId, |
||||
|
phone_number as phoneNumber, |
||||
|
type, |
||||
|
nick_name as nickName, |
||||
|
company, |
||||
|
region, |
||||
|
level, |
||||
|
demand, |
||||
|
spec, |
||||
|
created_at, |
||||
|
updated_at |
||||
|
FROM users |
||||
|
WHERE level = 'organization-sea-pools' |
||||
|
AND updated_at <= #{thresholdTime} |
||||
|
AND deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<select id="findRecentlyRecycledCustomers" resultType="com.example.web.dto.UserProductCartDTO"> |
||||
|
SELECT |
||||
|
u.user_id, |
||||
|
u.phone_number, |
||||
|
u.type, |
||||
|
u.nick_name, |
||||
|
u.company, |
||||
|
u.region, |
||||
|
u.level, |
||||
|
u.demand, |
||||
|
u.spec, |
||||
|
u.created_at, |
||||
|
u.updated_at |
||||
|
FROM users u |
||||
|
WHERE u.updated_at >= #{sinceTime} |
||||
|
AND u.level IN ('organization-sea-pools', 'department-sea-pools') |
||||
|
ORDER BY u.updated_at DESC |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,986 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="zh-CN"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
|
<title>客户关系管理系统 - 登录</title> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
||||
|
<style> |
||||
|
/* 基础样式保持不变 */ |
||||
|
* { |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
box-sizing: border-box; |
||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
||||
|
} |
||||
|
|
||||
|
body { |
||||
|
overflow-x: hidden; |
||||
|
color: #333; |
||||
|
background: linear-gradient(135deg, #ebc4d2 0%, #c094ed 100%); |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
|
||||
|
canvas { |
||||
|
display: block; |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
z-index: -1; |
||||
|
} |
||||
|
|
||||
|
.login-container { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
min-height: 100vh; |
||||
|
padding: 20px; |
||||
|
} |
||||
|
|
||||
|
.login-panel { |
||||
|
background: rgba(161, 164, 163, 0); |
||||
|
border-radius: 20px; |
||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2); |
||||
|
padding: 40px; |
||||
|
width: 100%; |
||||
|
max-width: 450px; |
||||
|
backdrop-filter: blur(3px); |
||||
|
} |
||||
|
|
||||
|
.login-title { |
||||
|
font-size: 32px; |
||||
|
font-weight: 700; |
||||
|
text-align: center; |
||||
|
margin-bottom: 30px; |
||||
|
color: #333; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
gap: 15px; |
||||
|
} |
||||
|
|
||||
|
.login-title i { |
||||
|
color: #e86a92; |
||||
|
} |
||||
|
|
||||
|
.form-group { |
||||
|
margin-bottom: 25px; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.form-label { |
||||
|
display: block; |
||||
|
margin-bottom: 8px; |
||||
|
font-weight: 500; |
||||
|
color: #555; |
||||
|
} |
||||
|
|
||||
|
.form-input { |
||||
|
width: 100%; |
||||
|
padding: 15px 20px; |
||||
|
border-radius: 12px; |
||||
|
border: 1px solid rgba(0, 0, 0, 0.1); |
||||
|
background: rgba(255, 255, 255, 0.7); |
||||
|
font-size: 16px; |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.form-input:focus { |
||||
|
outline: none; |
||||
|
border-color: #e86a92; |
||||
|
box-shadow: 0 0 0 4px rgba(232, 106, 146, 0.2); |
||||
|
} |
||||
|
|
||||
|
.login-btn { |
||||
|
width: 100%; |
||||
|
padding: 16px; |
||||
|
border-radius: 12px; |
||||
|
border: none; |
||||
|
background: linear-gradient(45deg, #e86a92, #8e44ad); |
||||
|
color: white; |
||||
|
font-size: 18px; |
||||
|
font-weight: 600; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s ease; |
||||
|
margin-top: 10px; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.login-btn:hover:not(:disabled) { |
||||
|
transform: translateY(-3px); |
||||
|
box-shadow: 0 8px 20px rgba(232, 106, 146, 0.4); |
||||
|
} |
||||
|
|
||||
|
.login-btn:disabled { |
||||
|
opacity: 0.7; |
||||
|
cursor: not-allowed; |
||||
|
} |
||||
|
|
||||
|
.login-btn .spinner { |
||||
|
display: none; |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
border: 3px solid rgba(255, 255, 255, 0.3); |
||||
|
border-radius: 50%; |
||||
|
border-top-color: white; |
||||
|
animation: spin 1s ease-in-out infinite; |
||||
|
position: absolute; |
||||
|
left: calc(50% - 10px); |
||||
|
} |
||||
|
|
||||
|
@keyframes spin { |
||||
|
to { transform: rotate(360deg); } |
||||
|
} |
||||
|
|
||||
|
.error-message { |
||||
|
color: #cc2e1d; |
||||
|
font-size: 14px; |
||||
|
text-align: center; |
||||
|
margin-top: 15px; |
||||
|
padding: 10px; |
||||
|
border-radius: 8px; |
||||
|
background: rgba(231, 76, 60, 0.1); |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.error-message.show { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.form-input.error { |
||||
|
border-color: #e74c3c; |
||||
|
box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.2); |
||||
|
} |
||||
|
|
||||
|
.field-error { |
||||
|
color: #e74c3c; |
||||
|
font-size: 12px; |
||||
|
margin-top: 5px; |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.field-error.show { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.main-app { |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.main-app.active { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.modal-overlay { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: rgba(0, 0, 0, 0.5); |
||||
|
backdrop-filter: blur(4px); |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
z-index: 1000; |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.modal { |
||||
|
background: linear-gradient(135deg, #ebc4d2 0%, #c094ed 100%); |
||||
|
border-radius: 20px; |
||||
|
padding: 30px; |
||||
|
max-width: 400px; |
||||
|
width: 90%; |
||||
|
box-shadow: 0 10px 40px rgba(195, 194, 194, 0.5); |
||||
|
border: 1px solid rgba(255, 255, 255, 0.3); |
||||
|
backdrop-filter: blur(3px); |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.modal-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
margin-bottom: 20px; |
||||
|
padding-bottom: 15px; |
||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
.modal-title { |
||||
|
font-size: 22px; |
||||
|
text-align: center; |
||||
|
justify-content: space-between; |
||||
|
font-weight: 600; |
||||
|
color: #AB2524; |
||||
|
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2); |
||||
|
} |
||||
|
|
||||
|
.modal-close { |
||||
|
background: none; |
||||
|
border: none; |
||||
|
font-size: 24px; |
||||
|
cursor: pointer; |
||||
|
color: rgba(66, 239, 224, 0.8); |
||||
|
transition: color 0.3s; |
||||
|
} |
||||
|
|
||||
|
.modal-close:hover { |
||||
|
color: #2771d1; |
||||
|
} |
||||
|
|
||||
|
.modal-body { |
||||
|
margin-bottom: 25px; |
||||
|
line-height: 1.6; |
||||
|
text-align: center; |
||||
|
font-size: 16px; |
||||
|
color: #EAF044; |
||||
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.modal-footer { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
|
||||
|
.modal-btn { |
||||
|
padding: 10px 20px; |
||||
|
border-radius: 8px; |
||||
|
border: none; |
||||
|
background: linear-gradient(45deg, #e86a92, #8e44ad); |
||||
|
color: white; |
||||
|
cursor: pointer; |
||||
|
font-weight: 500; |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.modal-btn:hover { |
||||
|
transform: translateY(-2px); |
||||
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); |
||||
|
} |
||||
|
|
||||
|
.remember-me { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-top: 15px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
.remember-me input { |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
|
||||
|
.remember-me label { |
||||
|
font-size: 14px; |
||||
|
color: #555; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.clear-saved { |
||||
|
display: block; |
||||
|
text-align: right; |
||||
|
font-size: 12px; |
||||
|
color: #8e44ad; |
||||
|
cursor: pointer; |
||||
|
margin-top: 5px; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.clear-saved:hover { |
||||
|
color: #e86a92; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<canvas id="particleCanvas"></canvas> |
||||
|
|
||||
|
<div id="login-page" class="login-container"> |
||||
|
<div class="login-panel"> |
||||
|
<div class="login-title"> |
||||
|
<i class="fas fa-users"></i> |
||||
|
<span>客户关系管理系统</span> |
||||
|
</div> |
||||
|
|
||||
|
<form id="login-form" novalidate> |
||||
|
<div class="form-group"> |
||||
|
<label class="form-label" for="projectName">工位名</label> |
||||
|
<input type="text" id="projectName" class="form-input" placeholder="请输入工位名" required> |
||||
|
<div class="field-error" id="projectName-error">请输入工位名</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="form-group"> |
||||
|
<label class="form-label" for="userName">用户名</label> |
||||
|
<input type="text" id="userName" class="form-input" placeholder="请输入用户名" required> |
||||
|
<div class="field-error" id="userName-error">请输入用户名</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="form-group"> |
||||
|
<label class="form-label" for="password">密码</label> |
||||
|
<input type="password" id="password" class="form-input" placeholder="请输入密码" required> |
||||
|
<div class="field-error" id="password-error">请输入密码</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="remember-me"> |
||||
|
<input type="checkbox" id="rememberMe"> |
||||
|
<label for="rememberMe">记住用户名和工位名</label> |
||||
|
</div> |
||||
|
|
||||
|
<span class="clear-saved" id="clearSaved">清除已保存的信息</span> |
||||
|
|
||||
|
<button type="submit" class="login-btn" id="login-button"> |
||||
|
<span class="spinner" id="login-spinner"></span> |
||||
|
<span id="login-text"><i class="fas fa-sign-in-alt"></i> 登录</span> |
||||
|
</button> |
||||
|
|
||||
|
<div class="error-message" id="login-error"></div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div id="main-app" class="main-app"> |
||||
|
<!-- 主应用内容 --> |
||||
|
</div> |
||||
|
|
||||
|
<div class="modal-overlay" id="modal-overlay"> |
||||
|
<div class="modal"> |
||||
|
<div class="modal-header"> |
||||
|
<h3 class="modal-title" id="modal-title">登录失败</h3> |
||||
|
<button class="modal-close" id="modal-close">×</button> |
||||
|
</div> |
||||
|
<div class="modal-body" id="modal-message"> |
||||
|
账号或密码不正确,请重新输入。 |
||||
|
</div> |
||||
|
<div class="modal-footer"> |
||||
|
<button class="modal-btn" id="modal-confirm">确定</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script> |
||||
|
|
||||
|
<script> |
||||
|
// 登录状态管理 |
||||
|
let isLoggedIn = false;//登录状态记录 |
||||
|
let currentUser = null;//存储信息 |
||||
|
|
||||
|
// 检查本地存储中的登录状态 |
||||
|
function checkLoginStatus() { |
||||
|
const token = localStorage.getItem('authToken');//获取token |
||||
|
const user = localStorage.getItem('currentUser');//获取user |
||||
|
if (token && user) |
||||
|
{ |
||||
|
isLoggedIn = true; |
||||
|
currentUser = JSON.parse(user);//将user字符串解析为对象 |
||||
|
showMainApp(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
showLoginPage(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 检查是否有保存的用户名和工位名 |
||||
|
function checkSavedLoginInfo() |
||||
|
{ |
||||
|
const savedLoginInfo = localStorage.getItem('savedLoginInfo'); |
||||
|
if (savedLoginInfo) |
||||
|
{ |
||||
|
try { |
||||
|
const { projectName, userName } = JSON.parse(savedLoginInfo);//解析保存的登录信息 |
||||
|
if (projectName) |
||||
|
{ |
||||
|
document.getElementById('projectName').value = projectName; |
||||
|
} |
||||
|
if (userName) |
||||
|
{ |
||||
|
document.getElementById('userName').value = userName; |
||||
|
} |
||||
|
document.getElementById('rememberMe').checked = true;//记住用户名和工位名 |
||||
|
document.getElementById('clearSaved').style.display = 'block';//显示清除已保存的信息按钮 |
||||
|
} |
||||
|
catch (e) |
||||
|
{ |
||||
|
console.error('解析保存的登录信息失败', e); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
document.getElementById('clearSaved').style.display = 'none'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 清除已保存的用户名和工位名 |
||||
|
function clearSavedLoginInfo() { |
||||
|
localStorage.removeItem('savedLoginInfo'); |
||||
|
document.getElementById('projectName').value = '';//清空工位名输入框 |
||||
|
document.getElementById('userName').value = ''; |
||||
|
document.getElementById('rememberMe').checked = false;//取消记住用户名和工位名 |
||||
|
document.getElementById('clearSaved').style.display = 'none';//隐藏清除已保存的信息按钮 |
||||
|
} |
||||
|
|
||||
|
// 显示登录页面 |
||||
|
function showLoginPage() { |
||||
|
document.getElementById('login-page').style.display = 'flex';//显示登录页面 |
||||
|
document.getElementById('main-app').classList.remove('active');//隐藏主应用页面 |
||||
|
} |
||||
|
|
||||
|
// 显示主应用 |
||||
|
function showMainApp() { |
||||
|
document.getElementById('login-page').style.display = 'none';//隐藏登录页面 |
||||
|
document.getElementById('main-app').classList.add('active');//显示主应用页面 |
||||
|
|
||||
|
// 生成主应用内容 |
||||
|
document.getElementById('main-app').innerHTML = ` |
||||
|
<div style="text-align: center; padding: 50px;"> |
||||
|
<h2>退出成功!</h2> |
||||
|
<p>欢迎下次回来,${currentUser.userName} (${currentUser.projectName})</p> |
||||
|
<button id="logout-btn" style="margin-top: 20px; padding: 10px 20px; background: #e86a92; color: white; border: none; border-radius: 8px; cursor: pointer;"> |
||||
|
确定 |
||||
|
</button> |
||||
|
</div> |
||||
|
`; |
||||
|
|
||||
|
// 添加退出登录按钮事件监听 |
||||
|
document.getElementById('logout-btn').addEventListener('click', logout); |
||||
|
} |
||||
|
|
||||
|
// 退出登录 |
||||
|
function logout() { |
||||
|
localStorage.removeItem('authToken');//删除token |
||||
|
localStorage.removeItem('currentUser'); |
||||
|
isLoggedIn = false; |
||||
|
currentUser = null; |
||||
|
showLoginPage(); |
||||
|
} |
||||
|
|
||||
|
// 显示弹窗 |
||||
|
function showModal(title, message) { |
||||
|
document.getElementById('modal-title').textContent = title;//设置弹窗标题 |
||||
|
document.getElementById('modal-message').textContent = message;//设置弹窗消息 |
||||
|
document.getElementById('modal-overlay').style.display = 'flex';//显示弹窗 |
||||
|
} |
||||
|
|
||||
|
// 隐藏弹窗 |
||||
|
function hideModal() { |
||||
|
document.getElementById('modal-overlay').style.display = 'none'; |
||||
|
} |
||||
|
|
||||
|
// 设置登录按钮状态 |
||||
|
function setLoginButtonState(isLoading) { |
||||
|
const loginButton = document.getElementById('login-button');//获取登录按钮 |
||||
|
const loginSpinner = document.getElementById('login-spinner');//获取加载动画 |
||||
|
const loginText = document.getElementById('login-text');//获取登录按钮文字 |
||||
|
|
||||
|
if (isLoading) { |
||||
|
loginButton.disabled = true; |
||||
|
loginSpinner.style.display = 'block'; |
||||
|
loginText.style.opacity = '0'; |
||||
|
} else { |
||||
|
loginButton.disabled = false; |
||||
|
loginSpinner.style.display = 'none'; |
||||
|
loginText.style.opacity = '1'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 验证单个字段 |
||||
|
function validateField(fieldId) { |
||||
|
const field = document.getElementById(fieldId);//获取字段 |
||||
|
const errorElement = document.getElementById(`${fieldId}-error`);//获取错误提示元素 |
||||
|
|
||||
|
if (!field.value.trim()) { |
||||
|
field.classList.add('error');//添加错误样式 |
||||
|
errorElement.classList.add('show');//显示错误提示 |
||||
|
return false; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
field.classList.remove('error'); |
||||
|
errorElement.classList.remove('show'); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 验证所有字段 |
||||
|
function validateForm() { |
||||
|
let isValid = true;//初始化为true |
||||
|
if (!validateField('projectName')) isValid = false; |
||||
|
if (!validateField('userName')) isValid = false; |
||||
|
if (!validateField('password')) isValid = false; |
||||
|
return isValid; |
||||
|
} |
||||
|
|
||||
|
// 清除字段错误状态 |
||||
|
function clearFieldError(fieldId) { |
||||
|
const field = document.getElementById(fieldId); |
||||
|
const errorElement = document.getElementById(`${fieldId}-error`); |
||||
|
field.classList.remove('error'); |
||||
|
errorElement.classList.remove('show'); |
||||
|
} |
||||
|
|
||||
|
const API_BASE_URL = 'http://localhost:8080/DL'; // 服务器API地址 |
||||
|
async function sendLoginRequest(projectName, userName, password) { |
||||
|
try { |
||||
|
// 使用URL编码的表单数据 |
||||
|
const params = new URLSearchParams(); |
||||
|
params.append('projectName', projectName); |
||||
|
params.append('userName', userName); |
||||
|
params.append('password', password); |
||||
|
|
||||
|
const response = await fetch(`${API_BASE_URL}/logins`, { |
||||
|
method: 'POST', |
||||
|
headers: { |
||||
|
'Content-Type': 'application/x-www-form-urlencoded', |
||||
|
}, |
||||
|
body: params.toString() |
||||
|
}); |
||||
|
|
||||
|
if (!response.ok) { |
||||
|
throw new Error(`HTTP error! status: ${response.status}`); |
||||
|
} |
||||
|
const data = await response.json(); |
||||
|
return data; |
||||
|
} catch (error) { |
||||
|
console.error('登录请求失败:', error); |
||||
|
throw new Error('网络错误,请检查网络连接后重试'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 处理登录表单提交 |
||||
|
document.getElementById('login-form').addEventListener('submit', async function (e) { |
||||
|
e.preventDefault(); |
||||
|
// 重置错误消息 |
||||
|
document.getElementById('login-error').classList.remove('show'); |
||||
|
|
||||
|
// 验证表单 |
||||
|
if (!validateForm()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 获取表单值 |
||||
|
const projectName = document.getElementById('projectName').value; |
||||
|
const userName = document.getElementById('userName').value; |
||||
|
const password = document.getElementById('password').value; |
||||
|
const rememberMe = document.getElementById('rememberMe').checked; |
||||
|
|
||||
|
// 显示加载状态 |
||||
|
setLoginButtonState(true); |
||||
|
|
||||
|
try { |
||||
|
// 发送登录请求到后端 |
||||
|
const response = await sendLoginRequest(projectName, userName, password); |
||||
|
|
||||
|
if (response.success) { |
||||
|
// 登录成功 |
||||
|
if (rememberMe) { |
||||
|
const loginInfo = { projectName, userName }; |
||||
|
localStorage.setItem('savedLoginInfo', JSON.stringify(loginInfo)); |
||||
|
document.getElementById('clearSaved').style.display = 'block'; |
||||
|
} else { |
||||
|
localStorage.removeItem('savedLoginInfo'); |
||||
|
document.getElementById('clearSaved').style.display = 'none'; |
||||
|
} |
||||
|
|
||||
|
// 保存认证信息 |
||||
|
localStorage.setItem('authToken', response.token); |
||||
|
localStorage.setItem('currentUser', JSON.stringify(response.user)); |
||||
|
|
||||
|
// 根据角色跳转到不同的页面,并传递用户信息 |
||||
|
const root = response.root; |
||||
|
const userParams = new URLSearchParams({ |
||||
|
managerId:encodeURIComponent(response.user.managerId), |
||||
|
managercompany:encodeURIComponent(response.user.managercompany), |
||||
|
managerdepartment:encodeURIComponent(response.user.managerdepartment), |
||||
|
organization:encodeURIComponent(response.user.organization), |
||||
|
role: encodeURIComponent(response.user.role),//角色 |
||||
|
userName: encodeURIComponent(response.user.userName),//用户名 |
||||
|
assistant:encodeURIComponent(response.user.assistant),//助理 |
||||
|
token: response.token//认证信息 |
||||
|
}).toString(); |
||||
|
|
||||
|
if (root === 1) { |
||||
|
// 总经理跳转到 |
||||
|
window.location.href = `mainapp(2).html?${userParams}`; |
||||
|
} |
||||
|
else if (root === 2) { |
||||
|
// 采购员跳转 |
||||
|
// 销售员跳转 |
||||
|
console.log('负责人id',response.user.managerId); |
||||
|
console.log('所属部门', response.user.managerdepartment); |
||||
|
console.log('所属公司', response.user.managercompany); |
||||
|
console.log('所属组织', response.user.organization); |
||||
|
console.log('角色', response.user.role); |
||||
|
console.log('用户名', response.user.userName); |
||||
|
console.log('助理', response.user.assistant); |
||||
|
window.location.href = `mainapp-supplys.html?${userParams}`; |
||||
|
} |
||||
|
else if (root === 3) { |
||||
|
// 销售员跳转 |
||||
|
console.log('负责人id',response.user.managerId); |
||||
|
console.log('所属部门', response.user.managerdepartment); |
||||
|
console.log('所属公司', response.user.managercompany); |
||||
|
console.log('所属组织', response.user.organization); |
||||
|
console.log('角色', response.user.role); |
||||
|
console.log('用户名', response.user.userName); |
||||
|
console.log('助理', response.user.assistant); |
||||
|
window.location.href = `mainapp-sells.html?${userParams}`; |
||||
|
} else { |
||||
|
// 未知角色,显示错误或跳转到默认页面 |
||||
|
showModal('登录失败', '未知用户角色,请联系管理员'); |
||||
|
} |
||||
|
} else { |
||||
|
// 登录失败 |
||||
|
if (response.errorType === 'password') { |
||||
|
document.getElementById('password').value = ''; |
||||
|
showModal('登录失败', '密码错误,请重新输入'); |
||||
|
} else { |
||||
|
showModal('登录失败', response.message || '登录失败,请检查您的账号和密码'); |
||||
|
} |
||||
|
} |
||||
|
} catch (error) { |
||||
|
// 异常处理 |
||||
|
showModal('登录错误', error.message || '登录过程中发生错误,请稍后重试'); |
||||
|
console.error('Login error:', error); |
||||
|
} finally { |
||||
|
// 隐藏加载状态 |
||||
|
setLoginButtonState(false); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// 为输入字段添加事件监听器,失去焦点时验证 |
||||
|
document.getElementById('projectName').addEventListener('blur', function() { |
||||
|
validateField('projectName'); |
||||
|
}); |
||||
|
|
||||
|
document.getElementById('userName').addEventListener('blur', function() { |
||||
|
validateField('userName'); |
||||
|
}); |
||||
|
|
||||
|
document.getElementById('password').addEventListener('blur', function() { |
||||
|
validateField('password'); |
||||
|
}); |
||||
|
|
||||
|
// 为输入字段添加事件监听器,输入时清除错误状态 |
||||
|
document.getElementById('projectName').addEventListener('input', function() { |
||||
|
clearFieldError('projectName'); |
||||
|
}); |
||||
|
|
||||
|
document.getElementById('userName').addEventListener('input', function() { |
||||
|
clearFieldError('userName'); |
||||
|
}); |
||||
|
|
||||
|
document.getElementById('password').addEventListener('input', function() { |
||||
|
clearFieldError('password'); |
||||
|
}); |
||||
|
|
||||
|
// 清除已保存的用户名和工位名 |
||||
|
document.getElementById('clearSaved').addEventListener('click', clearSavedLoginInfo); |
||||
|
|
||||
|
// 弹窗事件处理 |
||||
|
document.getElementById('modal-close').addEventListener('click', hideModal); |
||||
|
document.getElementById('modal-confirm').addEventListener('click', hideModal); |
||||
|
|
||||
|
// 页面加载时检查登录状态 |
||||
|
window.addEventListener('DOMContentLoaded', function () { |
||||
|
checkLoginStatus(); |
||||
|
checkSavedLoginInfo(); |
||||
|
initParticleBackground(); // 初始化粒子背景 |
||||
|
}); |
||||
|
|
||||
|
// 粒子背景初始化函数 |
||||
|
function initParticleBackground() { |
||||
|
// 3D粒子背景特效 |
||||
|
const scene = new THREE.Scene(); // 创建场景 |
||||
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000); // 创建透视相机 |
||||
|
const renderer = new THREE.WebGLRenderer({ |
||||
|
canvas: document.getElementById('particleCanvas'), // 指定渲染画布 |
||||
|
antialias: true, // 开启抗锯齿 |
||||
|
alpha: true // 开启透明度 |
||||
|
}); |
||||
|
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器尺寸 |
||||
|
renderer.setClearColor(0x000000, 0); // 设置清除颜色(透明) |
||||
|
|
||||
|
camera.position.z = 5; // 设置相机位置 |
||||
|
|
||||
|
// 粒子系统参数 |
||||
|
const particleCount = 120; // 粒子数量 |
||||
|
const minDistance = 2.5; // 最小距离 |
||||
|
const particleSize = 0.2; // 粒子大小 |
||||
|
const particles = new THREE.BufferGeometry(); // 创建粒子几何体 |
||||
|
const positions = new Float32Array(particleCount * 3); // 位置数组 |
||||
|
const colors = new Float32Array(particleCount * 3); // 颜色数组 |
||||
|
const sizes = new Float32Array(particleCount); // 大小数组 |
||||
|
const velocities = new Float32Array(particleCount * 3); // 速度数组 |
||||
|
const opacities = new Float32Array(particleCount); // 透明度数组 |
||||
|
const lifeCycles = new Float32Array(particleCount); // 生命周期数组 |
||||
|
const resetOffsets = new Float32Array(particleCount); // 重置偏移数组 |
||||
|
|
||||
|
// 粒子系统常量 |
||||
|
const maxLife = 5000; // 最大生命周期 |
||||
|
const fadeRange = 600; // 淡入淡出范围 |
||||
|
const baseSpeed = 0.007; // 基础速度 |
||||
|
const frustum = new THREE.Frustum(); // 视锥体 |
||||
|
const distanceThreshold = 200; // 距离阈值 |
||||
|
const distributionRadius = 14; // 分布半径 |
||||
|
|
||||
|
// 颜色调色板 |
||||
|
const colorPalette = [ |
||||
|
new THREE.Color(0xe86a92), |
||||
|
new THREE.Color(0xd68fb7), |
||||
|
new THREE.Color(0x8e44ad), |
||||
|
new THREE.Color(0xe74c3c) |
||||
|
]; |
||||
|
|
||||
|
// 检查位置是否有效(避免粒子过于接近) |
||||
|
function isPositionValid(x, y, z, existingParticles, index) { |
||||
|
for (let i = 0; i < index; i++) { |
||||
|
const i3 = i * 3; |
||||
|
const dx = x - existingParticles[i3]; |
||||
|
const dy = y - existingParticles[i3 + 1]; |
||||
|
const dz = z - existingParticles[i3 + 2]; |
||||
|
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); |
||||
|
|
||||
|
if (distance < minDistance) { |
||||
|
return false; // 距离太近,位置无效 |
||||
|
} |
||||
|
} |
||||
|
return true; // 位置有效 |
||||
|
} |
||||
|
|
||||
|
let particleIndex = 0; // 粒子索引 |
||||
|
const maxAttempts = 100; // 最大尝试次数 |
||||
|
const rings = 6; // 环数 |
||||
|
const particlesPerRing = Math.ceil(particleCount / rings); // 每环粒子数 |
||||
|
|
||||
|
// 初始化粒子位置 |
||||
|
for (let ring = 1; ring <= rings; ring++) { |
||||
|
const radius = (distributionRadius / (rings + 1)) * ring; // 计算环半径 |
||||
|
|
||||
|
for (let p = 0; p < particlesPerRing && particleIndex < particleCount; p++) { |
||||
|
let validPosition = false; // 位置有效性标志 |
||||
|
let x, y, z; // 位置坐标 |
||||
|
let attempts = 0; // 尝试次数 |
||||
|
|
||||
|
// 尝试找到有效位置 |
||||
|
while (!validPosition && attempts < maxAttempts) { |
||||
|
const angle = (p / particlesPerRing) * Math.PI * 2 + (Math.random() * 0.1); // 计算角度 |
||||
|
x = Math.cos(angle) * radius; // 计算x坐标 |
||||
|
y = Math.sin(angle) * radius; // 计算y坐标 |
||||
|
z = -Math.random() * 4; // 计算z坐标 |
||||
|
|
||||
|
validPosition = isPositionValid(x, y, z, positions, particleIndex); // 检查位置有效性 |
||||
|
attempts++; // 增加尝试次数 |
||||
|
} |
||||
|
|
||||
|
if (validPosition) { |
||||
|
addParticle(x, y, z); // 添加粒子 |
||||
|
} else { |
||||
|
addParticle(x, y, z); // 即使位置无效也添加粒子 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 添加粒子到系统 |
||||
|
function addParticle(x, y, z) { |
||||
|
const i3 = particleIndex * 3; // 计算数组索引 |
||||
|
|
||||
|
// 设置位置 |
||||
|
positions[i3] = x; |
||||
|
positions[i3 + 1] = y; |
||||
|
positions[i3 + 2] = z; |
||||
|
|
||||
|
// 计算速度因子 |
||||
|
const distanceFromCenter = Math.sqrt(x * x + y * y) || 1; |
||||
|
const speedFactor = 0.025 / distanceFromCenter; |
||||
|
|
||||
|
// 设置速度 |
||||
|
velocities[i3] = x * speedFactor * baseSpeed; |
||||
|
velocities[i3 + 1] = y * speedFactor * baseSpeed; |
||||
|
velocities[i3 + 2] = baseSpeed * (1 + Math.random() * 0.2); |
||||
|
|
||||
|
// 设置大小 |
||||
|
sizes[particleIndex] = particleSize * (0.9 + Math.random() * 0.2); |
||||
|
|
||||
|
// 设置颜色 |
||||
|
const color = colorPalette[Math.floor(Math.random() * colorPalette.length)]; |
||||
|
colors[i3] = color.r; |
||||
|
colors[i3 + 1] = color.g; |
||||
|
colors[i3 + 2] = color.b; |
||||
|
|
||||
|
// 设置生命周期和透明度 |
||||
|
lifeCycles[particleIndex] = Math.random() * maxLife; |
||||
|
resetOffsets[particleIndex] = Math.random() * 1000; |
||||
|
opacities[particleIndex] = 1; |
||||
|
|
||||
|
particleIndex++; // 增加粒子索引 |
||||
|
} |
||||
|
|
||||
|
// 设置几何体属性 |
||||
|
particles.setAttribute('position', new THREE.BufferAttribute(positions, 3)); |
||||
|
particles.setAttribute('color', new THREE.BufferAttribute(colors, 3)); |
||||
|
particles.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); |
||||
|
particles.setAttribute('opacity', new THREE.BufferAttribute(opacities, 1)); |
||||
|
|
||||
|
// 创建粒子材质 |
||||
|
const particleMaterial = new THREE.ShaderMaterial({ |
||||
|
uniforms: { |
||||
|
color: { value: new THREE.Color(0xffffff) } // 颜色统一值 |
||||
|
}, |
||||
|
// 顶点着色器 |
||||
|
vertexShader: ` |
||||
|
attribute float size; |
||||
|
attribute float opacity; |
||||
|
varying float vOpacity; |
||||
|
void main() { |
||||
|
vOpacity = opacity; |
||||
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); |
||||
|
gl_PointSize = size * (150.0 / -mvPosition.z); |
||||
|
gl_Position = projectionMatrix * mvPosition; |
||||
|
} |
||||
|
`, |
||||
|
// 片段着色器 |
||||
|
fragmentShader: ` |
||||
|
uniform vec3 color; |
||||
|
varying float vOpacity; |
||||
|
void main() { |
||||
|
vec2 coord = gl_PointCoord - vec2(0.5); |
||||
|
float distance = length(coord); |
||||
|
|
||||
|
float smoothness = 0.2; |
||||
|
float alpha = vOpacity * (1.0 - smoothstep(0.5 - smoothness, 0.5, distance)); |
||||
|
|
||||
|
alpha *= 1.0 - (distance * 1.5); |
||||
|
|
||||
|
if (alpha < 0.05) discard; |
||||
|
|
||||
|
gl_FragColor = vec4(color, alpha); |
||||
|
} |
||||
|
`, |
||||
|
transparent: true, // 启用透明度 |
||||
|
blending: THREE.AdditiveBlending, // 使用相加混合 |
||||
|
alphaTest: 0.05 // alpha测试阈值 |
||||
|
}); |
||||
|
|
||||
|
// 创建粒子系统 |
||||
|
const particleSystem = new THREE.Points(particles, particleMaterial); |
||||
|
scene.add(particleSystem); // 将粒子系统添加到场景 |
||||
|
|
||||
|
const vector = new THREE.Vector3(); // 创建临时向量 |
||||
|
|
||||
|
// 动画循环函数 |
||||
|
function animate() { |
||||
|
requestAnimationFrame(animate); // 请求下一帧动画 |
||||
|
|
||||
|
// 更新视锥体 |
||||
|
camera.updateMatrixWorld(); |
||||
|
frustum.setFromProjectionMatrix( |
||||
|
new THREE.Matrix4().multiplyMatrices( |
||||
|
camera.projectionMatrix, |
||||
|
camera.matrixWorldInverse |
||||
|
) |
||||
|
); |
||||
|
|
||||
|
const positions = particles.attributes.position.array; // 获取位置数组 |
||||
|
const opacities = particles.attributes.opacity.array; // 获取透明度数组 |
||||
|
|
||||
|
// 更新每个粒子 |
||||
|
for (let i = 0; i < particleCount; i++) { |
||||
|
const i3 = i * 3; // 计算数组索引 |
||||
|
|
||||
|
lifeCycles[i]++; // 增加生命周期 |
||||
|
|
||||
|
// 计算有效最大生命周期 |
||||
|
const effectiveMaxLife = maxLife + resetOffsets[i]; |
||||
|
if (lifeCycles[i] < fadeRange) { |
||||
|
// 淡入阶段 |
||||
|
opacities[i] = lifeCycles[i] / fadeRange; |
||||
|
} else if (lifeCycles[i] > effectiveMaxLife - fadeRange) { |
||||
|
// 淡出阶段 |
||||
|
opacities[i] = (effectiveMaxLife - lifeCycles[i]) / fadeRange; |
||||
|
} else { |
||||
|
// 完全可见阶段 |
||||
|
opacities[i] = 1; |
||||
|
} |
||||
|
|
||||
|
// 更新位置 |
||||
|
positions[i3] += velocities[i3]; |
||||
|
positions[i3 + 1] += velocities[i3 + 1]; |
||||
|
positions[i3 + 2] += velocities[i3 + 2]; |
||||
|
|
||||
|
// 检查粒子是否需要重置 |
||||
|
vector.set(positions[i3], positions[i3 + 1], positions[i3 + 2]); |
||||
|
const isOutsideFrustum = !frustum.containsPoint(vector); // 是否在视锥体外 |
||||
|
const distanceFromCamera = vector.distanceTo(camera.position); // 与相机的距离 |
||||
|
|
||||
|
// 重置条件:生命周期结束、距离过远或在视锥体外 |
||||
|
if (lifeCycles[i] > effectiveMaxLife || |
||||
|
distanceFromCamera > distanceThreshold || |
||||
|
isOutsideFrustum) { |
||||
|
|
||||
|
let x, y, z; // 新位置坐标 |
||||
|
let validPosition = false; // 位置有效性标志 |
||||
|
let attempts = 0; // 尝试次数 |
||||
|
|
||||
|
// 尝试找到有效的新位置 |
||||
|
while (!validPosition && attempts < maxAttempts) { |
||||
|
const ring = Math.floor(Math.random() * rings) + 1; // 随机选择环 |
||||
|
const radius = (distributionRadius / (rings + 1)) * ring; // 计算环半径 |
||||
|
const angle = Math.random() * Math.PI * 2; // 随机角度 |
||||
|
|
||||
|
x = Math.cos(angle) * radius; // 计算x坐标 |
||||
|
y = Math.sin(angle) * radius; // 计算y坐标 |
||||
|
z = -Math.random() * 4; // 计算z坐标 |
||||
|
|
||||
|
validPosition = true; // 假设位置有效 |
||||
|
// 检查与其他粒子的距离 |
||||
|
for (let j = 0; j < particleCount; j++) { |
||||
|
if (j === i) continue; // 跳过自身 |
||||
|
const j3 = j * 3; |
||||
|
const dx = x - positions[j3]; |
||||
|
const dy = y - positions[j3 + 1]; |
||||
|
const dz = z - positions[j3 + 2]; |
||||
|
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); |
||||
|
|
||||
|
// 如果距离太近且粒子处于活跃状态,则位置无效 |
||||
|
if (distance < minDistance && lifeCycles[j] > fadeRange && lifeCycles[j] < effectiveMaxLife - fadeRange) { |
||||
|
validPosition = false; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
attempts++; // 增加尝试次数 |
||||
|
} |
||||
|
|
||||
|
// 设置新位置 |
||||
|
positions[i3] = x; |
||||
|
positions[i3 + 1] = y; |
||||
|
positions[i3 + 2] = z; |
||||
|
lifeCycles[i] = 0; // 重置生命周期 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 标记需要更新属性 |
||||
|
particles.attributes.position.needsUpdate = true; |
||||
|
particles.attributes.opacity.needsUpdate = true; |
||||
|
|
||||
|
// 缓慢旋转粒子系统 |
||||
|
particleSystem.rotation.x += 0.0000005; |
||||
|
particleSystem.rotation.y += 0.000001; |
||||
|
|
||||
|
renderer.render(scene, camera); // 渲染场景 |
||||
|
} |
||||
|
|
||||
|
// 窗口大小调整事件处理 |
||||
|
window.addEventListener('resize', () => { |
||||
|
camera.aspect = window.innerWidth / window.innerHeight; // 更新相机宽高比 |
||||
|
camera.updateProjectionMatrix(); // 更新相机投影矩阵 |
||||
|
renderer.setSize(window.innerWidth, window.innerHeight); // 更新渲染器尺寸 |
||||
|
}); |
||||
|
|
||||
|
// 启动动画 |
||||
|
animate(); |
||||
|
} |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
||||
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,13 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
|
||||
|
@SpringBootTest |
||||
|
class WebApplicationTests { |
||||
|
|
||||
|
@Test |
||||
|
void contextLoads() { |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue