315 lines
7.5 KiB
Vue
315 lines
7.5 KiB
Vue
<script lang="ts" setup>
|
|
import { Toast, VButton, VModal, VSpace } from "@halo-dev/components";
|
|
import { ref, computed, nextTick, watch} from "vue";
|
|
import cloneDeep from "lodash.clonedeep";
|
|
import {doubanCoreApiClient} from "@/api";
|
|
import type { DoubanMovie } from "@/api/generated";
|
|
import {toDatetimeLocal, toISOString} from "@/utils/date";
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
visible: boolean;
|
|
doubanMovie?: DoubanMovie;
|
|
}>(),
|
|
{
|
|
visible: false,
|
|
doubanMovie: undefined,
|
|
}
|
|
);
|
|
|
|
const emit = defineEmits<{
|
|
(event: "update:visible", value: boolean): void;
|
|
(event: "close"): void;
|
|
}>();
|
|
|
|
const initialFormState: DoubanMovie = {
|
|
metadata: {
|
|
name: "",
|
|
generateName: "douban-movie-",
|
|
},
|
|
faves:{
|
|
remark :"",
|
|
createTime: undefined,
|
|
score: "",
|
|
status: "done"
|
|
},
|
|
spec: {
|
|
name: "",
|
|
poster: "",
|
|
link: "",
|
|
id: "",
|
|
score: "",
|
|
year: "",
|
|
type: "",
|
|
pubdate: "",
|
|
cardSubtitle: "",
|
|
dataType: "halo",
|
|
genres: []
|
|
},
|
|
kind: "DoubanMovie",
|
|
apiVersion: "douban.moony.la/v1alpha1",
|
|
};
|
|
|
|
const formState = ref<DoubanMovie>(cloneDeep(initialFormState));
|
|
const saving = ref<boolean>(false);
|
|
const formVisible = ref(false);
|
|
const createTime = ref<string | undefined>(undefined);
|
|
|
|
|
|
const isUpdateMode = computed(() => {
|
|
return !!formState.value.metadata.creationTimestamp;
|
|
});
|
|
|
|
const modalTitle = computed(() => {
|
|
return isUpdateMode.value ? "编辑条目" : "新建条目";
|
|
});
|
|
|
|
const onVisibleChange = (visible: boolean) => {
|
|
emit("update:visible", visible);
|
|
if (!visible) {
|
|
emit("close");
|
|
}
|
|
};
|
|
|
|
const handleResetForm = () => {
|
|
formState.value = cloneDeep(initialFormState);
|
|
};
|
|
|
|
watch(
|
|
() => props.visible,
|
|
(visible) => {
|
|
if (visible) {
|
|
formVisible.value = true;
|
|
} else {
|
|
setTimeout(() => {
|
|
formVisible.value = false;
|
|
handleResetForm();
|
|
}, 200);
|
|
}
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => props.doubanMovie,
|
|
(doubanMovie) => {
|
|
if (doubanMovie) {
|
|
formState.value = cloneDeep(doubanMovie);
|
|
createTime.value = toDatetimeLocal(formState.value.faves.createTime);
|
|
}else {
|
|
createTime.value = undefined;
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => createTime.value,
|
|
(value) => {
|
|
formState.value.faves.createTime = value ? toISOString(value) : undefined;
|
|
}
|
|
);
|
|
const annotationsFormRef = ref();
|
|
|
|
const handleSaveFriend = async () => {
|
|
annotationsFormRef.value?.handleSubmit();
|
|
await nextTick();
|
|
|
|
const { customAnnotations, annotations, customFormInvalid, specFormInvalid } =
|
|
annotationsFormRef.value || {};
|
|
if (customFormInvalid || specFormInvalid) {
|
|
return;
|
|
}
|
|
|
|
formState.value.metadata.annotations = {
|
|
...annotations,
|
|
...customAnnotations,
|
|
};
|
|
|
|
try {
|
|
saving.value = true;
|
|
if (isUpdateMode.value) {
|
|
await doubanCoreApiClient.doubanMovie.updateDoubanMovie({
|
|
name: formState.value.metadata.name,
|
|
doubanMovie: formState.value
|
|
});
|
|
} else {
|
|
await doubanCoreApiClient.doubanMovie.createDoubanMovie(
|
|
{
|
|
doubanMovie: formState.value
|
|
});
|
|
}
|
|
|
|
Toast.success("保存成功");
|
|
|
|
onVisibleChange(false);
|
|
} catch (e) {
|
|
console.error(e);
|
|
} finally {
|
|
saving.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
<template>
|
|
<VModal
|
|
:title="modalTitle"
|
|
:visible="visible"
|
|
:width="650"
|
|
@update:visible="onVisibleChange"
|
|
>
|
|
<template #actions>
|
|
<slot name="append-actions" />
|
|
</template>
|
|
|
|
<FormKit
|
|
v-if="formVisible"
|
|
id="doubanMovie-form"
|
|
name="doubanMovie-form"
|
|
type="form"
|
|
:config="{ validationVisibility: 'submit' }"
|
|
@submit="handleSaveFriend"
|
|
>
|
|
<div class="md:grid md:grid-cols-4 md:gap-6">
|
|
<div class="md:col-span-1">
|
|
<div class="sticky top-0">
|
|
<span class="text-base font-medium text-gray-900"> 常规 </span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-5 divide-y divide-gray-100 md:col-span-3 md:mt-0">
|
|
<td v-if="isUpdateMode">
|
|
<p><img :src="formState.spec.poster" width="100"></p>
|
|
<p>{{formState.spec.name}} <span class="db--titletag">{{formState.spec.dataType == 'db' ? '豆瓣' : formState.spec.dataType == 'tmdb' ? 'TMDB' : '手动添加'}}</span>
|
|
</p>
|
|
<p>{{formState.spec.cardSubtitle}}</p>
|
|
</td>
|
|
<FormKit
|
|
v-if="formState.spec.dataType=='halo'"
|
|
type="attachment"
|
|
v-model="formState.spec.poster"
|
|
name="poster"
|
|
validation="required"
|
|
label="封面"
|
|
></FormKit>
|
|
<FormKit
|
|
v-if="formState.spec.dataType=='halo'"
|
|
type="text"
|
|
v-model="formState.spec.name"
|
|
name="name"
|
|
validation="required"
|
|
label="标题"
|
|
></FormKit>
|
|
<FormKit
|
|
type="text"
|
|
v-model="formState.spec.link"
|
|
name="link"
|
|
validation="required"
|
|
label="链接"
|
|
></FormKit>
|
|
<FormKit
|
|
v-if="formState.spec.dataType=='halo'"
|
|
type="number"
|
|
v-model="formState.spec.score"
|
|
name="score"
|
|
validation="required"
|
|
label="评分"
|
|
max="10"
|
|
min="0"
|
|
></FormKit>
|
|
<FormKit
|
|
v-if="formState.spec.dataType=='halo'"
|
|
type="text"
|
|
v-model="formState.spec.type"
|
|
name="type"
|
|
label="类型"
|
|
placeholder="输入类型 value,例如 movie"
|
|
></FormKit>
|
|
<FormKit
|
|
v-if="formState.spec.dataType=='halo'"
|
|
type="textarea"
|
|
v-model="formState.spec.cardSubtitle"
|
|
name="cardSubtitle"
|
|
label="描述"
|
|
:rows="4"
|
|
validation="required|length:0,300"
|
|
></FormKit>
|
|
<FormKit
|
|
type="datetime-local"
|
|
min="0000-01-01T00:00"
|
|
max="9999-12-31T23:59"
|
|
v-model="createTime"
|
|
name="createTime"
|
|
validation="required"
|
|
label="观看时间"
|
|
></FormKit>
|
|
<FormKit
|
|
:options="[
|
|
{ label: '已看', value: 'done' },
|
|
{ label: '想看', value: 'mark' },
|
|
{ label: '在看', value: 'doing' },
|
|
]"
|
|
label="状态"
|
|
v-model="formState.faves.status"
|
|
name="status"
|
|
type="select"
|
|
></FormKit>
|
|
<FormKit
|
|
type="textarea"
|
|
v-model="formState.faves.remark"
|
|
name="remark"
|
|
label="我的短评"
|
|
:rows="4"
|
|
validation="length:0,300"
|
|
></FormKit>
|
|
<FormKit
|
|
type="number"
|
|
v-model="formState.faves.score"
|
|
name="score"
|
|
label="我的评分"
|
|
max="5"
|
|
min="0"
|
|
></FormKit>
|
|
</div>
|
|
</div>
|
|
</FormKit>
|
|
|
|
<template #footer>
|
|
<VSpace>
|
|
<VButton
|
|
:loading="saving"
|
|
type="secondary"
|
|
@click="$formkit.submit('doubanMovie-form')"
|
|
>
|
|
提交
|
|
</VButton>
|
|
<VButton @click="onVisibleChange(false)">取消</VButton>
|
|
</VSpace>
|
|
</template>
|
|
</VModal>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.db--titletag {
|
|
font-size: 13px;
|
|
display: inline-block;
|
|
color: #fff;
|
|
background-color: green;
|
|
border-radius: 2px;
|
|
line-height: 1;
|
|
padding: 2px 3px;
|
|
margin-left: 4px;
|
|
}
|
|
|
|
divide-y td {
|
|
margin-bottom: 9px;
|
|
line-height: 1.3;
|
|
padding-bottom: 1rem;
|
|
}
|
|
|
|
.divide-y td p {
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
</style>
|