补充删除

This commit is contained in:
yumaojun03 2025-01-12 18:31:26 +08:00
parent d578bdcba2
commit 5f3ea8c6c9
11 changed files with 270 additions and 10 deletions

View File

@ -3,6 +3,7 @@ package impl
import (
"context"
"fmt"
"time"
"github.com/infraboard/mcube/v2/ioc"
"github.com/infraboard/mcube/v2/ioc/config/datasource"
@ -26,7 +27,7 @@ func (i *BlogServiceImpl) Name() string {
// CreateBlog implements blog.Service.
func (b *BlogServiceImpl) CreateBlog(ctx context.Context, in *blog.CreateBlogRequest) (*blog.Blog, error) {
ins, err := blog.NewBook(in)
ins, err := blog.NewBlog(in)
if err != nil {
return nil, err
}
@ -77,13 +78,23 @@ func (b *BlogServiceImpl) QueryBlog(ctx context.Context, in *blog.QueryBlogReque
}
// DeleteBlog implements blog.Service.
func (b *BlogServiceImpl) DeleteBlog(context.Context, *blog.DeleteBlogRequest) error {
panic("unimplemented")
func (b *BlogServiceImpl) DeleteBlog(ctx context.Context, in *blog.DeleteBlogRequest) error {
time.Sleep(3 * time.Second)
ins, err := b.DescribeBlog(ctx, blog.NewDescribeBlogRequest(in.Id))
if err != nil {
return err
}
return datasource.DBFromCtx(ctx).Where("id = ?", ins.Id).Delete(ins).Error
}
// DescribeBlog implements blog.Service.
func (b *BlogServiceImpl) DescribeBlog(context.Context, *blog.DescribeBlogRequest) (*blog.Blog, error) {
panic("unimplemented")
func (b *BlogServiceImpl) DescribeBlog(ctx context.Context, in *blog.DescribeBlogRequest) (*blog.Blog, error) {
ins := &blog.Blog{}
err := datasource.DBFromCtx(ctx).Where("id = ?", in.Id).First(ins).Error
if err != nil {
return nil, err
}
return ins, nil
}
// PublishBlog implements blog.Service.

View File

@ -63,6 +63,12 @@ type UpdateBlogRequest struct {
CreateBlogRequest
}
func NewDescribeBlogRequest(id uint) *DescribeBlogRequest {
return &DescribeBlogRequest{
GetRequest: *utils.NewGetRequest(id),
}
}
type DescribeBlogRequest struct {
utils.GetRequest
}

View File

@ -20,7 +20,7 @@ type BlogSet struct {
Items []*Blog `json:"items"`
}
func NewBook(in *CreateBlogRequest) (*Blog, error) {
func NewBlog(in *CreateBlogRequest) (*Blog, error) {
if err := in.Validate(); err != nil {
return nil, exception.NewBadRequest("参数异常: %s", err)
}

View File

@ -1,7 +1,7 @@
[app]
name = "vblog"
description = "app desc"
address = "http://127.0.0.1"
address = "http://localhost/"
[http]
# HTTP服务Host

View File

@ -246,3 +246,80 @@
{"level":"info","component":"server","time":"2025-01-12T14:57:03+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T14:57:03+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T14:57:03+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"info","component":"server","time":"2025-01-12T17:22:29+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T17:22:29+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T17:22:29+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T17:22:29+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T17:22:32+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T17:22:32+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T17:22:32+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T17:22:32+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T17:22:32+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T17:22:32+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T17:22:32+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"debug","time":"2025-01-12T17:32:36+08:00","caller":"token/api/api.go:57","message":"cookie domain: 127.0.0.1"}
{"level":"error","time":"2025-01-12T18:05:41+08:00","caller":"vblog/middleware/auth.go:36","message":"get cookie error, http: named cookie not present"}
{"level":"error","time":"2025-01-12T18:05:49+08:00","caller":"vblog/middleware/auth.go:36","message":"get cookie error, http: named cookie not present"}
{"level":"info","component":"server","time":"2025-01-12T18:06:23+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:06:23+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:06:23+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:06:23+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T18:06:26+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T18:06:26+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T18:06:26+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:06:26+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:06:26+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:06:26+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T18:06:26+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"error","time":"2025-01-12T18:06:48+08:00","caller":"vblog/middleware/auth.go:36","message":"get cookie error, http: named cookie not present"}
{"level":"debug","time":"2025-01-12T18:07:57+08:00","caller":"token/api/api.go:57","message":"cookie domain: 127.0.0.1"}
{"level":"error","time":"2025-01-12T18:08:03+08:00","caller":"vblog/middleware/auth.go:36","message":"get cookie error, http: named cookie not present"}
{"level":"info","component":"server","time":"2025-01-12T18:11:49+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:11:49+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:11:49+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:11:49+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T18:11:51+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T18:11:51+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T18:11:51+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:11:51+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:11:51+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:11:51+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T18:11:51+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"debug","time":"2025-01-12T18:12:03+08:00","caller":"token/api/api.go:57","message":"cookie domain: localhost"}
{"level":"info","component":"server","time":"2025-01-12T18:17:07+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:17:07+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:17:07+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:17:07+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T18:17:10+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T18:17:10+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T18:17:10+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:17:10+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:17:10+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:17:10+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T18:17:10+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"info","component":"server","time":"2025-01-12T18:19:23+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:19:23+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:19:23+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:19:23+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T18:19:25+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T18:19:25+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T18:19:25+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:19:25+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:19:25+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:19:25+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T18:19:25+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"info","component":"server","time":"2025-01-12T18:27:47+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:27:47+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:27:47+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:27:47+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}
{"level":"info","component":"gin_webframework","time":"2025-01-12T18:27:51+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"}
{"level":"debug","time":"2025-01-12T18:27:51+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"}
{"level":"info","component":"server","time":"2025-01-12T18:27:51+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:27:51+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:27:51+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"}
{"level":"info","component":"server","time":"2025-01-12T18:27:51+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"}
{"level":"info","component":"http","time":"2025-01-12T18:27:51+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"}
{"level":"info","component":"server","time":"2025-01-12T18:30:18+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"}
{"level":"info","component":"http","time":"2025-01-12T18:30:18+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"}
{"level":"error","component":"http","time":"2025-01-12T18:30:18+08:00","caller":"config/http/http.go:146","message":"http: Server closed"}
{"level":"info","component":"server","time":"2025-01-12T18:30:18+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"}

View File

@ -1,5 +1,11 @@
package utils
func NewGetRequest(id uint) *GetRequest {
return &GetRequest{
Id: id,
}
}
type GetRequest struct {
Id uint `json:"id"`
}

View File

@ -444,3 +444,127 @@ const pageSizeChanged = (pageSize) => {
queryData()
}
```
## Menu状态保存
```js
import { useStorage } from '@vueuse/core'
export const systemConfig = useStorage(
'system_config',
{
selected_current_menu_item_key: '',
},
localStorage,
{
mergeDefaults: true,
},
)
```
点击时,保存这个状态
```js
const handleMenuItemClick = (key) => {
// https://router.vuejs.org/zh/guide/essentials/navigation.html
router.push({ name: key })
systemConfig.value.selected_current_menu_item_key = key
}
```
```html
<a-menu
@menu-item-click="handleMenuItemClick"
breakpoint="xl"
:default-selected-keys="[systemConfig.selected_current_menu_item_key]"
auto-open
>
</a-menu>
```
## 文章删除
1. 准备好你的后端接口:
```go
// DeleteBlog implements blog.Service.
func (b *BlogServiceImpl) DeleteBlog(ctx context.Context, in *blog.DeleteBlogRequest) error {
ins, err := b.DescribeBlog(ctx, blog.NewDescribeBlogRequest(in.Id))
if err != nil {
return err
}
return datasource.DBFromCtx(ctx).Where("id = ?", ins.Id).Delete(ins).Error
}
// DescribeBlog implements blog.Service.
func (b *BlogServiceImpl) DescribeBlog(ctx context.Context, in *blog.DescribeBlogRequest) (*blog.Blog, error) {
ins := &blog.Blog{}
err := datasource.DBFromCtx(ctx).Where("id = ?", in.Id).First(ins).Error
if err != nil {
return nil, err
}
return ins, nil
}
```
```go
r.DELETE(":id", h.DeleteBlog)
func (h *BlogApiHandler) DeleteBlog(ctx *gin.Context) {
in := blog.NewDeleteBlogRequest(ctx.Param("id"))
err := h.blog.DeleteBlog(ctx.Request.Context(), in)
if err != nil {
response.Failed(ctx, err)
return
}
response.Success(ctx, "ok")
}
```
2. SetCookie的问题: localhost
```go
// 打印下日志, ioc
domain := application.Get().Domain()
log.L().Debug().Msgf("cookie domain: %s", domain)
// 设置Cookie
ctx.SetCookie(token.COOKIE_NAME, ins.AccessToken, ins.AccessTokenExpireTTL(), "/", domain, false, true)
```
```toml
[app]
name = "vblog"
description = "app desc"
address = "http://localhost/"
```
3. 调用API, 实现删除, 刷新页面(2个操作的先后关系)
```js
// 删除函数
const delteLoadding = ref(0)
const deleteBlog = async (id) => {
try {
delteLoadding.value = id
// 等待这个操作执行完成
await DELTE_BLOG(id)
// 刷新数据
queryData()
} finally {
delteLoadding.value = 0
}
}
```
4. 删除按钮Loadding控制:
```html
<a-button :loading="delteLoadding === record.id" status="danger" @click="deleteBlog(record.id)">
<template #icon>
<icon-delete />
</template>
删除
</a-button>
```

View File

@ -10,3 +10,9 @@ export const QUERY_BLOG = (params) =>
// params: params
params,
})
export const DELTE_BLOG = (blog_id) =>
client({
url: `/api/vblog/v1/blogs/${blog_id}`,
method: 'DELETE',
})

View File

@ -0,0 +1,12 @@
import { useStorage } from '@vueuse/core'
export const systemConfig = useStorage(
'system_config',
{
selected_current_menu_item_key: '',
},
localStorage,
{
mergeDefaults: true,
},
)

View File

@ -17,7 +17,8 @@
<a-layout class="body">
<!-- 侧边栏 -->
<a-layout-sider :width="260" collapsible breakpoint="xl">
<a-menu @menu-item-click="handleMenuItemClick" breakpoint="xl">
<a-menu @menu-item-click="handleMenuItemClick" breakpoint="xl"
:default-selected-keys="[systemConfig.selected_current_menu_item_key]" auto-open>
<a-sub-menu key="blog">
<template #title>
<span>
@ -49,6 +50,7 @@
import { token } from '@/stores/token';
import { useRouter } from 'vue-router';
import { systemConfig } from '@/stores/system';
const router = useRouter()
@ -56,6 +58,7 @@ const router = useRouter()
const handleMenuItemClick = (key) => {
// https://router.vuejs.org/zh/guide/essentials/navigation.html
router.push({ name: key })
systemConfig.value.selected_current_menu_item_key = key
}
const logout = () => {
// Logout, 退

View File

@ -55,7 +55,7 @@
</template>
发布
</a-button>
<a-button status="danger" @click="$modal.info({ title: 'Name', content: record.id })">
<a-button :loading="delteLoadding === record.id" status="danger" @click="deleteBlog(record.id)">
<template #icon>
<icon-delete />
</template>
@ -78,7 +78,7 @@
<script setup>
import { onMounted, reactive, ref } from 'vue';
import { QUERY_BLOG } from '@/api/blog'
import { QUERY_BLOG, DELTE_BLOG } from '@/api/blog'
import dayjs from 'dayjs'
// API
@ -92,6 +92,7 @@ const blogQueryRequest = reactive({
// ref data.value = {}
const data = ref({})
//
const queryBlogLoadding = ref(false)
const queryData = async () => {
try {
@ -102,6 +103,20 @@ const queryData = async () => {
}
}
//
const delteLoadding = ref(0)
const deleteBlog = async (id) => {
try {
delteLoadding.value = id
//
await DELTE_BLOG(id)
//
queryData()
} finally {
delteLoadding.value = 0
}
}
// API, ,
onMounted(() => {
queryData()