diff --git a/backend/src/main/java/com/zl/mjga/controller/AiController.java b/backend/src/main/java/com/zl/mjga/controller/AiController.java index b95d5fd..e1fe2c9 100644 --- a/backend/src/main/java/com/zl/mjga/controller/AiController.java +++ b/backend/src/main/java/com/zl/mjga/controller/AiController.java @@ -5,6 +5,8 @@ import com.zl.mjga.dto.PageResponseDto; import com.zl.mjga.dto.ai.LlmQueryDto; import com.zl.mjga.dto.ai.LlmVm; import com.zl.mjga.exception.BusinessException; +import com.zl.mjga.repository.DepartmentRepository; +import com.zl.mjga.repository.UserRepository; import com.zl.mjga.service.AiChatService; import com.zl.mjga.service.EmbeddingService; import com.zl.mjga.service.LlmService; @@ -16,8 +18,11 @@ import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.jooq.generated.mjga.enums.LlmCodeEnum; import org.jooq.generated.mjga.tables.pojos.AiLlmConfig; +import org.jooq.generated.mjga.tables.pojos.Department; +import org.jooq.generated.mjga.tables.pojos.User; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; @@ -34,6 +39,8 @@ public class AiController { private final AiChatService aiChatService; private final LlmService llmService; private final EmbeddingService embeddingService; + private final UserRepository userRepository; + private final DepartmentRepository departmentRepository; @PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux chat(Principal principal, @RequestBody String userMessage) { @@ -72,4 +79,27 @@ public class AiController { } return embeddingService.searchAction(message); } + + @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)") + @DeleteMapping("/action/user") + void deleteUser(@RequestParam String username, Principal principal) { + if (StringUtils.equals(username, principal.getName())) { + throw new BusinessException("不能删除当前登录用户"); + } + User fetched = userRepository.fetchOneByUsername(username); + if (fetched == null) { + throw new BusinessException("该用户不存在"); + } + userRepository.deleteByUsername(username); + } + + @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)") + @DeleteMapping("/action/department") + void deleteDepartment(@RequestParam String name) { + Department department = departmentRepository.fetchOneByName(name); + if (department == null) { + throw new BusinessException("该部门不存在"); + } + departmentRepository.deleteByName(name); + } } diff --git a/backend/src/main/java/com/zl/mjga/controller/IdentityAccessController.java b/backend/src/main/java/com/zl/mjga/controller/IdentityAccessController.java index 12fe4cd..0e381ff 100644 --- a/backend/src/main/java/com/zl/mjga/controller/IdentityAccessController.java +++ b/backend/src/main/java/com/zl/mjga/controller/IdentityAccessController.java @@ -63,7 +63,7 @@ public class IdentityAccessController { return identityAccessService.queryUniqueUserWithRolePermission(userId); } - @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).DELETE_USER_ROLE_PERMISSION)") + @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)") @DeleteMapping("/user") void deleteUser(@RequestParam Long userId) { if (userId == 1) { diff --git a/backend/src/main/java/com/zl/mjga/model/urp/Actions.java b/backend/src/main/java/com/zl/mjga/model/urp/Actions.java index d96014f..2fce6b8 100644 --- a/backend/src/main/java/com/zl/mjga/model/urp/Actions.java +++ b/backend/src/main/java/com/zl/mjga/model/urp/Actions.java @@ -7,7 +7,9 @@ import lombok.Getter; @Getter public enum Actions { CREATE_USER("CREATE_USER", "创建用户"), - CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"); + CREATE_DEPARTMENT("CREATE_DEPARTMENT", "创建部门"), + DELETE_USER("DELETE_USER", "删除用户"), + DELETE_DEPARTMENT("DELETE_DEPARTMENT", "删除部门"); public static final String INDEX_KEY = "action"; private final String code; private final String content; diff --git a/backend/src/main/java/com/zl/mjga/repository/DepartmentRepository.java b/backend/src/main/java/com/zl/mjga/repository/DepartmentRepository.java index 341f9fa..53005ba 100644 --- a/backend/src/main/java/com/zl/mjga/repository/DepartmentRepository.java +++ b/backend/src/main/java/com/zl/mjga/repository/DepartmentRepository.java @@ -15,6 +15,7 @@ import org.jooq.generated.mjga.tables.daos.DepartmentDao; import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository public class DepartmentRepository extends DepartmentDao { @@ -95,4 +96,9 @@ public class DepartmentRepository extends DepartmentDao { .innerJoin(USER.department()) .where(USER.ID.eq(userId)); } + + @Transactional + public void deleteByName(String name) { + ctx().deleteFrom(DEPARTMENT).where(DEPARTMENT.NAME.eq(name)).execute(); + } } diff --git a/backend/src/main/java/com/zl/mjga/repository/LlmRepository.java b/backend/src/main/java/com/zl/mjga/repository/LlmRepository.java index b0b4d61..ff23bde 100644 --- a/backend/src/main/java/com/zl/mjga/repository/LlmRepository.java +++ b/backend/src/main/java/com/zl/mjga/repository/LlmRepository.java @@ -26,8 +26,7 @@ public class LlmRepository extends AiLlmConfigDao { public Result pageFetchBy(PageRequestDto pageRequestDto, LlmQueryDto llmQueryDto) { return ctx() .select( - AI_LLM_CONFIG.asterisk(), - DSL.count().over().as("total_llm").convertFrom(Long::valueOf)) + AI_LLM_CONFIG.asterisk(), DSL.count().over().as("total_llm").convertFrom(Long::valueOf)) .from(AI_LLM_CONFIG) .where( StringUtils.isNotEmpty(llmQueryDto.name()) diff --git a/backend/src/main/java/com/zl/mjga/service/EmbeddingService.java b/backend/src/main/java/com/zl/mjga/service/EmbeddingService.java index 068699b..8967838 100644 --- a/backend/src/main/java/com/zl/mjga/service/EmbeddingService.java +++ b/backend/src/main/java/com/zl/mjga/service/EmbeddingService.java @@ -35,7 +35,7 @@ public class EmbeddingService { EmbeddingSearchRequest embeddingSearchRequest = EmbeddingSearchRequest.builder() .queryEmbedding(zhipuEmbeddingModel.embed(message).content()) - .minScore(0.89) + .minScore(0.89) .build(); EmbeddingSearchResult embeddingSearchResult = zhiPuEmbeddingStore.search(embeddingSearchRequest); diff --git a/backend/src/main/java/com/zl/mjga/service/LlmService.java b/backend/src/main/java/com/zl/mjga/service/LlmService.java index b2613a2..56eb932 100644 --- a/backend/src/main/java/com/zl/mjga/service/LlmService.java +++ b/backend/src/main/java/com/zl/mjga/service/LlmService.java @@ -1,5 +1,7 @@ package com.zl.mjga.service; +import static org.jooq.generated.mjga.Tables.AI_LLM_CONFIG; + import com.zl.mjga.dto.PageRequestDto; import com.zl.mjga.dto.PageResponseDto; import com.zl.mjga.dto.ai.LlmQueryDto; @@ -18,8 +20,6 @@ import org.jooq.generated.mjga.tables.pojos.AiLlmConfig; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; -import static org.jooq.generated.mjga.Tables.AI_LLM_CONFIG; - @Service @RequiredArgsConstructor @Slf4j @@ -44,11 +44,13 @@ public class LlmService { if (records.isEmpty()) { return PageResponseDto.empty(); } - List llmVms = records.map((record) -> { - LlmVm into = record.into(LlmVm.class); - into.setType(record.get(AI_LLM_CONFIG.TYPE).getLiteral()); - return into; - }); + List llmVms = + records.map( + (record) -> { + LlmVm into = record.into(LlmVm.class); + into.setType(record.get(AI_LLM_CONFIG.TYPE).getLiteral()); + return into; + }); Long totalLlm = records.get(0).getValue("total_llm", Long.class); return new PageResponseDto<>(totalLlm, llmVms); } diff --git a/frontend/src/api/schema/openapi.json b/frontend/src/api/schema/openapi.json index b53b6ec..3eb5b25 100644 --- a/frontend/src/api/schema/openapi.json +++ b/frontend/src/api/schema/openapi.json @@ -1102,6 +1102,52 @@ } } } + }, + "/ai/action/user": { + "delete": { + "tags": [ + "ai-controller" + ], + "operationId": "deleteUser_1", + "parameters": [ + { + "name": "username", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/ai/action/department": { + "delete": { + "tags": [ + "ai-controller" + ], + "operationId": "deleteDepartment_1", + "parameters": [ + { + "name": "name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } } }, "components": { diff --git a/frontend/src/api/types/schema.d.ts b/frontend/src/api/types/schema.d.ts index 5142735..df74447 100644 --- a/frontend/src/api/types/schema.d.ts +++ b/frontend/src/api/types/schema.d.ts @@ -532,6 +532,38 @@ export interface paths { patch?: never; trace?: never; }; + "/ai/action/user": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations["deleteUser_1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/ai/action/department": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations["deleteDepartment_1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { @@ -1693,4 +1725,44 @@ export interface operations { }; }; }; + deleteUser_1: { + parameters: { + query: { + username: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteDepartment_1: { + parameters: { + query: { + name: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; } diff --git a/frontend/src/components/InputButton.vue b/frontend/src/components/InputButton.vue new file mode 100644 index 0000000..0c49a54 --- /dev/null +++ b/frontend/src/components/InputButton.vue @@ -0,0 +1,51 @@ + + + diff --git a/frontend/src/components/PopupModal.vue b/frontend/src/components/PopupModal.vue index 4731ef8..949a437 100644 --- a/frontend/src/components/PopupModal.vue +++ b/frontend/src/components/PopupModal.vue @@ -43,7 +43,7 @@ defineProps<{ title: string; id: string; closeModal: () => void; - onSubmit: (event: Event) => Promise; + onSubmit: () => Promise; }>(); onMounted(() => { diff --git a/frontend/src/composables/ai/useAiAction.ts b/frontend/src/composables/ai/useAiAction.ts new file mode 100644 index 0000000..5606f3f --- /dev/null +++ b/frontend/src/composables/ai/useAiAction.ts @@ -0,0 +1,28 @@ +import client from "../../api/client"; + +export const useAiAction = () => { + const deleteUserByUsername = async (username: string) => { + await client.DELETE("/ai/action/user", { + params: { + query: { + username, + }, + }, + }); + }; + + const deleteDepartmentByName = async (name: string) => { + await client.DELETE("/ai/action/department", { + params: { + query: { + name, + }, + }, + }); + }; + + return { + deleteUserByUsername, + deleteDepartmentByName, + }; +}; diff --git a/frontend/src/views/AiChatView.vue b/frontend/src/views/AiChatView.vue index bed167e..8eda9d9 100644 --- a/frontend/src/views/AiChatView.vue +++ b/frontend/src/views/AiChatView.vue @@ -17,12 +17,21 @@
- + + @@ -54,6 +63,24 @@ 帮我创建用户? + +