|
@@ -1,280 +1,413 @@
|
|
|
<template>
|
|
|
- <div v-if="!loading" class="box-border pb-80">
|
|
|
- <CreateNoteHeaderBanner v-model:bannerUrl="noteJson.travelNotesBanner" />
|
|
|
-
|
|
|
- <CreateNoteForm
|
|
|
- v-model:departureTime="noteJson.departureTime"
|
|
|
- v-model:countTimes="noteJson.countTimes"
|
|
|
- v-model:endPlace="noteJson.endPlace"
|
|
|
- v-model:role="noteJson.role"
|
|
|
- v-model:travelMode="noteJson.travelMode"
|
|
|
- v-model:averageCost="noteJson.averageCost"
|
|
|
- v-model:recommendationRate="noteJson.recommendationRate"
|
|
|
- v-model:travelNumber="noteJson.travelNumber"
|
|
|
- />
|
|
|
-
|
|
|
- <div class="flex items-center pl-16 pt-16 w-full h-40">
|
|
|
- <div class="w-2 h-14 bg-[#FF9300] mr-16"></div>
|
|
|
- <h1 class="text-sm font-bold">编辑游记文章</h1>
|
|
|
- </div>
|
|
|
- <div class="mb-12">
|
|
|
- <van-cell-group class="border" inset>
|
|
|
- <van-field
|
|
|
- v-model="noteJson.projectTitle"
|
|
|
- rows="1"
|
|
|
- autosize
|
|
|
- type="textarea"
|
|
|
- placeholder="从这里开始游记大标题..."
|
|
|
- maxlength="50"
|
|
|
- show-word-limit
|
|
|
- ></van-field>
|
|
|
- </van-cell-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template v-for="(item, index) in noteJson.travelNotesContent" :key="item.tmpId">
|
|
|
- <div v-if="item.type === defaultSectionTitle.type" class="h-50 mb-12 relative box-border">
|
|
|
- <van-cell-group class="border h-full" inset>
|
|
|
+ <div v-if="!loading" class="box-border pb-85">
|
|
|
+ <div v-if="!previewOptions.show">
|
|
|
+ <CreateNoteHeaderBanner v-model:bannerUrl="noteJson.travelNotesBanner" />
|
|
|
+
|
|
|
+ <CreateNoteForm
|
|
|
+ v-model:departureTime="noteJson.departureTime"
|
|
|
+ v-model:countTimes="noteJson.countTimes"
|
|
|
+ v-model:endPlace="noteJson.endPlace"
|
|
|
+ v-model:role="noteJson.role"
|
|
|
+ v-model:travelMode="noteJson.travelMode"
|
|
|
+ v-model:averageCost="noteJson.averageCost"
|
|
|
+ v-model:recommendationRate="noteJson.recommendationRate"
|
|
|
+ v-model:travelNumber="noteJson.travelNumber"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div class="flex items-center pl-16 pt-16 w-full h-40">
|
|
|
+ <div class="w-2 h-14 bg-[#FF9300] mr-16"></div>
|
|
|
+ <h1 class="text-sm font-bold">编辑游记文章</h1>
|
|
|
+ </div>
|
|
|
+ <div class="mb-12">
|
|
|
+ <van-cell-group class="border" inset>
|
|
|
<van-field
|
|
|
- v-model="item.content"
|
|
|
+ v-model="noteJson.projectTitle"
|
|
|
rows="1"
|
|
|
autosize
|
|
|
- class="text-base"
|
|
|
+ clearable
|
|
|
type="textarea"
|
|
|
- trigger="onChange"
|
|
|
- validate-trigger="onChange"
|
|
|
- placeholder="请输入段落标题..."
|
|
|
- @click-input="handleInsertOrEditTitleIndex(index)"
|
|
|
- @update:model-value="handleInsertOrEditTitle"
|
|
|
- >
|
|
|
- <template #extra>
|
|
|
- <div class="w-16 h-16 z-0">
|
|
|
- <img
|
|
|
- @click="handleDeleteTitle(index)"
|
|
|
- class="w-full h-full"
|
|
|
- src="~/assets/img/note-create/delete.svg"
|
|
|
- alt=""
|
|
|
- />
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </van-field>
|
|
|
+ @update:model-value="handleInsertOrEditProjectTitle"
|
|
|
+ placeholder="从这里开始游记大标题..."
|
|
|
+ maxlength="50"
|
|
|
+ show-word-limit
|
|
|
+ ></van-field>
|
|
|
</van-cell-group>
|
|
|
</div>
|
|
|
+ <VueDraggable v-model="noteJson.travelNotesContent" :options="dragOptions">
|
|
|
+ <template v-for="(item, index) in noteJson.travelNotesContent" :key="item.tmpId">
|
|
|
+ <div v-if="item.type === defaultSectionTitle.type" class="h-50 mb-12 relative box-border">
|
|
|
+ <van-cell-group class="border h-full" inset>
|
|
|
+ <van-field
|
|
|
+ v-model="item.content"
|
|
|
+ rows="1"
|
|
|
+ autosize
|
|
|
+ class="text-base"
|
|
|
+ type="textarea"
|
|
|
+ trigger="onChange"
|
|
|
+ validate-trigger="onChange"
|
|
|
+ placeholder="请输入段落标题..."
|
|
|
+ @click-input="handleInsertOrEditTitleIndex(index)"
|
|
|
+ @update:model-value="handleInsertOrEditTitle"
|
|
|
+ >
|
|
|
+ <template #extra>
|
|
|
+ <div class="w-16 h-16 z-0">
|
|
|
+ <img
|
|
|
+ @click="handleDeleteTitle(index)"
|
|
|
+ class="w-full h-full"
|
|
|
+ src="~/assets/img/note-create/delete.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
|
|
|
- <div
|
|
|
- v-else-if="item.type === defaultSectionContent.type"
|
|
|
- class="h-100 mb-12 relative box-border"
|
|
|
- >
|
|
|
- <van-cell-group class="border h-full" inset>
|
|
|
- <van-field
|
|
|
- v-model="item.content"
|
|
|
- rows="1"
|
|
|
- autosize
|
|
|
- class="text-base border"
|
|
|
- type="textarea"
|
|
|
- trigger="onChange"
|
|
|
- validate-trigger="onChange"
|
|
|
- placeholder="请在这里输入游记正文..."
|
|
|
- @click-input="handleInsertOrEditTitleIndex(index)"
|
|
|
- @update:model-value="handleInsertOrEditTitle"
|
|
|
+ <div
|
|
|
+ v-else-if="item.type === defaultSectionContent.type"
|
|
|
+ class="h-100 mb-12 relative box-border"
|
|
|
>
|
|
|
- <template #extra>
|
|
|
- <div class="w-16 h-16 z-0">
|
|
|
- <img
|
|
|
- @click="handleDeleteTitle(index)"
|
|
|
- class="w-full h-full"
|
|
|
- src="../../assets/img/note-create/delete.svg"
|
|
|
- alt=""
|
|
|
- />
|
|
|
+ <!-- focus:outline-none focus:caret-[#FF9300] active:border-[#FF9300] focus:border-[#FF9300]-->
|
|
|
+ <van-cell-group class="border h-full" inset>
|
|
|
+ <van-field
|
|
|
+ autofocus
|
|
|
+ v-model="item.content"
|
|
|
+ rows="1"
|
|
|
+ autosize
|
|
|
+ class="text-base"
|
|
|
+ type="textarea"
|
|
|
+ trigger="onChange"
|
|
|
+ validate-trigger="onChange"
|
|
|
+ placeholder="请在这里输入游记正文..."
|
|
|
+ @click-input="handleInsertOrEditTitleIndex(index)"
|
|
|
+ @update:model-value="handleInsertOrEditTitle"
|
|
|
+ >
|
|
|
+ <template #extra>
|
|
|
+ <div class="w-16 h-16 z-0">
|
|
|
+ <img
|
|
|
+ @click="handleDeleteTitle(index)"
|
|
|
+ class="w-full h-full"
|
|
|
+ src="../../assets/img/note-create/delete.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
+ <!-- 有图片的样式 -->
|
|
|
+ <div v-else-if="item.type === defaultSectionImage.type" class="relative box-border mb-12">
|
|
|
+ <template v-if="item.content">
|
|
|
+ <div>
|
|
|
+ <van-cell-group class="border h-full" inset>
|
|
|
+ <div v-if="item.content">
|
|
|
+ <img :src="item.content" alt="Uploaded Image" />
|
|
|
+ </div>
|
|
|
+ </van-cell-group>
|
|
|
+ <div
|
|
|
+ class="w-110 rounded-xl box-border px-10 h-20 flex justify-between items-center h-16 absolute top-12 right-26 z-100 bg-[#fff]/[0.5]"
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ @click="handleSaveCover(item)"
|
|
|
+ class="text-sm pr-7 border-r-[1px] border-[#F3F3F3] text-black-3"
|
|
|
+ >
|
|
|
+ 设为封面图
|
|
|
+ </span>
|
|
|
+ <div class="w-16 h-16 inline-block">
|
|
|
+ <img
|
|
|
+ @click="handleDeleteImage(index)"
|
|
|
+ class="w-full h-full"
|
|
|
+ src="../../assets/img/note-create/delete.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
- </van-field>
|
|
|
- </van-cell-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div
|
|
|
- v-else-if="item.type === defaultSectionImage.type"
|
|
|
- class="relative box-border h-203 mb-12"
|
|
|
- >
|
|
|
- <van-cell-group class="border h-full" inset>
|
|
|
- <!-- <van-field>
|
|
|
- <template #input>
|
|
|
- <van-uploader v-model="value">
|
|
|
- <template #default>
|
|
|
+ <!-- 没有图片的样式 -->
|
|
|
+ <template v-else>
|
|
|
+ <div class="h-200">
|
|
|
+ <van-cell-group class="border h-full" inset>
|
|
|
+ <!-- <div v-if="itemsImage">
|
|
|
+ <img ref="cropperRef" class="w-full h-full" :src="itemsImage" alt="" />
|
|
|
+ </div> v-else -->
|
|
|
<div class="w-full h-full flex justify-center items-center">
|
|
|
<button
|
|
|
+ @click="handleSelectImage(index)"
|
|
|
class="box-border active:bg-[#000]/[0.1] text-base flex justify-center items-center px-28 py-10 rounded-full border"
|
|
|
>
|
|
|
<div class="h-16 w-16 mr-8">
|
|
|
- <img
|
|
|
- class="w-full h-full"
|
|
|
- src="../../assets/img/note-create/img.svg"
|
|
|
- alt=""
|
|
|
- />
|
|
|
+ <img class="w-full h-full" src="~/assets/img/note-create/img.svg" alt="" />
|
|
|
</div>
|
|
|
|
|
|
插入图片
|
|
|
</button>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </van-uploader>
|
|
|
- </template>
|
|
|
- </van-field> -->
|
|
|
-
|
|
|
- <div class="w-full h-full flex justify-center items-center">
|
|
|
- <van-uploader v-model="fileList" :after-read="afterRead" :multiple="false" >
|
|
|
- <button
|
|
|
- @click="handleInsertOrEditTitleIndex(index)"
|
|
|
- class="box-border active:bg-[#000]/[0.1] text-base flex justify-center items-center px-28 py-10 rounded-full border"
|
|
|
- >
|
|
|
- <div class="h-16 w-16 mr-8">
|
|
|
- <img class="w-full h-full" src="~/assets/img/note-create/img.svg" alt="" />
|
|
|
+ </van-cell-group>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="w-86 flex justify-between items-center h-16 absolute top-10 right-26 z-100"
|
|
|
+ >
|
|
|
+ <span @click="handleSaveCover(item)" class="text-sm text-black-3">
|
|
|
+ 设为封面图
|
|
|
+ </span>
|
|
|
+ <div class="w-16 h-16 inline-block">
|
|
|
+ <img
|
|
|
+ @click="handleDeleteImage(index)"
|
|
|
+ class="w-full h-full"
|
|
|
+ src="~/assets/img/note-create/delete.svg"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
-
|
|
|
- 插入图片
|
|
|
- </button>
|
|
|
- </van-uploader>
|
|
|
-
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
- </van-cell-group>
|
|
|
- <div v-if="item.content ">
|
|
|
- <img :src="item.content" alt="Uploaded Image" />
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
+ </VueDraggable>
|
|
|
+
|
|
|
+ <div class="px-16 flex justify-between">
|
|
|
+ <button
|
|
|
+ @click="handleInsertOrEditTitleOk(defaultSectionTitle)"
|
|
|
+ class="w-110 active:bg-[#000]/[0.1] h-44 box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
+ >
|
|
|
+ <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
+ 插入小标题
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ @click="handleInsertOrEditTitleOk(defaultSectionContent)"
|
|
|
+ class="w-110 h-44 active:bg-[#000]/[0.1] box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
+ >
|
|
|
+ <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
+ 插入内容
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ @click="handleInsertOrEditTitleOk(defaultSectionImage)"
|
|
|
+ class="w-110 active:bg-[#000]/[0.1] h-44 box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
+ >
|
|
|
+ <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
+ 插入图片
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="w-86 flex justify-between items-center h-16 absolute top-[10px] right-26 z-1">
|
|
|
- <span @click="handleSaveCover(item)" class="text-sm text-black-3">设为封面图</span>
|
|
|
- <div class="w-16 h-16 inline-block">
|
|
|
- <img
|
|
|
- @click="handleDeleteImage(index)"
|
|
|
- class="w-full h-full"
|
|
|
- src="../../assets/img/note-create/delete.svg"
|
|
|
- alt=""
|
|
|
- />
|
|
|
+ <div
|
|
|
+ class="fixed box-border p-16 shadow-[0_-4px_4px_0px_rgba(0,0,0,0.1)] bottom-0 left-0 w-full h-80 flex justify-between bg-white items-center"
|
|
|
+ >
|
|
|
+ <div class="flex justify-start items-center h-50">
|
|
|
+ <div class="w-50 text-center" @click="showDialog(draftDialogContent)">
|
|
|
+ <van-icon :name="draft" size="20px" />
|
|
|
+ <p class="text-sm text-black-3">草稿</p>
|
|
|
+ </div>
|
|
|
+ <div class="w-50 text-center" @click="handlePreview">
|
|
|
+ <van-icon name="eye-o" size="24px" />
|
|
|
+ <p class="text-sm text-black-3">预览</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
|
|
|
- <div class="px-16 flex justify-between">
|
|
|
- <button
|
|
|
- @click="handleInsertOrEditTitleOk(defaultSectionTitle)"
|
|
|
- class="w-110 active:bg-[#000]/[0.1] h-44 box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
- >
|
|
|
- <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
- 插入小标题
|
|
|
- </button>
|
|
|
- <button
|
|
|
- @click="handleInsertOrEditTitleOk(defaultSectionContent)"
|
|
|
- class="w-110 h-44 active:bg-[#000]/[0.1] box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
- >
|
|
|
- <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
- 插入内容
|
|
|
- </button>
|
|
|
- <!-- @click="handleInsertOrEditTitleOk(defaultSectionImage)" -->
|
|
|
- <button
|
|
|
- @click="handleInsertOrEditTitleOk(defaultSectionImage)"
|
|
|
- class="w-110 active:bg-[#000]/[0.1] h-44 box-border text-base text-black-3 flex justify-center rounded-md items-center bg-[#F3F3F3]"
|
|
|
- >
|
|
|
- <van-icon name="plus" class="mr-5" color="#FF9300" />
|
|
|
- 插入图片
|
|
|
- </button>
|
|
|
+ <van-button
|
|
|
+ class="w-full h-full flex items-center"
|
|
|
+ size="large"
|
|
|
+ type="primary"
|
|
|
+ round
|
|
|
+ color="#FD9A00"
|
|
|
+ block
|
|
|
+ :loading="publishLoading"
|
|
|
+ @click="handlePublish"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <van-image width="22" height="22" :src="upload" />
|
|
|
+ </template>
|
|
|
+ 发布
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
- <div
|
|
|
- class="fixed box-border p-16 shadow-[0_-4px_4px_0px_rgba(0,0,0,0.1)] bottom-0 left-0 w-full h-80 flex justify-between bg-white items-center"
|
|
|
- >
|
|
|
- <div class="flex justify-start items-center h-50">
|
|
|
- <div class="w-50 text-center" @click="handleSaveDraft">
|
|
|
- <van-icon name="notes-o" size="24px" />
|
|
|
- <p class="text-sm text-black-3">草稿</p>
|
|
|
+ <div v-else class="w-full h-full">
|
|
|
+ <div class="p-10 pb-80">
|
|
|
+ <img
|
|
|
+ v-if="defaultNoteJson?.travelNotesBanner"
|
|
|
+ :src="defaultNoteJson?.travelNotesBanner"
|
|
|
+ class="aspect-[316/204] w-full object-cover rounded-lg"
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ v-else
|
|
|
+ src="~/assets/img/note-create/note_create_banner_bg.png"
|
|
|
+ class="aspect-[316/204] w-full object-cover rounded-lg"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div class="flex mt-10">
|
|
|
+ <img src="~/assets/img/article_title.png" class="w-[32px] h-[32px] shrink-0" alt="" />
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="w-321 line-clamp-2 overflow-hidden truncate max-w-xs ml-10 text-xl whitespace-normal font-bold text-black-3"
|
|
|
+ >
|
|
|
+ {{ defaultNoteJson?.projectTitle ?? '游记标题' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex justify-end text-[#999] text-[12px]">
|
|
|
+ {{ defaultNoteJson.createTime }}
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="relative border-2 border-dashed border-[#E3E3E3] pt-15 pb-15 mt-12 rounded-lg pl-20 text-[#4B99EA] text-[12px]"
|
|
|
+ :style="{ background: `url(${dashBorder2})`, backgroundSize: '100% 100%' }"
|
|
|
+ >
|
|
|
+ <div class="">
|
|
|
+ <van-row>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/date.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">出发时间/</div>
|
|
|
+ <div class="leading-[20px] flex-1">
|
|
|
+ {{ defaultNoteJson?.departureTime || '' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/time.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">出发天数/</div>
|
|
|
+ <div class="leading-[20px] flex-1">{{ defaultNoteJson?.countTimes || '' }}</div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
+ <div class="mt-24">
|
|
|
+ <van-row>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img
|
|
|
+ class="w-[20px] h-[20px] mr-5"
|
|
|
+ src="~/assets/img/yj/relationship.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <div class="font-bold leading-[20px]">人物关系/</div>
|
|
|
+ <div class="leading-[20px] flex-1">{{ defaultNoteJson?.role || '' }}</div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/money.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">人均费用/</div>
|
|
|
+ <div class="leading-[20px] flex-1">{{ defaultNoteJson?.averageCost || '' }}</div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
+ <div class="mt-24">
|
|
|
+ <van-row>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/plan.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">出行方式/</div>
|
|
|
+ <div class="leading-[20px] flex-1">
|
|
|
+ {{ defaultNoteJson?.travelMode || '' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/target.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">目的地/</div>
|
|
|
+ <div class="leading-[20px] flex-1">
|
|
|
+ {{ defaultNoteJson?.endPlace || '' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
+ <div class="mt-24">
|
|
|
+ <van-row>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/person.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">游玩人数/</div>
|
|
|
+ <div class="leading-[20px] flex-1">{{ defaultNoteJson?.travelNumber || '' }}</div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ <van-col span="12">
|
|
|
+ <div class="w-[90%] flex text-[#FD9A00]">
|
|
|
+ <img class="w-[20px] h-[20px] mr-5" src="~/assets/img/yj/star.png" alt="" />
|
|
|
+ <div class="font-bold leading-[20px]">推荐指数/</div>
|
|
|
+ <div class="leading-[20px] flex-1">
|
|
|
+ {{ defaultNoteJson?.recommendationRate || '' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-col>
|
|
|
+ </van-row>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="w-50 text-center">
|
|
|
- <van-icon name="eye-o" size="24px" />
|
|
|
- <p class="text-sm text-black-3">预览</p>
|
|
|
+ <div class="mt-10" v-for="con in defaultNoteJson.travelNotesContent" :key="con.id">
|
|
|
+ <template v-if="con.type == 'image'">
|
|
|
+ <img :src="con.content" class="w-[full] rounded-xl" alt="" />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div v-html="con.content"></div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <van-button
|
|
|
- class="w-full h-full flex items-center"
|
|
|
- size="large"
|
|
|
- type="primary"
|
|
|
- round
|
|
|
- color="#FD9A00"
|
|
|
- block
|
|
|
+ <div
|
|
|
+ style="justify-content: space-between"
|
|
|
+ class="fixed box-border p-16 shadow-[0_-4px_4px_0px_rgba(0,0,0,0.1)] bottom-0 left-0 w-full h-80 flex justify-between bg-white items-center"
|
|
|
>
|
|
|
- <template #icon>
|
|
|
- <van-image width="22" height="22" :src="upload" />
|
|
|
- </template>
|
|
|
- 发布
|
|
|
- </van-button>
|
|
|
- </div>
|
|
|
+ <div class="w-165">
|
|
|
+ <van-button
|
|
|
+ @click="handlePreview"
|
|
|
+ style="color: #fd9a00"
|
|
|
+ class="w-full h-full flex items-center"
|
|
|
+ size="large"
|
|
|
+ type="primary"
|
|
|
+ round
|
|
|
+ color="#FFF7E6"
|
|
|
+ >
|
|
|
+ 继续编辑
|
|
|
+ </van-button>
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="flex justify-center">
|
|
|
- <div class="mx-auto mt-30 flex w-wrap space-x-50">
|
|
|
- <div>
|
|
|
- <!-- <VueDraggable v-model="noteJson.travelNotesContent">
|
|
|
- <template
|
|
|
- v-for="(item, index) in noteJson.travelNotesContent"
|
|
|
- :key="item.tmpId"
|
|
|
- >
|
|
|
- <CreateNoteInsertTitleSection
|
|
|
- v-if="item.type === defaultSectionTitle.type"
|
|
|
- :title="item.content"
|
|
|
- @onEdit="handleInsertOrEditTitle(index)"
|
|
|
- @onDelete="handleDeleteTitle(index)"
|
|
|
- />
|
|
|
- <template v-else-if="item.type === defaultSectionContent.type">
|
|
|
- <CreateNoteInsertContentSection
|
|
|
- v-model="item.content"
|
|
|
- @on-delete="handleDeleteContent(index)"
|
|
|
- />
|
|
|
- </template>
|
|
|
- <template v-else-if="item.type === defaultSectionImage.type">
|
|
|
- <CreateNoteInsertImageSection
|
|
|
- :url="item.content"
|
|
|
- @on-save-cover="handleSaveCover(item)"
|
|
|
- @on-delete="handleDeleteImage(index)"
|
|
|
- />
|
|
|
- </template>
|
|
|
- </template>
|
|
|
- </VueDraggable> -->
|
|
|
- <!-- <CreateNoteBottomActions
|
|
|
- class="mt-50"
|
|
|
- :publishLoading="publishLoading"
|
|
|
- @on-preview="handlePreview"
|
|
|
- @on-publish="handlePublish"
|
|
|
- /> -->
|
|
|
+ <div class="w-165">
|
|
|
+ <van-button
|
|
|
+ class="w-full h-full flex items-center"
|
|
|
+ size="large"
|
|
|
+ type="primary"
|
|
|
+ round
|
|
|
+ color="#FD9A00"
|
|
|
+ block
|
|
|
+ :loading="publishLoading"
|
|
|
+ @click="handlePublish"
|
|
|
+ >
|
|
|
+ <template #icon>
|
|
|
+ <van-image width="22" height="22" :src="upload" />
|
|
|
+ </template>
|
|
|
+ 确定发布
|
|
|
+ </van-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- <CreateNoteInsertTitleModal
|
|
|
- v-model:visible="insertTilteOptions.show"
|
|
|
- :title="insertTilteOptions.content"
|
|
|
- @on-ok="handleInsertOrEditTitleOk"
|
|
|
- /> -->
|
|
|
- <!-- <CreateNoteInsertImageModal
|
|
|
- v-model:visible="insertImageOptions.show"
|
|
|
- @on-ok="handleInsertImageOk"
|
|
|
- /> -->
|
|
|
- <!-- <CreateNotePreviewModal
|
|
|
- v-model:visible="previewOptions.show"
|
|
|
- :data="noteJson"
|
|
|
- /> -->
|
|
|
- <!-- <CreateNoteUserInfoModal
|
|
|
+ <CreateNoteUserInfoModal
|
|
|
v-model:visible="userInfoOptions.show"
|
|
|
@submit-ok="handleCollectUserInfoOk"
|
|
|
- /> -->
|
|
|
- <!-- <CreateNotePublishResultModal
|
|
|
- v-model:visible="publishResultModalOptions.show"
|
|
|
- /> -->
|
|
|
+ />
|
|
|
+ <CreateNotePublishResultModal v-model:visible="publishResultModalOptions" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
+import { useFileDialog } from '@vueuse/core'
|
|
|
import upload from '~/assets/img/note-create/upload.svg'
|
|
|
-import { cloneDeep } from 'lodash-es'
|
|
|
-// import { VueDraggable } from 'vue-draggable-plus'
|
|
|
+import draft from '~/assets/img/note-create/draft.svg'
|
|
|
+// import { cloneDeep } from 'lodash-es'
|
|
|
+import { VueDraggable } from 'vue-draggable-plus'
|
|
|
import { nanoid } from 'nanoid'
|
|
|
+const useAuth = useAuthStore()
|
|
|
+const { token } = storeToRefs(useAuth)
|
|
|
+
|
|
|
+const dragOptions = {
|
|
|
+ disabled: false, // 是否禁用拖拽
|
|
|
+ animation: 150 // 拖拽时的动画效果持续时间
|
|
|
+}
|
|
|
+
|
|
|
+const { open, onChange } = useFileDialog({
|
|
|
+ accept: '.png,.png,.jpeg,.JPG,Png '
|
|
|
+})
|
|
|
|
|
|
const { loading, setLoading } = useLoading()
|
|
|
loading.value = false
|
|
@@ -309,15 +442,42 @@ const noteJson = reactive(defaultNoteJson)
|
|
|
|
|
|
watch(noteJson, () => {}, { deep: true })
|
|
|
|
|
|
-// const id = useRouteQuery('id')
|
|
|
+const id = useRouteQuery('id')
|
|
|
+console.log(noteJson.projectTitle, 'projectTitle')
|
|
|
+
|
|
|
+watch(
|
|
|
+ id,
|
|
|
+ () => {
|
|
|
+ getNoteDetail()
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+)
|
|
|
+
|
|
|
+// 删除的弹窗内容
|
|
|
+const deleteDialogContent = {
|
|
|
+ title: '温馨提示',
|
|
|
+ message: '是否删除',
|
|
|
+ confirmButtonColor: '#FF9300'
|
|
|
+}
|
|
|
|
|
|
-// watch(
|
|
|
-// id,
|
|
|
-// () => {
|
|
|
-// // getNoteDetail()
|
|
|
-// },
|
|
|
-// { immediate: true }
|
|
|
-// )
|
|
|
+// 保存草稿的弹窗内容
|
|
|
+const draftDialogContent = {
|
|
|
+ title: '是否保存到草稿箱',
|
|
|
+ message: '保存后,可在“我的-我的游记-草稿箱”查看',
|
|
|
+ confirmButtonText: '保存草稿',
|
|
|
+ confirmButtonColor: '#FF9300',
|
|
|
+ cancelButtonText: '不保存'
|
|
|
+}
|
|
|
+
|
|
|
+// 显示弹窗
|
|
|
+const showDialog = (parmas) => {
|
|
|
+ showConfirmDialog(parmas)
|
|
|
+ .then(() => {
|
|
|
+ // getNoteDetail()
|
|
|
+ handleSaveDraft()
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
+}
|
|
|
|
|
|
// 获取草稿详情
|
|
|
async function getNoteDetail() {
|
|
@@ -352,13 +512,18 @@ const insertTilteOptions = reactive({
|
|
|
content: null,
|
|
|
editIndex: null
|
|
|
})
|
|
|
+
|
|
|
const editIndex = ref(null)
|
|
|
|
|
|
-// 点击编辑或者新增段落标题,弹出dialog
|
|
|
+// 点击那个插入的内容那个就是框的下标
|
|
|
function handleInsertOrEditTitleIndex(index) {
|
|
|
editIndex.value = index
|
|
|
}
|
|
|
|
|
|
+// 点击编辑大标题,
|
|
|
+function handleInsertOrEditProjectTitle(value) {
|
|
|
+ noteJson.travelNotesContent.projectTitle = value
|
|
|
+}
|
|
|
// 点击编辑或者新增段落标题,弹出dialog
|
|
|
function handleInsertOrEditTitle(value) {
|
|
|
noteJson.travelNotesContent[editIndex.value].content = value
|
|
@@ -366,7 +531,6 @@ function handleInsertOrEditTitle(value) {
|
|
|
|
|
|
// 确认编辑或者新增段落标题
|
|
|
function handleInsertOrEditTitleOk(newTitle) {
|
|
|
- // if (insertTilteOptions.editIndex === null) {
|
|
|
noteJson.travelNotesContent.push({
|
|
|
...newTitle,
|
|
|
tmpId: nanoid()
|
|
@@ -375,33 +539,63 @@ function handleInsertOrEditTitleOk(newTitle) {
|
|
|
|
|
|
// 删除段落标题
|
|
|
function handleDeleteTitle(index) {
|
|
|
- noteJson.travelNotesContent.splice(index, 1)
|
|
|
+ showConfirmDialog(deleteDialogContent)
|
|
|
+ .then(() => {
|
|
|
+ noteJson.travelNotesContent.splice(index, 1)
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
}
|
|
|
|
|
|
/******************插入正文相关逻辑*******************/
|
|
|
|
|
|
-function handleInsertContent() {
|
|
|
- noteJson.travelNotesContent.push(
|
|
|
- cloneDeep({
|
|
|
- ...defaultSectionContent,
|
|
|
- tmpId: nanoid()
|
|
|
- })
|
|
|
- )
|
|
|
+const imageLoading = ref(false)
|
|
|
+
|
|
|
+// 单个点击上传图片的事件
|
|
|
+const handleSelectImage = (index) => {
|
|
|
+ handleInsertOrEditTitleIndex(index)
|
|
|
+ open()
|
|
|
}
|
|
|
|
|
|
-// function handleDeleteContent(index) {
|
|
|
-// noteJson.travelNotesContent.splice(index, 1)
|
|
|
-// }
|
|
|
+onChange((files) => {
|
|
|
+ if (!files.length) return
|
|
|
+ const reader = new FileReader()
|
|
|
+ reader.readAsDataURL(files[0])
|
|
|
+ reader.onload = () => {
|
|
|
+ if (noteJson.travelNotesContent[editIndex.value].type == 'image') {
|
|
|
+ noteJson.travelNotesContent[editIndex.value].content = reader.result
|
|
|
+ }
|
|
|
|
|
|
-/******************插入图片逻辑*******************/
|
|
|
-const insertImageOptions = reactive({
|
|
|
- show: false
|
|
|
+ handleCropperOk(files[0])
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
-function handleInsertImage() {
|
|
|
- insertImageOptions.show = true
|
|
|
+async function handleCropperOk(data) {
|
|
|
+ console.log(data, '12222')
|
|
|
+ try {
|
|
|
+ // imageLoading.value = true
|
|
|
+ // 此处需上传图片,保存URL
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append('uploadFile', data)
|
|
|
+ formData.append('asImage', true)
|
|
|
+ formData.append('fieldName', 'travelNotesBanner')
|
|
|
+
|
|
|
+ console.log(formData, 'formData')
|
|
|
+
|
|
|
+ const res = await request('/admin/app/tourismProjectTravelNotesWrite/upload', {
|
|
|
+ method: 'post',
|
|
|
+ body: formData
|
|
|
+ })
|
|
|
+ const url = res.data.fileUrl
|
|
|
+ if (noteJson.travelNotesContent[editIndex.value].type == 'image') {
|
|
|
+ noteJson.travelNotesContent[editIndex.value].content = url
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ // imageLoading.value = false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+/******************插入图片逻辑*******************/
|
|
|
+
|
|
|
// function handleInsertImageOk(fileUrlList) {
|
|
|
// const imageList = fileUrlList.map((e) => ({
|
|
|
// type: defaultSectionImage.type,
|
|
@@ -412,9 +606,13 @@ function handleInsertImage() {
|
|
|
// }
|
|
|
|
|
|
function handleDeleteImage(index) {
|
|
|
- if (noteJson.travelNotesContent[index].type === 'image') {
|
|
|
- noteJson.travelNotesContent.splice(index, 1)
|
|
|
- }
|
|
|
+ showConfirmDialog(deleteDialogContent)
|
|
|
+ .then(() => {
|
|
|
+ if (noteJson.travelNotesContent[index].type === 'image') {
|
|
|
+ noteJson.travelNotesContent.splice(index, 1)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
}
|
|
|
|
|
|
// 设为封面图
|
|
@@ -428,57 +626,13 @@ function handleSaveCover(item) {
|
|
|
showToast('设置封面成功')
|
|
|
}
|
|
|
|
|
|
-const fileList = ref([])
|
|
|
-// 图片上传
|
|
|
-const afterRead = (file) => {
|
|
|
- // 此时可以自行将文件上传至服务器
|
|
|
- uploadFile(file)
|
|
|
-
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-const useAuth = useAuthStore()
|
|
|
-const { token } = storeToRefs(useAuth)
|
|
|
-
|
|
|
-const uploadUrl = `${import.meta.env.VITE_APP_BASE_URL}/admin/app/tourismProjectTravelNotesWrite/upload`
|
|
|
-
|
|
|
-const uploadFile = (file) => {
|
|
|
- // 使用 FormData 来包装文件,模拟表单提交
|
|
|
- const formData = new FormData();
|
|
|
- formData.append('file', file);
|
|
|
- // 这里假设使用 axios 进行文件上传
|
|
|
- request(uploadUrl, formData, {
|
|
|
- headers: {
|
|
|
- Authorization:token,
|
|
|
- 'Content-Type': 'multipart/form-data'
|
|
|
- }
|
|
|
- }).then(res => {
|
|
|
- console.log(res,'img1111');
|
|
|
- // noteJson.travelNotesContent.map(el=>{
|
|
|
- // if (el.type==='image') {
|
|
|
- // noteJson.travelNotesContent[editIndex.value].content=''
|
|
|
- // }
|
|
|
- // })
|
|
|
-
|
|
|
-
|
|
|
- // 处理上传成功的逻辑
|
|
|
- // Toast('上传成功');
|
|
|
- }).catch(err=> {
|
|
|
- console.log(err,'img');
|
|
|
-
|
|
|
- // 处理上传失败的逻辑
|
|
|
- // Toast('上传失败,请重试');
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 保存为草稿
|
|
|
async function handleSaveDraft() {
|
|
|
try {
|
|
|
await request('/website/tourism/publishTravelNotes/saveDraft', {
|
|
|
method: 'post',
|
|
|
body: {
|
|
|
...noteJson,
|
|
|
- // id: id?.value
|
|
|
+ id: id?.value
|
|
|
}
|
|
|
})
|
|
|
showToast('草稿保存成功')
|
|
@@ -490,8 +644,9 @@ async function handleSaveDraft() {
|
|
|
const previewOptions = reactive({
|
|
|
show: false
|
|
|
})
|
|
|
+
|
|
|
function handlePreview() {
|
|
|
- previewOptions.show = true
|
|
|
+ previewOptions.show = !previewOptions.show
|
|
|
}
|
|
|
|
|
|
// 收集个人信息
|
|
@@ -500,17 +655,16 @@ const userInfoOptions = reactive({
|
|
|
})
|
|
|
|
|
|
function handleCollectUserInfoOk() {
|
|
|
- // requestPublish()
|
|
|
+ requestPublish()
|
|
|
}
|
|
|
|
|
|
-const publishResultModalOptions = reactive({
|
|
|
- show: false
|
|
|
-})
|
|
|
+const publishResultModalOptions = ref(false)
|
|
|
|
|
|
// 发布
|
|
|
async function handlePublish() {
|
|
|
if (!noteJson.travelNotesBanner) {
|
|
|
showNotify({
|
|
|
+ type: 'warning',
|
|
|
message: '请设置游记头图',
|
|
|
duration: 3000
|
|
|
})
|
|
@@ -518,6 +672,7 @@ async function handlePublish() {
|
|
|
}
|
|
|
if (!noteJson.projectTitle) {
|
|
|
showNotify({
|
|
|
+ type: 'warning',
|
|
|
message: '请输入游记标题',
|
|
|
duration: 3000
|
|
|
})
|
|
@@ -525,6 +680,7 @@ async function handlePublish() {
|
|
|
}
|
|
|
if (!noteJson.endPlace) {
|
|
|
showNotify({
|
|
|
+ type: 'warning',
|
|
|
message: '请选择目的地',
|
|
|
duration: 3000
|
|
|
})
|
|
@@ -532,6 +688,7 @@ async function handlePublish() {
|
|
|
}
|
|
|
if (noteJson.travelNotesContent.length === 0) {
|
|
|
showNotify({
|
|
|
+ type: 'warning',
|
|
|
message: '游记内容不能为空',
|
|
|
duration: 3000
|
|
|
})
|
|
@@ -543,27 +700,32 @@ async function handlePublish() {
|
|
|
// 需要收集个人信息
|
|
|
userInfoOptions.show = true
|
|
|
} else {
|
|
|
- // requestPublish()
|
|
|
+ requestPublish()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const publishLoading = ref(false)
|
|
|
-// async function requestPublish() {
|
|
|
-// try {
|
|
|
-// publishLoading.value = true
|
|
|
-// await request('/website/tourism/publishTravelNotes/publishDraft', {
|
|
|
-// method: 'post',
|
|
|
-// body: {
|
|
|
-// ...noteJson,
|
|
|
-// id: id.value
|
|
|
-// }
|
|
|
-// })
|
|
|
-// publishResultModalOptions.show = true
|
|
|
-// publishLoading.value = false
|
|
|
-// } catch (error) {
|
|
|
-// publishLoading.value = false
|
|
|
-// }
|
|
|
-// }
|
|
|
+async function requestPublish() {
|
|
|
+ try {
|
|
|
+ publishLoading.value = true
|
|
|
+ await request('/website/tourism/publishTravelNotes/publishDraft', {
|
|
|
+ method: 'post',
|
|
|
+ body: {
|
|
|
+ ...noteJson,
|
|
|
+ id: id.value
|
|
|
+ }
|
|
|
+ })
|
|
|
+ publishResultModalOptions.value = true
|
|
|
+ publishLoading.value = false
|
|
|
+ } catch (error) {
|
|
|
+ publishLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
-<style lang="scss" scoped></style>
|
|
|
+<style lang="scss" scoped>
|
|
|
+::v-deep .van-field:focus {
|
|
|
+ caret-color: #ff9300 !important;
|
|
|
+ outline: none;
|
|
|
+}
|
|
|
+</style>
|