Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
I
img-manager
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ivan Lan
img-manager
Commits
28692f2c
Commit
28692f2c
authored
Mar 10, 2025
by
Ivan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: update edit
parent
63b84398
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
133 additions
and
83 deletions
+133
-83
ImageUploadForm.jsx
app/frontend/components/ImageUploadForm.jsx
+14
-4
ComImageIndex.jsx
app/frontend/components/images/ComImageIndex.jsx
+4
-71
ComImageShow.jsx
app/frontend/components/images/ComImageShow.jsx
+2
-1
ComImageStatusSelect.jsx
app/frontend/components/images/ComImageStatusSelect.jsx
+70
-0
ComTagsIndex.jsx
app/frontend/components/tags/ComTagsIndex.jsx
+1
-1
Layout.jsx
app/frontend/pages/Layout.jsx
+1
-1
Edit.jsx
app/frontend/pages/admin/images/Edit.jsx
+41
-5
No files found.
app/frontend/components/ImageUploadForm.jsx
View file @
28692f2c
import
{
useState
,
useEffect
}
from
'react'
import
*
as
Form
from
'@radix-ui/react-form'
import
TagSearchInput
from
'./TagSearchInput'
import
ComImageStatusSelect
from
'./images/ComImageStatusSelect'
export
default
function
ImageUploadForm
({
data
,
...
...
@@ -11,6 +12,7 @@ export default function ImageUploadForm({
submitButtonText
=
'上传图片'
,
processingButtonText
=
'上传中...'
,
showTagsField
=
true
,
showStatusField
=
false
,
isEdit
=
false
,
image
=
null
,
tags
=
[],
...
...
@@ -151,7 +153,17 @@ export default function ImageUploadForm({
/>
</
div
>
)
}
{
showStatusField
&&
(
<
Form
.
Field
name=
"status"
className=
"space-y-2"
>
<
ComImageStatusSelect
value=
{
data
.
status
}
onChange=
{
(
value
)
=>
setData
(
'status'
,
value
)
}
allowAll=
{
false
}
/>
</
Form
.
Field
>
)
}
{
showTagsField
&&
(
<
Form
.
Field
name=
"tags"
className=
"space-y-2"
>
<
Form
.
Label
className=
"block text-sm font-medium text-gray-700"
>
...
...
@@ -165,9 +177,7 @@ export default function ImageUploadForm({
placeholder=
"点击搜索图标添加标签"
/>
</
Form
.
Control
>
<
p
className=
"text-xs text-gray-500"
>
点击右侧搜索图标可按分类浏览标签
</
p
>
</
Form
.
Field
>
)
}
...
...
app/frontend/components/images/ComImageIndex.jsx
View file @
28692f2c
...
...
@@ -2,14 +2,11 @@ import { useState, useEffect, useRef, useCallback } from 'react'
import
{
Head
,
Link
,
router
}
from
'@inertiajs/react'
import
*
as
Form
from
'@radix-ui/react-form'
import
*
as
Collapsible
from
'@radix-ui/react-collapsible'
import
*
as
Select
from
'@radix-ui/react-select'
import
{
uniqBy
}
from
'lodash-es'
import
{
ComImageCard
}
from
'./ComImageCard'
import
TagSearchInput
from
'../TagSearchInput'
import
DateRangePicker
from
'../DateRangePicker'
import
{
ChevronDownIcon
,
ChevronUpIcon
,
XMarkIcon
}
from
'@heroicons/react/24/solid'
import
ComImageStatusSelect
from
'./ComImageStatusSelect'
export
default
function
ComImageIndex
({
title
,
description
,
path
,
images
,
pagination
,
filters
,
auth
,
backLink
,
actionButton
,
showUserName
=
false
,
allTags
=
{}
})
{
const
[
allImages
,
setAllImages
]
=
useState
(
images
||
[])
...
...
@@ -44,10 +41,6 @@ export default function ComImageIndex({ title, description, path, images, pagina
setSearchParams
({
...
searchParams
,
status_eq
:
statusValue
})
}
const
clearStatus
=
()
=>
{
setSearchParams
({
...
searchParams
,
status_eq
:
''
})
}
const
handleSearch
=
(
e
)
=>
{
e
.
preventDefault
()
setLoadedPageMap
({})
...
...
@@ -281,70 +274,10 @@ export default function ComImageIndex({ title, description, path, images, pagina
状态
</
Form
.
Label
>
<
Form
.
Control
asChild
>
<
Select
.
Root
<
ComImageStatusSelect
value=
{
searchParams
.
status_eq
||
"all"
}
onValueChange=
{
handleStatusChange
}
>
<
div
className=
"relative"
>
<
Select
.
Trigger
className=
"mt-1 inline-flex items-center justify-between w-full px-3 py-2 text-sm border border-gray-300 rounded-md shadow-sm bg-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
>
<
Select
.
Value
placeholder=
"选择状态"
/>
<
Select
.
Icon
>
<
ChevronDownIcon
className=
"h-4 w-4 text-gray-500"
/>
</
Select
.
Icon
>
</
Select
.
Trigger
>
{
searchParams
.
status_eq
&&
(
<
button
type=
"button"
onClick=
{
clearStatus
}
className=
"absolute right-8 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
aria
-
label=
"清空状态筛选"
>
<
XMarkIcon
className=
"h-4 w-4"
/>
</
button
>
)
}
</
div
>
<
Select
.
Portal
>
<
Select
.
Content
className=
"overflow-hidden bg-white rounded-md shadow-lg border border-gray-200 z-50"
>
<
Select
.
ScrollUpButton
className=
"flex items-center justify-center h-6 bg-white text-gray-700 cursor-default"
>
<
ChevronUpIcon
className=
"h-4 w-4"
/>
</
Select
.
ScrollUpButton
>
<
Select
.
Viewport
className=
"p-1"
>
<
Select
.
Group
>
<
Select
.
Item
value=
"all"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
全部状态
</
Select
.
ItemText
>
</
Select
.
Item
>
<
Select
.
Item
value=
"pending"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
待审核
</
Select
.
ItemText
>
</
Select
.
Item
>
<
Select
.
Item
value=
"approved"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
已通过
</
Select
.
ItemText
>
</
Select
.
Item
>
<
Select
.
Item
value=
"rejected"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
已拒绝
</
Select
.
ItemText
>
</
Select
.
Item
>
</
Select
.
Group
>
</
Select
.
Viewport
>
<
Select
.
ScrollDownButton
className=
"flex items-center justify-center h-6 bg-white text-gray-700 cursor-default"
>
<
ChevronDownIcon
className=
"h-4 w-4"
/>
</
Select
.
ScrollDownButton
>
</
Select
.
Content
>
</
Select
.
Portal
>
</
Select
.
Root
>
{
/* <select
name="status_eq"
value={searchParams.status_eq}
onChange={handleInputChange}
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md"
>
<option value="">全部状态</option>
<option value="pending">待审核</option>
<option value="approved">已通过</option>
<option value="rejected">已拒绝</option>
</select> */
}
onChange=
{
handleStatusChange
}
/>
</
Form
.
Control
>
</
Form
.
Field
>
</
div
>
...
...
app/frontend/components/images/ComImageShow.jsx
View file @
28692f2c
...
...
@@ -123,7 +123,8 @@ export default function ComImageShow({ path, image, can_edit, can_approve, isAdm
<
Dialog
.
Root
open=
{
isModalOpen
}
onOpenChange=
{
setIsModalOpen
}
>
<
Dialog
.
Portal
>
<
Dialog
.
Overlay
className=
"fixed inset-0 bg-black/50"
/>
<
Dialog
.
Content
className=
"fixed inset-0 flex items-center justify-center"
>
<
Dialog
.
Content
className=
"fixed inset-0 flex items-center justify-center z-50"
>
<
Dialog
.
Title
className=
"hidden"
/>
<
div
className=
"relative w-full h-full max-w-screen-xl max-h-screen p-4"
>
<
img
src=
{
image
.
file_url
}
...
...
app/frontend/components/images/ComImageStatusSelect.jsx
0 → 100644
View file @
28692f2c
import
*
as
Select
from
'@radix-ui/react-select'
import
{
ChevronDownIcon
,
ChevronUpIcon
,
XMarkIcon
}
from
'@heroicons/react/24/solid'
export
default
function
ComImageStatusSelect
({
value
,
onChange
,
disabled
=
false
,
allowAll
=
true
})
{
return
(
<
Select
.
Root
value=
{
value
}
onValueChange=
{
onChange
}
disabled=
{
disabled
}
>
<
div
className=
"relative"
>
<
Select
.
Trigger
className=
"mt-1 inline-flex items-center justify-between w-full px-3 py-2 text-sm border border-gray-300 rounded-md shadow-sm bg-white focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
>
<
Select
.
Value
placeholder=
"选择状态"
/>
<
Select
.
Icon
>
<
ChevronDownIcon
className=
"h-4 w-4 text-gray-500"
/>
</
Select
.
Icon
>
</
Select
.
Trigger
>
{
value
&&
(
<
button
type=
"button"
onClick=
{
()
=>
onChange
(
''
)
}
className=
"absolute right-8 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
aria
-
label=
"清空状态筛选"
>
<
XMarkIcon
className=
"h-4 w-4"
/>
</
button
>
)
}
</
div
>
<
Select
.
Portal
>
<
Select
.
Content
className=
"overflow-hidden bg-white rounded-md shadow-lg border border-gray-200 z-50"
>
<
Select
.
ScrollUpButton
className=
"flex items-center justify-center h-6 bg-white text-gray-700 cursor-default"
>
<
ChevronUpIcon
className=
"h-4 w-4"
/>
</
Select
.
ScrollUpButton
>
<
Select
.
Viewport
className=
"p-1"
>
<
Select
.
Group
>
{
allowAll
&&
<
Select
.
Item
value=
"all"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
全部状态
</
Select
.
ItemText
>
</
Select
.
Item
>
}
<
Select
.
Item
value=
"pending"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
待审核
</
Select
.
ItemText
>
</
Select
.
Item
>
<
Select
.
Item
value=
"approved"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
已通过
</
Select
.
ItemText
>
</
Select
.
Item
>
<
Select
.
Item
value=
"rejected"
className=
"relative flex items-center h-8 px-6 py-2 text-sm rounded hover:bg-indigo-100 hover:text-indigo-900 cursor-pointer outline-none data-[highlighted]:bg-indigo-100 data-[highlighted]:text-indigo-900"
>
<
Select
.
ItemText
>
已拒绝
</
Select
.
ItemText
>
</
Select
.
Item
>
</
Select
.
Group
>
</
Select
.
Viewport
>
<
Select
.
ScrollDownButton
className=
"flex items-center justify-center h-6 bg-white text-gray-700 cursor-default"
>
<
ChevronDownIcon
className=
"h-4 w-4"
/>
</
Select
.
ScrollDownButton
>
</
Select
.
Content
>
</
Select
.
Portal
>
</
Select
.
Root
>
)
}
\ No newline at end of file
app/frontend/components/tags/ComTagsIndex.jsx
View file @
28692f2c
...
...
@@ -148,7 +148,7 @@ export default function ComTagsIndex({
</
Link
>
</
div
>
{
isAdmin
&&
<
div
className=
"!mt-2 flex space-x-2 justify-end mt-auto pt-2
border-t border-gray-200
"
>
{
isAdmin
&&
<
div
className=
"!mt-2 flex space-x-2 justify-end mt-auto pt-2"
>
<
button
onClick=
{
()
=>
openEditModal
(
tag
)
}
className=
"text-xs text-indigo-600 hover:text-indigo-900"
...
...
app/frontend/pages/Layout.jsx
View file @
28692f2c
...
...
@@ -8,7 +8,7 @@ export default function Layout({ children, user, title }) {
return
(
<
div
className=
"min-h-screen bg-gray-50 flex flex-col"
>
<
header
className=
"bg-white shadow-sm"
>
<
header
className=
"bg-white shadow-sm
sticky top-0 z-10
"
>
<
div
className=
"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"
>
<
div
className=
"flex justify-between h-16"
>
<
div
className=
"flex"
>
...
...
app/frontend/pages/admin/images/Edit.jsx
View file @
28692f2c
import
{
Head
}
from
'@inertiajs/react'
import
{
Head
,
useForm
}
from
'@inertiajs/react'
import
Layout
from
'../../Layout'
import
ComImageEdit
from
'../../../components/images/ComImageEdit
'
import
ImageUploadForm
from
'../../../components/ImageUploadForm
'
export
default
function
AdminImagesEdit
({
image
,
tags
,
auth
})
{
// 初始化已有标签的ID数组
const
initialTagIds
=
image
.
tags
?
image
.
tags
.
map
(
tag
=>
tag
.
id
)
:
[]
const
{
data
,
setData
,
patch
,
processing
,
errors
}
=
useForm
({
title
:
image
.
title
||
''
,
status
:
image
.
status
,
tag_ids
:
initialTagIds
,
})
const
handleSubmit
=
(
e
)
=>
{
e
.
preventDefault
()
patch
(
`/admin/images/
${
image
.
id
}
`
)
}
return
(
<
Layout
user=
{
auth
}
>
<
Head
title=
{
`管理 - 编辑 ${image.title}`
}
/>
<
ComImageEdit
<
div
className=
"bg-white shadow overflow-hidden sm:rounded-lg"
>
<
div
className=
"px-4 py-5 sm:px-6"
>
<
h1
className=
"text-2xl font-bold text-gray-900"
>
编辑图片
</
h1
>
<
p
className=
"mt-1 max-w-2xl text-sm text-gray-500"
>
更新图片信息
</
p
>
</
div
>
<
div
className=
"border-t border-gray-200 px-4 py-5 sm:px-6"
>
<
ImageUploadForm
data=
{
data
}
setData=
{
setData
}
processing=
{
processing
}
errors=
{
errors
}
onSubmit=
{
handleSubmit
}
submitButtonText=
"保存"
processingButtonText=
"保存中..."
showTagsField=
{
true
}
showStatusField=
{
true
}
isEdit=
{
true
}
image=
{
image
}
tags=
{
tags
}
path=
{
`/admin/images/${image.id}`
}
isAdmin=
{
true
}
cancelUrl=
{
`/admin/images/${image.id}`
}
/>
</
div
>
</
div
>
</
Layout
>
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment