Browse Source

feat(ui): success toasts for save and update actions

Made-with: Cursor
main
npmrun 8 hours ago
parent
commit
f6beaf05ef
  1. 2
      app/components/PostBodyMarkdownEditor.vue
  2. 2
      app/components/PostComments.vue
  3. 2
      app/pages/me/admin/config/index.vue
  4. 5
      app/pages/me/admin/users/index.vue
  5. 3
      app/pages/me/posts/[id].vue
  6. 2
      app/pages/me/posts/new.vue
  7. 4
      app/pages/me/profile/index.vue
  8. 5
      app/pages/me/rss/index.vue
  9. 4
      app/pages/me/timeline/index.vue

2
app/components/PostBodyMarkdownEditor.vue

@ -11,6 +11,7 @@ const emit = defineEmits<{
}>() }>()
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const editorId = `post-body-md-${useId()}` const editorId = `post-body-md-${useId()}`
const local = computed({ const local = computed({
@ -28,6 +29,7 @@ async function onUploadImg(files: File[], callback: (urls: string[]) => void) {
method: 'POST', method: 'POST',
body: form, body: form,
}) })
toast.add({ title: '图片已上传', color: 'success' })
callback(uploaded.map((x) => x.url)) callback(uploaded.map((x) => x.url))
} catch { } catch {
callback([]) callback([])

2
app/components/PostComments.vue

@ -104,6 +104,7 @@ async function deleteComment(node: CommentNode) {
try { try {
await fetchData(`/api/me/posts/${postId}/comments/${node.id}`, { method: 'DELETE' }) await fetchData(`/api/me/posts/${postId}/comments/${node.id}`, { method: 'DELETE' })
await refreshComments() await refreshComments()
toast.add({ title: '评论已删除', color: 'success' })
} }
catch { catch {
/* fetchData 已 toast */ /* fetchData 已 toast */
@ -147,6 +148,7 @@ async function submitComment() {
guestName.value = '' guestName.value = ''
replyToId.value = null replyToId.value = null
await refreshComments() await refreshComments()
toast.add({ title: '评论已发送', color: 'success' })
} }
catch { catch {
/* fetchData 已 toast */ /* fetchData 已 toast */

2
app/pages/me/admin/config/index.vue

@ -14,6 +14,7 @@ type GlobalConfigPayload = {
const { user, refresh } = useAuthSession() const { user, refresh } = useAuthSession()
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const { refresh: refreshGlobalConfig } = useGlobalConfig() const { refresh: refreshGlobalConfig } = useGlobalConfig()
const loading = ref(true) const loading = ref(true)
@ -64,6 +65,7 @@ async function save() {
await putKey('mediaOrphanAutoSweepIntervalMinutes', mediaOrphanAutoSweepIntervalMinutes.value) await putKey('mediaOrphanAutoSweepIntervalMinutes', mediaOrphanAutoSweepIntervalMinutes.value)
await load() await load()
await refreshGlobalConfig() await refreshGlobalConfig()
toast.add({ title: '配置已保存', color: 'success' })
} finally { } finally {
saving.value = false saving.value = false
} }

5
app/pages/me/admin/users/index.vue

@ -71,6 +71,7 @@ async function createUser() {
form.password = '' form.password = ''
form.email = '' form.email = ''
await load() await load()
toast.add({ title: '用户已创建', color: 'success' })
} finally { } finally {
creating.value = false creating.value = false
} }
@ -79,6 +80,10 @@ async function createUser() {
async function setStatus(id: number, status: 'active' | 'disabled') { async function setStatus(id: number, status: 'active' | 'disabled') {
await fetchData(`/api/admin/users/${id}`, { method: 'PATCH', body: { status } }) await fetchData(`/api/admin/users/${id}`, { method: 'PATCH', body: { status } })
await load() await load()
toast.add({
title: status === 'active' ? '已启用该用户' : '已禁用该用户',
color: 'success',
})
} }
</script> </script>

3
app/pages/me/posts/[id].vue

@ -7,6 +7,7 @@ const route = useRoute()
const id = computed(() => route.params.id as string) const id = computed(() => route.params.id as string)
const { user, refresh: refreshAuth } = useAuthSession() const { user, refresh: refreshAuth } = useAuthSession()
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const state = reactive({ const state = reactive({
title: '', title: '',
@ -67,6 +68,7 @@ async function save() {
}, },
}) })
await load() await load()
toast.add({ title: '文章已保存', color: 'success' })
} finally { } finally {
saving.value = false saving.value = false
} }
@ -74,6 +76,7 @@ async function save() {
async function remove() { async function remove() {
await fetchData(`/api/me/posts/${id.value}`, { method: 'DELETE' }) await fetchData(`/api/me/posts/${id.value}`, { method: 'DELETE' })
toast.add({ title: '文章已删除', color: 'success' })
await navigateTo('/me/posts') await navigateTo('/me/posts')
} }

2
app/pages/me/posts/new.vue

@ -2,6 +2,7 @@
definePageMeta({ title: '新建文章' }) definePageMeta({ title: '新建文章' })
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const state = reactive({ const state = reactive({
title: '', title: '',
@ -26,6 +27,7 @@ async function submit() {
}, },
}) })
const id = post.id const id = post.id
toast.add({ title: '文章已创建', color: 'success' })
await navigateTo(`/me/posts/${id}`) await navigateTo(`/me/posts/${id}`)
} finally { } finally {
loading.value = false loading.value = false

4
app/pages/me/profile/index.vue

@ -5,6 +5,7 @@ definePageMeta({ title: '资料' })
const { refresh: refreshAuthSession } = useAuthSession() const { refresh: refreshAuthSession } = useAuthSession()
const { fetchData, getApiErrorMessage } = useClientApi() const { fetchData, getApiErrorMessage } = useClientApi()
const toast = useToast()
type ProfileGet = { type ProfileGet = {
profile: { profile: {
@ -74,6 +75,7 @@ async function onAvatarFileChange(ev: Event) {
} }
state.avatar = url state.avatar = url
message.value = '头像已上传,请点击下方「保存」写入资料' message.value = '头像已上传,请点击下方「保存」写入资料'
toast.add({ title: '头像已上传,请保存资料', color: 'success' })
} catch (e: unknown) { } catch (e: unknown) {
message.value = getApiErrorMessage(e) message.value = getApiErrorMessage(e)
} finally { } finally {
@ -105,6 +107,7 @@ async function onHeaderIconFileChange(ev: Event) {
} }
state.publicHomeHeaderIconUrl = url state.publicHomeHeaderIconUrl = url
message.value = '顶栏图标已上传,请点击下方「保存」写入' message.value = '顶栏图标已上传,请点击下方「保存」写入'
toast.add({ title: '顶栏图标已上传,请保存资料', color: 'success' })
} catch (e: unknown) { } catch (e: unknown) {
message.value = getApiErrorMessage(e) message.value = getApiErrorMessage(e)
} finally { } finally {
@ -175,6 +178,7 @@ async function save() {
}), }),
]) ])
message.value = '已保存' message.value = '已保存'
toast.add({ title: '资料已保存', color: 'success' })
try { try {
await refreshAuthSession(true) await refreshAuthSession(true)
} catch { } catch {

5
app/pages/me/rss/index.vue

@ -21,6 +21,7 @@ let copyResetTimer: ReturnType<typeof setTimeout> | undefined
const { user, refresh } = useAuthSession() const { user, refresh } = useAuthSession()
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const filteredItems = computed(() => { const filteredItems = computed(() => {
if (selectedFeedId.value === null) { if (selectedFeedId.value === null) {
@ -77,11 +78,13 @@ async function addFeed() {
await fetchData('/api/me/rss/feeds', { method: 'POST', body: { feedUrl: feedUrl.value } }) await fetchData('/api/me/rss/feeds', { method: 'POST', body: { feedUrl: feedUrl.value } })
feedUrl.value = '' feedUrl.value = ''
await load() await load()
toast.add({ title: '已添加订阅', color: 'success' })
} }
async function syncAll() { async function syncAll() {
await fetchData('/api/me/rss/sync', { method: 'POST', body: {} }) await fetchData('/api/me/rss/sync', { method: 'POST', body: {} })
await load() await load()
toast.add({ title: '同步完成', color: 'success' })
} }
async function removeFeed(id: number) { async function removeFeed(id: number) {
@ -90,11 +93,13 @@ async function removeFeed(id: number) {
selectedFeedId.value = null selectedFeedId.value = null
} }
await load() await load()
toast.add({ title: '已删除订阅', color: 'success' })
} }
async function setItemVis(id: number, visibility: string) { async function setItemVis(id: number, visibility: string) {
await fetchData(`/api/me/rss/items/${id}`, { method: 'PATCH', body: { visibility } }) await fetchData(`/api/me/rss/items/${id}`, { method: 'PATCH', body: { visibility } })
await load() await load()
toast.add({ title: '可见性已更新', color: 'success' })
} }
async function copyUnlistedLink(it: Item) { async function copyUnlistedLink(it: Item) {

4
app/pages/me/timeline/index.vue

@ -61,6 +61,7 @@ const visibilitySelectItems = [
] as const ] as const
const { fetchData } = useClientApi() const { fetchData } = useClientApi()
const toast = useToast()
const events = ref<Ev[]>([]) const events = ref<Ev[]>([])
const loading = ref(true) const loading = ref(true)
@ -115,6 +116,7 @@ async function add() {
form.linkUrl = '' form.linkUrl = ''
form.occurredOn = occurredOnToLocalInputValue(new Date()) form.occurredOn = occurredOnToLocalInputValue(new Date())
await load() await load()
toast.add({ title: '已添加事件', color: 'success' })
} finally { } finally {
submitLoading.value = false submitLoading.value = false
} }
@ -128,6 +130,7 @@ async function removeEvent(e: Ev) {
try { try {
await fetchData(`/api/me/timeline/${e.id}`, { method: 'DELETE' }) await fetchData(`/api/me/timeline/${e.id}`, { method: 'DELETE' })
await load() await load()
toast.add({ title: '已删除', color: 'success' })
} finally { } finally {
deletingId.value = null deletingId.value = null
} }
@ -164,6 +167,7 @@ async function updateVisibility(e: Ev, visibility: string) {
body: { visibility }, body: { visibility },
}) })
await load() await load()
toast.add({ title: '可见性已更新', color: 'success' })
} finally { } finally {
updatingVisibilityId.value = null updatingVisibilityId.value = null
} }

Loading…
Cancel
Save