Skip to content

Commit

Permalink
fix: 完善图片管理
Browse files Browse the repository at this point in the history
  • Loading branch information
besscroft committed Apr 16, 2024
1 parent d6454bc commit c281ed8
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 17 deletions.
9 changes: 9 additions & 0 deletions app/api/v1/image-update/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'server-only'
import { updateImage } from '~/server/lib/operate'
import { NextRequest } from 'next/server'

export async function PUT(req: NextRequest) {
const image = await req.json()
const data = await updateImage(image);
return Response.json(data)
}
116 changes: 116 additions & 0 deletions components/admin/list/ImageEditSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use client'

import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '~/components/ui/Sheet'
import { useButtonStore } from '~/app/providers/button-store-Providers'
import { HandleListProps, ImageType } from '~/types'
import { usePageSWRHydrated } from '~/hooks/usePageSWRHydrated'
import { Button, cn, Input, Switch, Textarea } from '@nextui-org/react'
import React, { useState } from 'react'
import { toast } from 'sonner'

export default function ImageEditSheet(props : Readonly<HandleListProps & { pageNum: number }>) {
const { pageNum, ...restProps } = props
const { mutate } = usePageSWRHydrated(restProps, pageNum)
const { imageEdit, image, setImageEdit, setImageEditData } = useButtonStore(
(state) => state,
)
const [loading, setLoading] = useState(false)

async function submit() {
try {
setLoading(true)
const res = await fetch('/api/v1/image-update', {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(image),
method: 'PUT',
}).then(response => response.json())
toast.success('更新成功!')
setImageEditData({} as ImageType)
setImageEdit(false)
await mutate()
} catch (e) {
toast.error('更新失败!')
} finally {
setLoading(false)
}
}

return (
<Sheet
defaultOpen={false}
open={imageEdit}
onOpenChange={(open) => {
if (!open) {
setImageEdit(false)
setImageEditData({} as ImageType)
}
}}
>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>编辑标签</SheetTitle>
<SheetDescription className="space-y-2">
<Textarea
value={image?.detail}
onValueChange={(value) => setImageEditData({ ...image, detail: value })}
label="详情"
variant="bordered"
placeholder="输入详情"
disableAnimation
disableAutosize
classNames={{
input: "resize-y min-h-[40px]",
}}
/>
<Input
value={String(image?.sort)}
onValueChange={(value) => setImageEditData({ ...image, sort: Number(value) })}
type="number"
variant="bordered"
label="排序"
placeholder="0"
/>
<Switch
isSelected={image?.show === 0}
value={image?.show === 0 ? 'true' : 'false'}
onValueChange={(value) => setImageEditData({ ...image, show: value ? 0 : 1 })}
classNames={{
base: cn(
"inline-flex flex-row-reverse w-full max-w-md bg-content1 hover:bg-content2 items-center",
"justify-between cursor-pointer rounded-lg gap-2 p-4 border-2 border-transparent",
"data-[selected=true]:border-primary",
),
wrapper: "p-0 h-4 overflow-visible",
thumb: cn("w-6 h-6 border-2 shadow-lg",
"group-data-[hover=true]:border-primary",
//selected
"group-data-[selected=true]:ml-6",
// pressed
"group-data-[pressed=true]:w-7",
"group-data-[selected]:group-data-[pressed]:ml-4",
),
}}
>
<div className="flex flex-col gap-1">
<p className="text-medium">显示状态</p>
<p className="text-tiny text-default-400">
是否需要在首页显示图片
</p>
</div>
</Switch>
<Button
isLoading={loading}
color="primary"
variant="shadow"
onClick={() => submit()}
>
更新
</Button>
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
)
}
87 changes: 87 additions & 0 deletions components/admin/list/ImageView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client'

import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '~/components/ui/Sheet'
import { useButtonStore } from '~/app/providers/button-store-Providers'
import { ImageType } from '~/types'
import { cn, Input, Switch, Textarea, Image } from '@nextui-org/react'
import React from 'react'

