Skip to content

Commit

Permalink
feat: support moment user center (#68)
Browse files Browse the repository at this point in the history
#### What type of PR is this?

/kind feature

#### What this PR does / why we need it:

支持在个人中心发布瞬间

#### How to test it?

在个人中心发布瞬间,并测试相关权限是否正常。

#### Which issue(s) this PR fixes:

Fixes #47 
Fixes #53

#### Does this PR introduce a user-facing change?
```release-note
适配在个人中心发布瞬间
```
  • Loading branch information
LIlGG authored May 7, 2024
1 parent ffc4de3 commit d842fb4
Show file tree
Hide file tree
Showing 30 changed files with 1,786 additions and 192 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ build {

halo {
version = '2.12.0'
debug = true;
}
92 changes: 92 additions & 0 deletions console/src/components/FilterDropdown.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<script lang="ts" setup>
import {
IconArrowDown,
IconClose,
VDropdown,
VDropdownItem,
} from "@halo-dev/components";
import { computed } from "vue";
const props = withDefaults(
defineProps<{
items: {
label: string;
value?: string | boolean | number;
}[];
label: string;
modelValue?: string | boolean | number;
}>(),
{
modelValue: undefined,
}
);
const emit = defineEmits<{
(
event: "update:modelValue",
modelValue: string | boolean | number | undefined
): void;
}>();
const selectedItem = computed(() => {
return props.items.find((item) => item.value === props.modelValue);
});
function handleSelect(item: {
label: string;
value?: string | boolean | number;
}) {
if (item.value === props.modelValue) {
emit("update:modelValue", undefined);
return;
}
emit("update:modelValue", item.value);
}
const handleClear = (event: Event) => {
emit("update:modelValue", undefined);
event.stopPropagation();
};
</script>

<template>
<VDropdown>
<div
class="filter-dropdown moments-group"
:class="{
'moments-font-semibold moments-text-gray-700': modelValue !== undefined,
}"
>
<span v-if="!selectedItem" class="mr-0.5">
{{ label }}
</span>
<span v-else class="mr-0.5"> {{ label }}:{{ selectedItem.label }} </span>
<span class="moments-text-base">
<IconArrowDown
:class="{ 'group-hover:moments-hidden': modelValue !== undefined }"
/>
<IconClose
v-if="modelValue !== undefined"
class="moments-hidden group-hover:moments-block"
@click="handleClear"
/>
</span>
</div>
<template #popper>
<VDropdownItem
v-for="(item, index) in items"
:key="index"
:selected="item.value === modelValue"
@click="handleSelect(item)"
>
{{ item.label }}
</VDropdownItem>
</template>
</VDropdown>
</template>
<style scoped lang="scss">
.filter-dropdown {
@apply moments-flex moments-cursor-pointer moments-select-none moments-items-center moments-text-sm moments-leading-9 moments-px-3 moments-text-gray-700 moments-rounded-lg hover:moments-text-black;
border: 1px solid rgb(209 213 219);
}
</style>
78 changes: 46 additions & 32 deletions console/src/components/MomentEdit.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
<script lang="ts" setup>
import { VButton, IconEye, IconEyeOff } from "@halo-dev/components";
import type { Moment, MomentMedia, MomentMediaTypeEnum } from "@/types";
import apiClient from "@/utils/api-client";
import { Toast } from "@halo-dev/components";
import type { AttachmentLike } from "@halo-dev/console-shared";
import { computed, onMounted, ref, toRaw } from "vue";
import MediaCard from "./MediaCard.vue";
import TextEditor from "./TextEditor.vue";
import MediaCard from "@/components/MediaCard.vue";
import TextEditor from "@/components/TextEditor.vue";
import SendMoment from "~icons/ic/sharp-send";
import cloneDeep from "lodash.clonedeep";
import TablerPhoto from "~icons/tabler/photo";
import apiClient from "@/utils/api-client";
import { useConsoleTagQueryFetch } from "@/composables/use-tag";
const props = withDefaults(
defineProps<{
Expand Down Expand Up @@ -37,6 +38,7 @@ const initMoment: Moment = {
owner: "",
visible: "PUBLIC",
tags: [],
approved: true,
},
metadata: {
generateName: "moment-",
Expand Down Expand Up @@ -66,9 +68,10 @@ const handlerCreateOrUpdateMoment = async () => {
saving.value = true;
queryEditorTags();
if (isUpdateMode.value) {
updateMoment();
handleUpdate(formState.value);
} else {
createMoment();
handleSave(formState.value);
handleReset();
}
} catch (error) {
console.error(error);
Expand All @@ -77,6 +80,31 @@ const handlerCreateOrUpdateMoment = async () => {
}
};
const handleSave = async (moment: Moment) => {
moment.spec.releaseTime = new Date().toISOString();
moment.spec.approved = true;
const { data } = await apiClient.post<Moment>(
`/apis/console.api.moment.halo.run/v1alpha1/moments`,
moment
);
emit("save", data);
Toast.success("发布成功");
};
const handleUpdate = async (moment: Moment) => {
const { data } = await apiClient.get<Moment>(
`/apis/moment.halo.run/v1alpha1/moments/${moment.metadata.name}`
);
// 更新当前需要提交的 moment spec 为最新
data.spec = moment.spec;
const updated = await apiClient.put<Moment>(
`/apis/moment.halo.run/v1alpha1/moments/${moment.metadata.name}`,
data
);
emit("update", updated.data);
Toast.success("发布成功");
};
const parse = new DOMParser();
const queryEditorTags = function () {
let tags: Set<string> = new Set();
Expand All @@ -95,31 +123,6 @@ const queryEditorTags = function () {
formState.value.spec.tags = Array.from(tags);
};
const createMoment = async () => {
formState.value.spec.releaseTime = new Date().toISOString();
const { data } = await apiClient.post<Moment>(
`/apis/console.api.moment.halo.run/v1alpha1/moments`,
formState.value
);
emit("save", data);
handleReset();
Toast.success("发布成功");
};
const updateMoment = async () => {
const { data } = await apiClient.get<Moment>(
`/apis/moment.halo.run/v1alpha1/moments/${formState.value.metadata.name}`
);
// 更新当前需要提交的 moment spec 为最新
data.spec = formState.value.spec;
const updated = await apiClient.put<Moment>(
`/apis/moment.halo.run/v1alpha1/moments/${formState.value.metadata.name}`,
data
);
emit("update", updated.data);
Toast.success("发布成功");
};
const handleReset = () => {
formState.value = toRaw(cloneDeep(initMoment));
isEditorEmpty.value = true;
Expand All @@ -143,7 +146,11 @@ const supportVideoTypes: string[] = ["video/*"];
const supportAudioTypes: string[] = ["audio/*"];
const accepts = [...supportImageTypes, ...supportVideoTypes, ...supportAudioTypes];
const accepts = [
...supportImageTypes,
...supportVideoTypes,
...supportAudioTypes,
];
const mediumWhitelist: Map<string, MomentMediaTypeEnum> = new Map([
["image", "PHOTO"],
Expand Down Expand Up @@ -291,6 +298,7 @@ function handleKeydown(event: KeyboardEvent) {
>
<AttachmentSelectorModal
v-model:visible="attachmentSelectorModal"
v-permission="['system:attachments:view']"
:min="1"
:max="9"
:accepts="accepts"
Expand All @@ -300,6 +308,7 @@ function handleKeydown(event: KeyboardEvent) {
v-model:raw="formState.spec.content.raw"
v-model:html="formState.spec.content.html"
v-model:isEmpty="isEditorEmpty"
:tag-query-fetch="useConsoleTagQueryFetch"
class="moments-min-h-[9rem] moments-p-3.5"
tabindex="-1"
@keydown="handleKeydown"
Expand Down Expand Up @@ -367,7 +376,12 @@ function handleKeydown(event: KeyboardEvent) {
<span class="moments-text-xs"> 取消 </span>
</button>

<div v-permission="['plugin:moments:manage']" class="moments-h-fit">
<div
v-permission="
['plugin:moments:manage'] || ['uc:plugin:moments:publish']
"
class="moments-h-fit"
>
<VButton
v-model:disabled="saveDisable"
:loading="saving"
Expand Down
Loading

0 comments on commit d842fb4

Please sign in to comment.