From 682ae26b69588c64a567658c0cbf99321c6d02cf Mon Sep 17 00:00:00 2001 From: bs32g1038 Date: Tue, 23 Apr 2024 23:20:03 +0800 Subject: [PATCH] chore: add tag curd --- .../jixialunbi/controllers/TagController.java | 54 +++++++++++- .../jixialunbi/dto/request/TagRequest.java | 25 ++++++ .../main/java/com/jixialunbi/model/Tag.java | 3 + .../jixialunbi/repository/TagRepository.java | 4 + web/components/Modal/index.module.scss | 48 +++++----- .../setting/components/EditModal/index.tsx | 76 ++++++++++++++++ web/components/setting/index.module.scss | 23 +++++ web/components/setting/index.tsx | 87 +++++++++++++++++-- 8 files changed, 287 insertions(+), 33 deletions(-) create mode 100644 server/src/main/java/com/jixialunbi/dto/request/TagRequest.java create mode 100644 web/components/setting/components/EditModal/index.tsx create mode 100644 web/components/setting/index.module.scss diff --git a/server/src/main/java/com/jixialunbi/controllers/TagController.java b/server/src/main/java/com/jixialunbi/controllers/TagController.java index 3a56754..58fdbd7 100644 --- a/server/src/main/java/com/jixialunbi/controllers/TagController.java +++ b/server/src/main/java/com/jixialunbi/controllers/TagController.java @@ -1,12 +1,26 @@ package com.jixialunbi.controllers; import com.jixialunbi.common.R; +import com.jixialunbi.dto.request.CommentRequest; +import com.jixialunbi.dto.request.IdRequest; +import com.jixialunbi.dto.request.TagRequest; +import com.jixialunbi.model.Comment; +import com.jixialunbi.model.Post; +import com.jixialunbi.model.Tag; +import com.jixialunbi.model.User; import com.jixialunbi.repository.TagRepository; +import com.jixialunbi.security.UserDetailsImpl; +import com.jixialunbi.service.UserService; +import jakarta.transaction.Transactional; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; +import java.time.LocalDateTime; +import java.util.Optional; @RestController @@ -16,6 +30,9 @@ public class TagController { @Autowired TagRepository tagRepository; + @Autowired + UserService userService; + @GetMapping("/tags") public R fetchTags(@RequestParam(required = false, defaultValue = "1") int page, @RequestParam(required = false, defaultValue = "10") int pageSize) { try { @@ -25,4 +42,33 @@ public R fetchTags(@RequestParam(required = false, defaultValue = "1") int page, } } + @PreAuthorize("hasRole('ROLE_USER')") + @PostMapping("/tags/create") + public R createTag(@Valid @RequestBody TagRequest tagRequest) { + var tag = new Tag(); + tag.setName(tagRequest.getName().trim()); + tag.setDescription(tagRequest.getDescription().trim()); +// tag.setOrder(tagRequest.getOrder()); + return R.ok().data(tagRepository.save(tag)); + } + + @PreAuthorize("hasRole('ROLE_USER')") + @PostMapping("/tags/update") + public R updateTag(@Valid @RequestBody TagRequest tagRequest) { + Tag tag = tagRepository.findById(tagRequest.getId()).get(); + if(tag != null){ + tag.setName(tagRequest.getName().trim()); + tag.setDescription(tagRequest.getDescription().trim()); + } + return R.ok().data(tagRepository.save(tag)); + } + + @PreAuthorize("hasRole('ROLE_USER')") + @PostMapping("/delete-tag") + @Transactional + public R deleteTags(@Valid @RequestBody IdRequest idRequest) { + tagRepository.deleteById(idRequest.getId()); + return R.ok().data(true); + } + } \ No newline at end of file diff --git a/server/src/main/java/com/jixialunbi/dto/request/TagRequest.java b/server/src/main/java/com/jixialunbi/dto/request/TagRequest.java new file mode 100644 index 0000000..c83e988 --- /dev/null +++ b/server/src/main/java/com/jixialunbi/dto/request/TagRequest.java @@ -0,0 +1,25 @@ +package com.jixialunbi.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * Data Transfer Object for Profile request + */ +@Data +public class TagRequest { + + private Long id; + + @NotBlank + @Size(max = 20) + private String name; + + private long order; + + @Size(max = 200) + private String description; + +} diff --git a/server/src/main/java/com/jixialunbi/model/Tag.java b/server/src/main/java/com/jixialunbi/model/Tag.java index 7547314..e52519d 100644 --- a/server/src/main/java/com/jixialunbi/model/Tag.java +++ b/server/src/main/java/com/jixialunbi/model/Tag.java @@ -24,6 +24,9 @@ public class Tag { @Column(name = "description") private String description; +// @Column(name = "order") +// private Long order; + @ManyToMany(mappedBy = "tags") private List posts = new ArrayList<>(); diff --git a/server/src/main/java/com/jixialunbi/repository/TagRepository.java b/server/src/main/java/com/jixialunbi/repository/TagRepository.java index 168f318..34a1ec3 100644 --- a/server/src/main/java/com/jixialunbi/repository/TagRepository.java +++ b/server/src/main/java/com/jixialunbi/repository/TagRepository.java @@ -3,7 +3,11 @@ import com.jixialunbi.model.Tag; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface TagRepository extends JpaRepository { + Optional findById(Long id); + } \ No newline at end of file diff --git a/web/components/Modal/index.module.scss b/web/components/Modal/index.module.scss index dd5193e..bd7655e 100644 --- a/web/components/Modal/index.module.scss +++ b/web/components/Modal/index.module.scss @@ -1,27 +1,27 @@ -.default { - :global { - .ant-modal-header { - padding: 7px 24px; - color: rgba(0, 0, 0, 0.85); - background: #fff; - border-bottom: 1px solid #f0f0f0; - border-radius: 2px 2px 0 0; - } +// .default { +// :global { +// .ant-modal-header { +// // padding: 7px 24px; +// // color: rgba(0, 0, 0, 0.85); +// // background: #fff; +// // border-bottom: 1px solid #f0f0f0; +// // border-radius: 2px 2px 0 0; +// } - .ant-modal-close { - top: 22px; - } +// .ant-modal-close { +// top: 22px; +// } - .ant-modal-body { - padding: 0; - } +// .ant-modal-body { +// // padding: 0; +// } - .ant-modal-footer { - .ant-btn { - height: 24px; - padding-top: 0; - padding-bottom: 0; - } - } - } -} +// .ant-modal-footer { +// // .ant-btn { +// // height: 24px; +// // padding-top: 0; +// // padding-bottom: 0; +// // } +// } +// } +// } diff --git a/web/components/setting/components/EditModal/index.tsx b/web/components/setting/components/EditModal/index.tsx new file mode 100644 index 0000000..9fac062 --- /dev/null +++ b/web/components/setting/components/EditModal/index.tsx @@ -0,0 +1,76 @@ +import { Form, Input, InputNumber, message } from 'antd'; +import { useForm } from 'antd/lib/form/Form'; +import { noop } from 'lodash'; +import React, { useEffect } from 'react'; +import Modal from '@/components/Modal'; +import { useSWRMutation } from '@/hooks'; + +interface Props { + visible: boolean; + onOk?: () => void; + onCancel?: () => void; + data?: any; +} + +export default function EditModal(props: Props) { + const { visible, onOk = noop, onCancel, data } = props; + const [form] = useForm(); + const { trigger: createCategory, isMutating: createIsMutating } = useSWRMutation({ url: '/api/v1/tags/create' }); + const { trigger: updateCategory } = useSWRMutation({ url: '/api/v1/tags/update' }); + const onFinish = (values: any) => { + form.validateFields().then(async () => { + if (data) { + await updateCategory({ ...data, ...values }).then(() => { + message.success('更新成功'); + }); + } else { + await createCategory({ ...values, order: 0 }).then(() => { + message.success('提交成功'); + }); + } + await onOk(); + }); + }; + const onFinishFailed = (errorInfo: any) => { + console.log('Failed:', errorInfo); + }; + useEffect(() => { + if (data && form) { + form.setFieldsValue(data); + } + }, [data, form]); + return ( + { + form.submit(); + onOk(); + }} + onCancel={onCancel} + > +
+ + + + + + + + + +
+
+ ); +} diff --git a/web/components/setting/index.module.scss b/web/components/setting/index.module.scss new file mode 100644 index 0000000..a1453a1 --- /dev/null +++ b/web/components/setting/index.module.scss @@ -0,0 +1,23 @@ +.wrap { + padding-top: 15px; +} + +.title { + margin-bottom: 15px; +} + +.labels { + display: flex; + align-items: center; + flex-wrap: wrap; + button { + padding: 0; + } +} + +.labelsItem { + display: flex; + align-items: center; + gap: 10px; + margin-right: 20px; +} diff --git a/web/components/setting/index.tsx b/web/components/setting/index.tsx index 52f7d3f..7822640 100644 --- a/web/components/setting/index.tsx +++ b/web/components/setting/index.tsx @@ -1,15 +1,92 @@ 'use client'; -import TagGroup from '@/components/TagGroup'; -import { Form } from 'antd'; +import { Button, Spin, Space, Popconfirm } from 'antd'; import Layout from '../Layout'; +import styles from './index.module.scss'; +import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { useSWR, useSWRMutation } from '@/hooks'; +import EditModal from './components/EditModal'; +import { useState } from 'react'; export default function Setting() { + const { data, isLoading, mutate } = useSWR({ url: '/api/v1/tags' }); + const { trigger: deleteTag, isMutating: delIsMutating } = useSWRMutation({ url: '/api/v1/delete-tag' }); + const tags = data?.data ?? []; + const [editData, setEditData] = useState({ visible: false, data: {} }); return ( - - - +
+
标签管理
+ +
+ {tags.map((item) => { + return ( +
+
{item.name}
+ + + { + await deleteTag({ id: item.id } as any).then(() => { + mutate(); + }); + }} + > + + + +
+ ); + })} + + {editData.visible && ( + { + setEditData({ + visible: false, + data: null, + }); + }} + onOk={() => { + mutate(); + setEditData({ + visible: false, + data: null, + }); + }} + > + )} +
+
+
); }