export default function ImageView() {
const { imageView, imageViewData, setImageView, setImageViewData } = useButtonStore(
(state) => state,
)

return (
<Sheet
defaultOpen={false}
open={imageView}
onOpenChange={(open) => {
if (!open) {
setImageView(false)
setImageViewData({} as ImageType)
}
}}
>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>编辑标签</SheetTitle>
<SheetDescription className="space-y-2">
<Image
isBlurred
isZoomed
src={imageViewData.url}
alt={imageViewData.detail}
/>
<Textarea
isReadOnly
value={imageViewData?.detail}
label="详情"
variant="bordered"
disableAnimation
disableAutosize
classNames={{
input: "resize-y min-h-[40px]",
}}
/>
<Input
isReadOnly
value={String(imageViewData?.sort)}
type="number"
variant="bordered"
label="排序"
placeholder="0"
/>
<Switch
isDisabled
isSelected={imageViewData?.show === 0}
value={imageViewData?.show === 0 ? 'true' : 'false'}
classNames={{
base: cn(
"inline-flex flex-row-reverse w-full max-w-full bg-content1 hover:bg-content2 items-center",
"justify-between cursor-pointer rounded-lg gap-2 p-4 border-2 border-transparent",
"data-[selected=true]:border-primary",
),
wrapper: "p-0 h-4 overflow-visible",
thumb: cn("w-6 h-6 border-2 shadow-lg",
"group-data-[hover=true]:border-primary",
//selected
"group-data-[selected=true]:ml-6",
// pressed
"group-data-[pressed=true]:w-7",
"group-data-[selected]:group-data-[pressed]:ml-4",
),
}}
>
<div className="flex flex-col gap-1">
<p className="text-medium">显示状态</p>
<p className="text-tiny text-default-400">
是否需要在首页显示图片
</p>
</div>
</Switch>
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
)
}
18 changes: 14 additions & 4 deletions components/admin/list/ListProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
} from '~/components/ui/ContextMenu'
import { toast } from 'sonner'
import { useButtonStore } from '~/app/providers/button-store-Providers'
import ImageEditSheet from '~/components/admin/list/ImageEditSheet'
import ImageView from '~/components/admin/list/ImageView'

export default function ListProps(props : Readonly<HandleListProps>) {
const [pageNum, setPageNum] = useState(1)
Expand All @@ -38,7 +40,7 @@ export default function ListProps(props : Readonly<HandleListProps>) {
const [isOpen, setIsOpen] = useState(false)
const [image, setImage] = useState({} as ImageType)
const [deleteLoading, setDeleteLoading] = useState(false)
const { setImageEdit, setImageEditData } = useButtonStore(
const { setImageEdit, setImageEditData, setImageView, setImageViewData } = useButtonStore(
(state) => state,
)

Expand Down Expand Up @@ -97,7 +99,7 @@ export default function ListProps(props : Readonly<HandleListProps>) {
<ContextMenuTrigger>
<Card className="h-64">
<CardHeader className="flex gap-3">
<p>{image.detail}</p>
<Chip variant="shadow">{image.tag}</Chip>
</CardHeader>
<CardBody>
<p>{image.detail || '没有介绍'}</p>
Expand Down Expand Up @@ -128,6 +130,13 @@ export default function ListProps(props : Readonly<HandleListProps>) {
</Card>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem
className="cursor-pointer"
onClick={() => {
setImageViewData(image)
setImageView(true)
}}
>查看</ContextMenuItem>
<ContextMenuItem
className="cursor-pointer"
onClick={() => {
Expand All @@ -154,11 +163,10 @@ export default function ListProps(props : Readonly<HandleListProps>) {
<Pagination
className="!m-0"
total={total}
color="secondary"
color="primary"
size="sm"
page={pageNum}
onChange={async (page) => {
console.log(page)
setPageNum(page)
await mutate()
}}
Expand Down Expand Up @@ -194,6 +202,8 @@ export default function ListProps(props : Readonly<HandleListProps>) {
</ModalFooter>
</ModalContent>
</Modal>
<ImageEditSheet {...{...props, pageNum}} />
<ImageView {...{...props, pageNum}} />
</div>
)
}
1 change: 1 addition & 0 deletions components/admin/tag/TagEditSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default function TagEditSheet(props : Readonly<HandleProps>) {
onOpenChange={(open) => {
if (!open) {
setTagEdit(false)
setTagEditData({} as TagType)
}
}}
>
Expand Down
4 changes: 2 additions & 2 deletions components/ui/Sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ const sheetVariants = cva(
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-full sm:w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
left: "inset-y-0 left-0 h-full w-full sm:w-1/3 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left",
right:
"inset-y-0 right-0 h-full w-full sm:w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
"inset-y-0 right-0 h-full w-full sm:w-1/3 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
},
},
defaultVariants: {
Expand Down
26 changes: 26 additions & 0 deletions server/lib/operate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,30 @@ export async function deleteImage(id: number) {
}
})
return resultRow
}

export async function updateImage(image: ImageType) {
if (!image.sort || image.sort < 0) {
image.sort = 0
}
if (!image.rating || image.rating < 0) {
image.rating = 0
}
const resultRow = await db.images.update({
where: {
id: Number(image.id)
},
data: {
url: image.url,
exif: image.exif,
tag: image.tag,
detail: image.detail,
sort: image.sort,
show: image.show,
rating: image.rating,
update_time: new Date(),
}
}
)
return resultRow
}
Loading

0 comments on commit c281ed8

Please sign in to comment.