Skip to content

Commit

Permalink
chore: add tag curd
Browse files Browse the repository at this point in the history
  • Loading branch information
bs32g1038 committed Apr 23, 2024
1 parent e4654e1 commit 682ae26
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 33 deletions.
54 changes: 50 additions & 4 deletions server/src/main/java/com/jixialunbi/controllers/TagController.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 {
Expand All @@ -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);
}

}
25 changes: 25 additions & 0 deletions server/src/main/java/com/jixialunbi/dto/request/TagRequest.java
Original file line number Diff line number Diff line change
@@ -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;

}
3 changes: 3 additions & 0 deletions server/src/main/java/com/jixialunbi/model/Tag.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class Tag {
@Column(name = "description")
private String description;

// @Column(name = "order")
// private Long order;

@ManyToMany(mappedBy = "tags")
private List<Post> posts = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Tag, Long> {

Optional<Tag> findById(Long id);

}
48 changes: 24 additions & 24 deletions web/components/Modal/index.module.scss
Original file line number Diff line number Diff line change
@@ -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;
// // }
// }
// }
// }
76 changes: 76 additions & 0 deletions web/components/setting/components/EditModal/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Modal
title={data ? '编辑标签' : '添加标签'}
open={visible}
width={420}
confirmLoading={createIsMutating}
onOk={() => {
form.submit();
onOk();
}}
onCancel={onCancel}
>
<Form
form={form}
name="basic"
labelCol={{ span: 4 }}
wrapperCol={{ span: 20 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item label="名称" name="name" rules={[{ required: true, message: '请输入' }]}>
<Input placeholder="请输入" />
</Form.Item>
<Form.Item label="顺序" name="order">
<InputNumber placeholder="请输入" min={0} max={50} />
</Form.Item>
<Form.Item label="描述" name="description" rules={[{ message: '请输入' }]} style={{ marginBottom: 0 }}>
<Input.TextArea placeholder="请输入" />
</Form.Item>
</Form>
</Modal>
);
}
23 changes: 23 additions & 0 deletions web/components/setting/index.module.scss
Original file line number Diff line number Diff line change
@@ -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;
}
87 changes: 82 additions & 5 deletions web/components/setting/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Layout>
<Form.Item>
<TagGroup></TagGroup>
</Form.Item>
<div className={styles.wrap}>
<div className={styles.title}>标签管理</div>
<Spin tip="Loading" size="small" spinning={isLoading}>
<div className={styles.labels}>
{tags.map((item) => {
return (
<div className={styles.labelsItem} key={item.id}>
<div>{item.name}</div>
<Space>
<Button
type="link"
onClick={() => {
setEditData({
visible: true,
data: item,
});
}}
>
<EditOutlined></EditOutlined>
编辑
</Button>
<Popconfirm
title="是否删除该标签?"
onConfirm={async () => {
await deleteTag({ id: item.id } as any).then(() => {
mutate();
});
}}
>
<Button type="link" danger loading={delIsMutating}>
<DeleteOutlined></DeleteOutlined>
删除
</Button>
</Popconfirm>
</Space>
</div>
);
})}
<Button
type="link"
size="small"
onClick={() =>
setEditData({
visible: true,
data: null,
})
}
>
<PlusOutlined></PlusOutlined>添加标签
</Button>
{editData.visible && (
<EditModal
visible={editData.visible}
data={editData.data}
onCancel={() => {
setEditData({
visible: false,
data: null,
});
}}
onOk={() => {
mutate();
setEditData({
visible: false,
data: null,
});
}}
></EditModal>
)}
</div>
</Spin>
</div>
</Layout>
);
}

0 comments on commit 682ae26

Please sign in to comment.