From 1759de5af3dc84b2493bd6104c77873d1f8c1aa0 Mon Sep 17 00:00:00 2001 From: andy <594580820@qq.com> Date: Wed, 28 Jan 2026 16:04:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=8A=A5=E5=A4=87?= =?UTF-8?q?=E8=BF=9B=E5=B1=95=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 3 +- .gitignore | 25 +-- .../controller/ReportProgressController.java | 91 +++++++++++ .../java/com/bycrm/dto/ReportProgressDTO.java | 25 +++ .../java/com/bycrm/entity/ReportProgress.java | 53 +++++++ .../bycrm/mapper/ReportProgressMapper.java | 39 +++++ .../bycrm/service/ReportProgressService.java | 37 +++++ .../impl/ReportProgressServiceImpl.java | 119 +++++++++++++++ .../resources/mapper/ReportProgressMapper.xml | 71 +++++++++ frontend/src/api/report-progress.ts | 27 ++++ frontend/src/types/index.ts | 16 ++ frontend/src/views/Report.vue | 144 +++++++++++++++++- sql/01_init.sql | 13 ++ 13 files changed, 639 insertions(+), 24 deletions(-) create mode 100644 backend/src/main/java/com/bycrm/controller/ReportProgressController.java create mode 100644 backend/src/main/java/com/bycrm/dto/ReportProgressDTO.java create mode 100644 backend/src/main/java/com/bycrm/entity/ReportProgress.java create mode 100644 backend/src/main/java/com/bycrm/mapper/ReportProgressMapper.java create mode 100644 backend/src/main/java/com/bycrm/service/ReportProgressService.java create mode 100644 backend/src/main/java/com/bycrm/service/impl/ReportProgressServiceImpl.java create mode 100644 backend/src/main/resources/mapper/ReportProgressMapper.xml create mode 100644 frontend/src/api/report-progress.ts diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 08a46f1..1499743 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -10,7 +10,8 @@ "Bash(git push:*)", "Bash(git config:*)", "Bash(pnpm run build)", - "Bash(mvn compile:*)" + "Bash(mvn compile:*)", + "Bash(dir:*)" ] } } diff --git a/.gitignore b/.gitignore index ff56710..3a110d6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,27 +4,6 @@ /frontend/node_modules/ /frontend/node_modules/* /KEY_GENERATOR.md -/backend/tmpclaude-* -/frontend/tmpclaude-* -/tmpclaude-* -/tmpclaude-6f5d-cwd -/tmpclaude-006c-cwd -/tmpclaude-27a4-cwd -/tmpclaude-2246-cwd -/tmpclaude-a7d6-cwd -/tmpclaude-b78e-cwd -/tmpclaude-2a25-cwd -/tmpclaude-45c6-cwd -/tmpclaude-62fc-cwd -/tmpclaude-65b0-cwd -/tmpclaude-4540-cwd -/tmpclaude-b9f7-cwd -/tmpclaude-b842-cwd -/tmpclaude-c399-cwd -/tmpclaude-d1b4-cwd - - -/backend/target/ /mysql/data/ @@ -56,3 +35,7 @@ Thumbs.db Dockerfile .dockerignore +**/tmpclaude-* +/backend/tmpclaude-* +/frontend/tmpclaude-* +/tmpclaude-* diff --git a/backend/src/main/java/com/bycrm/controller/ReportProgressController.java b/backend/src/main/java/com/bycrm/controller/ReportProgressController.java new file mode 100644 index 0000000..0820add --- /dev/null +++ b/backend/src/main/java/com/bycrm/controller/ReportProgressController.java @@ -0,0 +1,91 @@ +package com.bycrm.controller; + +import com.bycrm.common.Result; +import com.bycrm.dto.ReportProgressDTO; +import com.bycrm.entity.ReportProgress; +import com.bycrm.service.ReportProgressService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +/** + * 报备进展记录控制器 + */ +@Api(tags = "报备进展管理") +@RestController +@RequestMapping("/report-progress") +public class ReportProgressController { + + private final ReportProgressService reportProgressService; + + public ReportProgressController(ReportProgressService reportProgressService) { + this.reportProgressService = reportProgressService; + } + + /** + * 根据报备ID获取进展记录列表 + */ + @ApiOperation("根据报备ID获取进展记录列表") + @GetMapping("/report/{reportId}") + public Result> getProgressByReportId( + @ApiParam("报备ID") @PathVariable Long reportId) { + List progressList = reportProgressService.getProgressByReportId(reportId); + return Result.success(progressList); + } + + /** + * 根据ID获取进展记录 + */ + @ApiOperation("根据ID获取进展记录") + @GetMapping("/{id}") + public Result getProgressById( + @ApiParam("进展ID") @PathVariable Long id) { + ReportProgress progress = reportProgressService.getProgressById(id); + return Result.success(progress); + } + + /** + * 创建进展记录 + */ + @ApiOperation("创建进展记录") + @PostMapping + public Result createProgress( + @ApiParam("进展记录数据") @RequestBody @Valid ReportProgressDTO progressDTO, + HttpServletRequest request) { + Long currentUserId = (Long) request.getAttribute("currentUserId"); + reportProgressService.createProgress(progressDTO, currentUserId); + return Result.success(); + } + + /** + * 更新进展记录 + */ + @ApiOperation("更新进展记录") + @PutMapping("/{id}") + public Result updateProgress( + @ApiParam("进展ID") @PathVariable Long id, + @ApiParam("进展记录数据") @RequestBody @Valid ReportProgressDTO progressDTO, + HttpServletRequest request) { + Long currentUserId = (Long) request.getAttribute("currentUserId"); + reportProgressService.updateProgress(id, progressDTO, currentUserId); + return Result.success(); + } + + /** + * 删除进展记录(根据需求不可删除,所以不提供该接口) + */ + // @ApiOperation("删除进展记录") + // @DeleteMapping("/{id}") + // public Result deleteProgress( + // @ApiParam("进展ID") @PathVariable Long id, + // HttpServletRequest request) { + // Long currentUserId = (Long) request.getAttribute("currentUserId"); + // reportProgressService.deleteProgress(id, currentUserId); + // return Result.success(); + // } +} diff --git a/backend/src/main/java/com/bycrm/dto/ReportProgressDTO.java b/backend/src/main/java/com/bycrm/dto/ReportProgressDTO.java new file mode 100644 index 0000000..7965740 --- /dev/null +++ b/backend/src/main/java/com/bycrm/dto/ReportProgressDTO.java @@ -0,0 +1,25 @@ +package com.bycrm.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 报备进展记录 DTO + */ +@Data +public class ReportProgressDTO { + + /** + * 关联报备ID + */ + @NotNull(message = "报备ID不能为空") + private Long reportId; + + /** + * 进展内容 + */ + @NotBlank(message = "进展内容不能为空") + private String progressContent; +} diff --git a/backend/src/main/java/com/bycrm/entity/ReportProgress.java b/backend/src/main/java/com/bycrm/entity/ReportProgress.java new file mode 100644 index 0000000..960edd3 --- /dev/null +++ b/backend/src/main/java/com/bycrm/entity/ReportProgress.java @@ -0,0 +1,53 @@ +package com.bycrm.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 报备进展记录实体 + */ +@Data +public class ReportProgress implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 进展ID + */ + private Long id; + + /** + * 关联报备ID + */ + private Long reportId; + + /** + * 进展内容 + */ + private String progressContent; + + /** + * 创建人ID + */ + private Long createdBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdAt; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updatedAt; + + /** + * 关联查询字段 - 创建人姓名 + */ + private String creatorName; +} diff --git a/backend/src/main/java/com/bycrm/mapper/ReportProgressMapper.java b/backend/src/main/java/com/bycrm/mapper/ReportProgressMapper.java new file mode 100644 index 0000000..83cc3ce --- /dev/null +++ b/backend/src/main/java/com/bycrm/mapper/ReportProgressMapper.java @@ -0,0 +1,39 @@ +package com.bycrm.mapper; + +import com.bycrm.entity.ReportProgress; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 报备进展记录 Mapper + */ +@Mapper +public interface ReportProgressMapper { + + /** + * 根据ID查询进展记录 + */ + ReportProgress selectById(@Param("id") Long id); + + /** + * 根据报备ID查询进展记录列表 + */ + List selectByReportId(@Param("reportId") Long reportId); + + /** + * 插入进展记录 + */ + int insert(ReportProgress reportProgress); + + /** + * 更新进展记录 + */ + int update(ReportProgress reportProgress); + + /** + * 根据ID删除进展记录 + */ + int deleteById(@Param("id") Long id); +} diff --git a/backend/src/main/java/com/bycrm/service/ReportProgressService.java b/backend/src/main/java/com/bycrm/service/ReportProgressService.java new file mode 100644 index 0000000..2289ae6 --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/ReportProgressService.java @@ -0,0 +1,37 @@ +package com.bycrm.service; + +import com.bycrm.entity.ReportProgress; +import com.bycrm.dto.ReportProgressDTO; + +import java.util.List; + +/** + * 报备进展记录服务接口 + */ +public interface ReportProgressService { + + /** + * 根据报备ID获取进展记录列表 + */ + List getProgressByReportId(Long reportId); + + /** + * 根据ID获取进展记录 + */ + ReportProgress getProgressById(Long id); + + /** + * 创建进展记录 + */ + void createProgress(ReportProgressDTO progressDTO, Long currentUserId); + + /** + * 更新进展记录 + */ + void updateProgress(Long id, ReportProgressDTO progressDTO, Long currentUserId); + + /** + * 删除进展记录(不提供删除功能,根据需求不可删除) + */ + // void deleteProgress(Long id, Long currentUserId); +} diff --git a/backend/src/main/java/com/bycrm/service/impl/ReportProgressServiceImpl.java b/backend/src/main/java/com/bycrm/service/impl/ReportProgressServiceImpl.java new file mode 100644 index 0000000..643a3be --- /dev/null +++ b/backend/src/main/java/com/bycrm/service/impl/ReportProgressServiceImpl.java @@ -0,0 +1,119 @@ +package com.bycrm.service.impl; + +import com.bycrm.common.Constants; +import com.bycrm.dto.ReportProgressDTO; +import com.bycrm.entity.Report; +import com.bycrm.entity.ReportProgress; +import com.bycrm.entity.User; +import com.bycrm.exception.BusinessException; +import com.bycrm.mapper.ReportMapper; +import com.bycrm.mapper.ReportProgressMapper; +import com.bycrm.mapper.UserMapper; +import com.bycrm.service.ReportProgressService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 报备进展记录服务实现 + */ +@Service +public class ReportProgressServiceImpl implements ReportProgressService { + + private final ReportProgressMapper reportProgressMapper; + private final ReportMapper reportMapper; + private final UserMapper userMapper; + + public ReportProgressServiceImpl(ReportProgressMapper reportProgressMapper, + ReportMapper reportMapper, + UserMapper userMapper) { + this.reportProgressMapper = reportProgressMapper; + this.reportMapper = reportMapper; + this.userMapper = userMapper; + } + + @Override + public List getProgressByReportId(Long reportId) { + return reportProgressMapper.selectByReportId(reportId); + } + + @Override + public ReportProgress getProgressById(Long id) { + return reportProgressMapper.selectById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createProgress(ReportProgressDTO progressDTO, Long currentUserId) { + // 获取当前用户 + User currentUser = userMapper.selectById(currentUserId); + + // 检查报备是否存在 + Report report = reportMapper.selectById(progressDTO.getReportId()); + if (report == null) { + throw new BusinessException("报备不存在"); + } + + // 检查权限:经销商只能操作自己的报备 + if (currentUser.getRole() == Constants.USER_ROLE_DEALER) { + if (!report.getDealerId().equals(currentUser.getDealerId())) { + throw new BusinessException("您只能操作自己报备的进展记录"); + } + } + + // 检查报备状态是否为已通过 + if (report.getStatus() != Constants.REPORT_STATUS_APPROVED) { + throw new BusinessException("只有审核通过的报备才能添加进展记录"); + } + + // 创建进展记录 + ReportProgress progress = new ReportProgress(); + progress.setReportId(progressDTO.getReportId()); + progress.setProgressContent(progressDTO.getProgressContent()); + progress.setCreatedBy(currentUserId); + progress.setCreatedAt(LocalDateTime.now()); + progress.setUpdatedAt(LocalDateTime.now()); + + reportProgressMapper.insert(progress); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateProgress(Long id, ReportProgressDTO progressDTO, Long currentUserId) { + // 获取当前用户 + User currentUser = userMapper.selectById(currentUserId); + + // 检查进展记录是否存在 + ReportProgress existingProgress = reportProgressMapper.selectById(id); + if (existingProgress == null) { + throw new BusinessException("进展记录不存在"); + } + + // 检查报备是否存在 + Report report = reportMapper.selectById(existingProgress.getReportId()); + if (report == null) { + throw new BusinessException("关联的报备不存在"); + } + + // 检查权限:经销商只能操作自己的报备 + if (currentUser.getRole() == Constants.USER_ROLE_DEALER) { + if (!report.getDealerId().equals(currentUser.getDealerId())) { + throw new BusinessException("您只能操作自己报备的进展记录"); + } + } + + // 更新进展记录 + existingProgress.setProgressContent(progressDTO.getProgressContent()); + existingProgress.setUpdatedAt(LocalDateTime.now()); + + reportProgressMapper.update(existingProgress); + } + + // 根据需求,不提供删除功能 + // @Override + // public void deleteProgress(Long id, Long currentUserId) { + // throw new BusinessException("进展记录不可删除"); + // } +} diff --git a/backend/src/main/resources/mapper/ReportProgressMapper.xml b/backend/src/main/resources/mapper/ReportProgressMapper.xml new file mode 100644 index 0000000..5b2da6b --- /dev/null +++ b/backend/src/main/resources/mapper/ReportProgressMapper.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + id, report_id, progress_content, created_by, created_at, updated_at + + + + + + + + + + + INSERT INTO crm_report_progress ( + report_id, progress_content, created_by, created_at, updated_at + ) VALUES ( + #{reportId}, #{progressContent}, #{createdBy}, #{createdAt}, #{updatedAt} + ) + + + + + UPDATE crm_report_progress + SET + progress_content = #{progressContent}, + updated_at = #{updatedAt} + WHERE + id = #{id} + + + + + DELETE FROM crm_report_progress WHERE id = #{id} + + + diff --git a/frontend/src/api/report-progress.ts b/frontend/src/api/report-progress.ts new file mode 100644 index 0000000..8c784bb --- /dev/null +++ b/frontend/src/api/report-progress.ts @@ -0,0 +1,27 @@ +import { http } from '@/utils/request' +import type { ReportProgress, ReportProgressForm } from '@/types' + +// 根据报备ID获取进展记录列表 +export const getProgressByReportId = (reportId: number) => { + return http.get(`/report-progress/report/${reportId}`) +} + +// 根据ID获取进展记录 +export const getProgressById = (id: number) => { + return http.get(`/report-progress/${id}`) +} + +// 创建进展记录 +export const createProgress = (data: ReportProgressForm) => { + return http.post('/report-progress', data) +} + +// 更新进展记录 +export const updateProgress = (id: number, data: ReportProgressForm) => { + return http.put(`/report-progress/${id}`, data) +} + +// 删除进展记录(根据需求不可删除,所以不提供该接口) +// export const deleteProgress = (id: number) => { +// return http.delete(`/report-progress/${id}`) +// } diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 7e63ecd..5a6feff 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -104,6 +104,22 @@ export interface DictItem { value: string | number } +// 报备进展记录相关类型 +export interface ReportProgress { + id: number + reportId: number + progressContent: string + createdBy: number + creatorName?: string + createdAt: string + updatedAt: string +} + +export interface ReportProgressForm { + reportId: number + progressContent: string +} + // 系统配置相关类型 export interface SystemConfig { id: number diff --git a/frontend/src/views/Report.vue b/frontend/src/views/Report.vue index 6ca7067..6cb16c5 100644 --- a/frontend/src/views/Report.vue +++ b/frontend/src/views/Report.vue @@ -58,9 +58,17 @@ - + + + + + + + + + + + + + + + 进展记录列表 + + + + + + + + + + @@ -166,9 +219,10 @@ import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'elem import { useUserStore } from '@/stores/user' import zhCn from 'element-plus/dist/locale/zh-cn.mjs' import { getReportPage, createReport, auditReport, withdrawReport } from '@/api/report' +import { getProgressByReportId, createProgress, updateProgress } from '@/api/report-progress' import { searchCustomerByName } from '@/api/customer' import { getConfigValue } from '@/api/system' -import type { Report, ReportForm } from '@/types' +import type { Report, ReportForm, ReportProgress, ReportProgressForm } from '@/types' const userStore = useUserStore() @@ -184,6 +238,21 @@ const formRef = ref() const searchLoading = ref(false) const customerOptions = ref>([]) +// 进展记录相关 +const progressDialogVisible = ref(false) +const progressFormRef = ref() +const progressFormData = reactive({ + reportId: 0, + progressContent: '' +}) +const progressList = ref([]) +const editingProgressId = ref() +const progressLoading = ref(false) + +const progressRules: FormRules = { + progressContent: [{ required: true, message: '请输入进展内容', trigger: 'blur' }] +} + const queryForm = reactive({ current: 1, size: 10, @@ -211,6 +280,77 @@ const formatDate = (dateStr: string | null | undefined) => { return dateStr.split(' ')[0] // 只保留日期部分,去掉时间 } +// 显示进展记录对话框 +const handleShowProgress = async (row: Report) => { + progressFormData.reportId = row.id + progressFormData.progressContent = '' + editingProgressId.value = undefined + await fetchProgressList(row.id) + progressDialogVisible.value = true +} + +// 获取进展记录列表 +const fetchProgressList = async (reportId: number) => { + progressLoading.value = true + try { + const res = await getProgressByReportId(reportId) + progressList.value = res + } catch (error) { + console.error('获取进展记录失败', error) + progressList.value = [] + } finally { + progressLoading.value = false + } +} + +// 保存进展记录 +const handleSaveProgress = async () => { + if (!progressFormRef.value) return + await progressFormRef.value.validate(async (valid) => { + if (valid) { + try { + if (editingProgressId.value) { + // 编辑模式 + await updateProgress(editingProgressId.value, progressFormData) + ElMessage.success('更新成功') + } else { + // 新增模式 + await createProgress(progressFormData) + ElMessage.success('添加成功') + } + // 重新获取进展记录列表 + await fetchProgressList(progressFormData.reportId) + // 重置表单 + progressFormData.progressContent = '' + editingProgressId.value = undefined + } catch (error) { + console.error('保存进展记录失败', error) + } + } + }) +} + +// 编辑进展记录 +const handleEditProgress = (row: ReportProgress) => { + editingProgressId.value = row.id + progressFormData.progressContent = row.progressContent +} + +// 取消编辑 +const handleCancelEdit = () => { + editingProgressId.value = undefined + progressFormData.progressContent = '' +} + +// 关闭进展记录对话框 +const handleProgressDialogClose = () => { + progressDialogVisible.value = false + progressFormRef.value?.resetFields() + progressFormData.progressContent = '' + editingProgressId.value = undefined + progressList.value = [] +} + // 查询数据 const fetchData = async () => { loading.value = true diff --git a/sql/01_init.sql b/sql/01_init.sql index 8bc6d43..b3aadf6 100644 --- a/sql/01_init.sql +++ b/sql/01_init.sql @@ -174,3 +174,16 @@ CREATE TABLE IF NOT EXISTS crm_school ( INDEX idx_school_name (school_name), INDEX idx_location (location) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学校表'; + +-- 报备进展记录表 +CREATE TABLE IF NOT EXISTS crm_report_progress ( + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '进展ID', + report_id BIGINT NOT NULL COMMENT '关联报备ID', + progress_content VARCHAR(500) NOT NULL COMMENT '进展内容', + created_by BIGINT NOT NULL COMMENT '创建人ID', + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + INDEX idx_report_id (report_id), + INDEX idx_created_by (created_by), + INDEX idx_created_at (created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='报备进展记录表';