Quellcode durchsuchen

feat:写游记的改版 和详情改版

suwenjiang vor 1 Monat
Ursprung
Commit
26871d6adc

+ 4 - 2
.env.development

@@ -5,6 +5,8 @@ VITE_APP_ENV=development
 # VITE_APP_BASE_URL=https://service.xiaoyaotravel.com/api/
 # VITE_APP_BASE_URL=http://101.126.146.250:8082/
 # VITE_APP_IM_URL=ws://101.126.146.250:8082/system/message
+VITE_APP_BASE_URL=http://101.126.146.250:8084/
+VITE_APP_IM_URL=ws://101.126.146.250:8084/system/message
 
 
 
@@ -19,9 +21,9 @@ VITE_APP_ENV=development
 # VITE_APP_BASE_URL=http://cilicli.qicp.vip
 
 # 黄雯本地
-VITE_APP_BASE_URL=http://192.168.1.44:8082/
+# VITE_APP_BASE_URL=http://192.168.1.44:8082/
 # 本地socoket
-VITE_APP_IM_URL=ws://192.168.1.44:8082/system/message
+# VITE_APP_IM_URL=ws://192.168.1.44:8082/system/message
 # 花生壳
 # VITE_APP_BASE_URL=http://q9943037p3.goho.co
 # VITE_APP_IM_URL=ws://q9943037p3.goho.co/system/message

+ 68 - 41
src/components/CreateNote/Form.vue

@@ -41,7 +41,7 @@
       position="bottom"
     >
       <van-cell-group inset>
-        <van-cell @click="isPublic = 0" title="公开可见" center>
+        <van-cell @click="(isPublic = 0), (showPublic = false)" title="公开可见" center>
           <template #icon>
             <span class="iconfont icon-unlock text-black-3 mr-12" style="font-size: 16px"></span>
           </template>
@@ -50,7 +50,7 @@
             <img class="w-16 h-16" :src="check" alt="" />
           </template>
         </van-cell>
-        <van-cell @click="isPublic = 1" title="仅自己可见" center>
+        <van-cell @click="(isPublic = 1), (showPublic = false)" title="仅自己可见" center>
           <template #icon>
             <span class="iconfont icon-lock text-black-3 mr-12" style="font-size: 16px"></span>
           </template>
@@ -62,7 +62,7 @@
       </van-cell-group>
     </van-popup>
 
-    <van-cell @click="getChatGroupList" size="large" title="关联群聊" center is-link>
+    <van-cell @click="showChatGroup = true" size="large" title="关联群聊" center is-link>
       <template #icon>
         <span class="iconfont icon-chatgroup text-black-3 mr-12" style="font-size: 16px"></span>
       </template>
@@ -77,38 +77,56 @@
       destroy-on-close
       position="bottom"
     >
-      <div class="h-322 w-full box-border py-16">
+      <div class="h-390 w-full box-border py-16">
         <div
-          class="w-full flex box-border mb-16 px-12 justify-between items-center text-xl font-semibold"
+          class="w-full flex box-border pb-16 border-b-[1px] border-[#FAFAFA] px-12 justify-between items-center text-xl font-semibold"
         >
           <span @click="showChatGroup = false">取消</span>
-          <span class="text-[#FF9300]" @click="showChatGroup = false">确认</span>
-        </div>
-        <van-radio-group v-model="checked" shape="round">
-          <van-cell
-            v-for="(item, i) in chatGroupList"
-            :key="item?.id"
-            :title="item?.groupName"
-            :label="item?.numCount ? item?.numCount + '人' : ''"
-            clickable
-            center
+          <span
+            class="text-[#FF9300]"
             @click="
               () => {
-                checked = item?.id
-                chatGroupName = item?.groupName
+                showChatGroup = false
+                tourImGroupId = checked
               }
             "
           >
-            <template v-if="item?.heardImage" #icon>
-              <div class="mr-8">
-                <MultiHeader :size="44" :imgUrls="item?.heardImage" />
-              </div>
-            </template>
-            <template #right-icon>
-              <van-radio checked-color="#FF9300" :name="item?.id" />
-            </template>
-          </van-cell>
-        </van-radio-group>
+            确认
+          </span>
+        </div>
+
+        <van-list class="h-332 overflow-y-auto">
+          <van-radio-group v-model="checked" shape="round">
+            <van-cell
+              v-for="(item, i) in chatGroupList"
+              :key="item?.id"
+              :title="item?.groupName"
+              :label="item?.numCount ? item?.numCount + '人' : ''"
+              clickable
+              center
+              @click="
+                () => {
+                  checked = item?.id
+                  // chatGroupName = item?.groupName
+                }
+              "
+            >
+              <template #icon>
+                <div class="w-44 h-44 rounded-full mr-8 overflow-hidden">
+                  <img
+                    v-if="item?.groupAvatarUrl"
+                    class="w-full h-full object-cover"
+                    :src="item?.groupAvatarUrl"
+                    alt=""
+                  />
+                </div>
+              </template>
+              <template #right-icon>
+                <van-radio checked-color="#FF9300" :name="item?.id" />
+              </template>
+            </van-cell>
+          </van-radio-group>
+        </van-list>
       </div>
     </van-popup>
 
@@ -264,10 +282,13 @@ const travelModeId = defineModel('travelMode')
 const travelNumber = defineModel('travelNumber')
 const chau = defineModel('chau')
 const chauId = defineModel('chauId')
+const isPublic = defineModel('isPublic') //是否公开
+const tourImGroupId = defineModel('tourImGroupId') //是否公开
 
 onMounted(() => {
   getPlaceOptions()
   getTravelModeOptions()
+  getChatGroupList()
 })
 
 const labelWidth = '81px'
@@ -278,13 +299,9 @@ const maxDate = new Date()
 const showCalendar = ref(false)
 const showFrom = ref(false) //是否显示整个表单
 const showPublic = ref(false) //是否显示公开
-const isPublic = ref(0) //是否公开
 
 const showChatGroup = ref(false) //是否显示群聊
 const checked = ref('') //是否显示群聊
-const chatGroup = ref({}) //选择群聊的结果
-const chatGroupName = ref('') //选择群聊的名称
-const endPlaceValue = ref('') //选择目的的名称
 
 // 展示时间的格式
 const onConfirm = (date) => {
@@ -355,21 +372,31 @@ async function getTravelModeOptions() {
 const chatGroupList = ref([])
 async function getChatGroupList() {
   try {
-    showChatGroup.value = true
-    const { data } = await request('/website/tourGroup/getOwnGroup')
-    // const { data } = await request(
-    //   '/website/tourism/publishTravelNotes/getTakePartImGroupListByName',
-    //   {
-    //     query: {
-    //       name: ''
-    //     }
-    //   }
-    // )
+    // const { data } = await request('/website/tourGroup/getOwnGroup')
+    const { data } = await request(
+      '/website/tourism/publishTravelNotes/getTakePartImGroupListByName',
+      {
+        query: {
+          name: '',
+          pageSize: 10,
+          pageNum: 1
+        }
+      }
+    )
     if (data) {
       chatGroupList.value = data
     }
   } catch (error) {}
 }
+
+//选择群聊的名称
+const chatGroupName = computed(() => {
+  if (tourImGroupId.value) {
+    return chatGroupList.value?.filter((i) => i.id == tourImGroupId.value)[0].groupName
+  } else {
+    return ''
+  }
+})
 </script>
 
 <style lang="scss" scoped>

+ 1 - 0
src/components/Profile/InteractionMessage/ReceiveComment.vue

@@ -154,3 +154,4 @@ const bgColor = (color) => {
 
 </script>
 <style lang="scss" scoped></style>
+~/pages/_yj/emoji.json

+ 1 - 1
src/middleware/create-note.global.js

@@ -10,7 +10,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
       const res = await request('/website/tourism/publishTravelNotes/getDraftId')
       const id = res.data
       return navigateTo({
-        path: '/note-create2',
+        path: '/note-create',
         query: {
           id
         },

+ 241 - 416
src/pages/note-create2/index.client.vue → src/pages/_note-create/index.client.vue

@@ -1,230 +1,232 @@
 <template>
   <div v-if="!loading" class="box-border pb-110">
     <div v-if="!previewOptions.show">
-      <CreateNoteHeaderImage
-        v-model:bannerUrl="noteJson.travelNotesBanner"
-        v-model:imgUrls="noteJson.imgUrls"
-        v-model:show="showExpandTextInput"
+      <CreateNoteHeaderBanner v-model:bannerUrl="noteJson.travelNotesBanner" />
+      <div class="mt-12">
+        <van-cell-group class="border" inset>
+          <van-field
+            style="font-size: 16px; font-weight: 600"
+            size="large"
+            v-model="noteJson.projectTitle"
+            rows="1"
+            autosize
+            clearable
+            type="textarea"
+            @update:model-value="handleInsertOrEditProjectTitle"
+            placeholder="从这里开始游记大标题..."
+            maxlength="50"
+            show-word-limit
+          ></van-field>
+        </van-cell-group>
+      </div>
+      <CreateNoteForm
+        v-model:departureTime="noteJson.departureTime"
+        v-model:countTimes="noteJson.countTimes"
+        v-model:endPlace="noteJson.endPlace"
+        v-model:endPlaceId="noteJson.endPlaceId"
+        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"
       />
 
-      <van-cell-group class="border-b-[1px]" inset>
-        <van-field
-          style="font-size: 16px; font-weight: 600"
-          size="large"
-          v-model="noteJson.projectTitle"
-          rows="1"
-          autosize
-          clearable
-          type="textarea"
-          @update:model-value="handleInsertOrEditProjectTitle"
-          @change=""
-          placeholder="请输入游记标题"
-          maxlength="50"
-        ></van-field>
-      </van-cell-group>
-
-      <div style="overflow: hidden; overflow-y: scroll" class="h-200">
-        <VueDraggable
-          :scroll="true"
-          :handle="'.drag'"
-          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="mb-12 box-border">
-              <van-cell-group
-                class="min-h-50 flex h-full focus:border-[#FF9300] active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
-                inset
-              >
-                <van-field
-                  v-model="item.content"
-                  rows="1"
-                  autosize
-                  class="text-base h-full"
-                  type="textarea"
-                  trigger="onChange"
-                  maxlength="30"
-                  validate-trigger="onChange"
-                  placeholder="请输入段落标题..."
-                  @click-input="handleInsertOrEditTitleIndex(index)"
-                  @update:model-value="handleInsertOrEditTitle"
-                >
-                  <template v-if="noteJson.travelNotesContent.length > 1" #extra>
-                    <div class="flex">
-                      <div class="h-16 drag flex mr-10 items-center">
-                        <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
-                        <span class="text-sm text-black-3">拖拽</span>
-                      </div>
-                      <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>
-                    </div>
-                  </template>
-                </van-field>
-              </van-cell-group>
-            </div>
-
-            <div
-              v-else-if="item.type === defaultSectionContent.type"
-              class="mb-12 relative box-border"
+      <div class="flex items-center pl-16 pt-16 w-full h-40">
+        <div class="w-2 h-14 bg-[#FF9300] mr-8"></div>
+        <h1 class="text-sm font-bold">编辑游记文章</h1>
+      </div>
+
+      <VueDraggable
+        :scroll="true"
+        :handle="'.drag'"
+        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="mb-12 box-border">
+            <van-cell-group
+              class="min-h-50 border flex h-full focus:border-[#FF9300] active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
+              inset
             >
-              <van-cell-group
-                class="min-h-100 active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
-                inset
+              <van-field
+                v-model="item.content"
+                rows="1"
+                autosize
+                class="text-base h-full"
+                type="textarea"
+                trigger="onChange"
+                maxlength="30"
+                validate-trigger="onChange"
+                placeholder="请输入段落标题..."
+                @click-input="handleInsertOrEditTitleIndex(index)"
+                @update:model-value="handleInsertOrEditTitle"
               >
-                <!-- <div
-                  class="w-full h-200"
-                  @click="handleInsertOrEditTitleIndex(index)"
-                  @change="handleInsertOrEditTitle"
-                  @update="handleInsertOrEditTitle"
-                  contenteditable
-                  @input="handleInsertOrEditTitle"
-                  v-html="item.content ? item.content : '请在这里输入游记正文...'"
-                ></div> -->
-                <van-field
-                  autofocus
-                  v-model="item.content"
-                  rows="3"
-                  autosize
-                  maxlength="5000"
-                  class="text-base"
-                  type="textarea"
-                  trigger="onChange"
-                  validate-trigger="onChange"
-                  placeholder="请在这里输入游记正文..."
-                  @click-input="handleInsertOrEditTitleIndex(index)"
-                  @update:model-value="handleInsertOrEditTitle"
-                >
-                  <template v-if="noteJson.travelNotesContent.length > 1" #extra>
-                    <div class="flex">
-                      <div class="h-16 drag flex mr-10 items-center">
-                        <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
-                        <span class="text-sm text-black-3">拖拽</span>
-                      </div>
-                      <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 #extra>
+                  <div class="flex">
+                    <div class="h-16 drag flex mr-10 items-center">
+                      <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
+                      <span class="text-sm text-black-3">拖拽</span>
                     </div>
-                  </template>
-                </van-field>
-              </van-cell-group>
-            </div>
-          </template>
-        </VueDraggable>
-      </div>
-      <div
-        v-if="(topicList && topicList.length) || (eitList && eitList.length)"
-        class="w-full px-16 box-border max-h-227 overflow-y-auto overflow-hidden"
-      >
-        <!-- 话题 -->
-        <template v-if="showTopicEit == TOPIC_TEXT">
-          <div
-            v-for="item in topicList"
-            :key="item?.userId"
-            class="w-full flex justify-between items-center mb-20"
-            @click="handleTopicAndEit(item, '#')"
-          >
-            <p v-if="item?.topicName" class="w-246 text-sm text-black-6 line-clamp-1">
-              # {{ item?.topicName }}
-            </p>
-            <p class="text-sm text-black-6 line-clamp-1">
-              {{
-                formatNumber(Number(item?.totalViewCount))
-                  ? `${formatNumber(Number(item?.totalViewCount))}次浏览`
-                  : ''
-              }}
-            </p>
+                    <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>
+                  </div>
+                </template>
+              </van-field>
+            </van-cell-group>
           </div>
-        </template>
 
-        <template v-if="showTopicEit == EIT_TEXT">
-          <!-- 艾特的好友 -->
           <div
-            v-for="item in eitList"
-            :key="item?.userId"
-            class="w-full flex justify-start items-center mb-12"
-            @click="handleTopicAndEit(item, '@')"
+            v-else-if="item.type === defaultSectionContent.type"
+            class="mb-12 relative box-border"
           >
-            <div class="w-30 h-30 rounded-full shrink-0 overflow-hidden mr-8">
-              <img class="w-full h-full object-cover" :src="item?.headImageUrl" alt="" />
-            </div>
-            <p class="text-sm text-black-6 line-clamp-1">{{ item?.showName }}</p>
+            <van-cell-group
+              class="border min-h-100 active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
+              inset
+            >
+              <van-field
+                autofocus
+                v-model="item.content"
+                rows="3"
+                autosize
+                maxlength="5000"
+                class="text-base"
+                type="textarea"
+                trigger="onChange"
+                validate-trigger="onChange"
+                placeholder="请在这里输入游记正文..."
+                @click-input="handleInsertOrEditTitleIndex(index)"
+                @update:model-value="handleInsertOrEditTitle"
+              >
+                <template #extra>
+                  <div class="flex">
+                    <div class="h-16 drag flex mr-10 items-center">
+                      <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
+                      <span class="text-sm text-black-3">拖拽</span>
+                    </div>
+                    <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>
+                  </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 active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
+                  inset
+                >
+                  <div v-if="item.content">
+                    <img :src="item.content" alt="Uploaded Image" />
+                  </div>
+                </van-cell-group>
+                <div
+                  class="w-150 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 text-black-3">
+                    设为封面图
+                  </span>
+                  <div class="drag flex items-center border-r-[1px] border-[#F3F3F3] pr-7">
+                    <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
+                    <span class="text-sm text-black-3">拖拽</span>
+                  </div>
+
+                  <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>
+            <!-- 没有图片的样式 -->
+            <template v-else>
+              <div class="h-200">
+                <van-cell-group
+                  class="border h-full active:shadow-[_0px_6px_4px_0px_rgba(0,0,0,0.25)]"
+                  inset
+                >
+                  <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="" />
+                      </div>
+
+                      插入图片
+                    </button>
+                  </div>
+                </van-cell-group>
+
+                <div
+                  class="w-136 flex justify-between items-center h-16 absolute top-10 right-26 z-100"
+                >
+                  <span @click="showToast('请上传图片')" class="text-sm text-black-3">
+                    设为封面图
+                  </span>
+                  <div class="drag flex pr-7 items-center">
+                    <img class="w-16 h-16" src="~/assets/img/note-create/drag.svg" alt="" />
+                    <span class="text-sm text-black-3">拖拽</span>
+                  </div>
+
+                  <div class="w-16 h-16 inline-block">
+                    <img
+                      @click="handleDeleteImage(index)"
+                      class="w-full h-full drag"
+                      src="~/assets/img/note-create/delete.svg"
+                      alt=""
+                    />
+                  </div>
+                </div>
+              </div>
+            </template>
           </div>
         </template>
-      </div>
+      </VueDraggable>
 
-      <div class="px-16 flex justify-start mb-12">
+      <div class="px-16 flex justify-between">
         <button
-          v-for="(operate, i) in userControlsList"
-          :key="operate.title + i"
-          @click="handleOperate(operate)"
-          class="h-26 shrink-0 active:bg-[#000]/[0.1] box-border text-[10px] px-8 mr-8 text-black-3 flex justify-center rounded-full items-center bg-[#F3F3F3]"
+          @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]"
         >
-          {{ operate.title }}
+          <van-icon name="plus" class="mr-5" color="#FF9300" />
+          插入小标题
         </button>
-
         <button
-          @click="expandTextInput"
-          class="h-26 ml-auto shrink-0 active:bg-[#000]/[0.1] box-border text-[10px] px-8 text-black-3 flex justify-center rounded-full items-center bg-[#F3F3F3]"
+          @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]"
         >
-          <img
-            v-if="showExpandTextInput"
-            class="w-16 h-16"
-            src="../../assets/img/note-create/orange-expand-text-input.svg"
-            alt=""
-          />
-          <img
-            v-else
-            class="w-16 h-16"
-            src="~/assets/img/note-create/expand-text-input.svg"
-            alt=""
-          />
+          <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
-        v-if="hotTopicList && hotTopicList.length"
-        style="overflow: hidden; overflow-x: scroll"
-        class="px-16 flex justify-start"
-      >
-        <div class="h-26 flex items-center justify-center">
-          <div
-            v-for="item in hotTopicList"
-            :key="item?.id"
-            @click=""
-            class="bg-[#F5F5F5] shrink-0 h-full rounded-full px-8 flex items-center justify-center"
-          >
-            # {{ item?.title }}
-          </div>
-        </div>
-      </div>
-      <template v-if="!showExpandTextInput">
-        <CreateNoteForm
-          v-model:departureTime="noteJson.departureTime"
-          v-model:countTimes="noteJson.countTimes"
-          v-model:endPlace="noteJson.endPlace"
-          v-model:endPlaceId="noteJson.endPlaceId"
-          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"
-          v-model:chau="noteJson.chau"
-          v-model:chauId="noteJson.chauId"
-        />
-      </template>
-
       <div
         class="fixed box-border px-16 pt-16 pb-31 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"
       >
@@ -258,47 +260,31 @@
     </div>
 
     <div v-else class="w-full h-full">
-      <van-cell center size="large" :title="userInfo.showName">
-        <template #icon>
-          <div class="w-30 h-30 rounded-full mr-8 overflow-hidden">
-            <img class="w-full h-full object-cover" :src="userInfo.headImageUrl" alt="" />
+      <div class="p-16">
+        <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>
-        </template>
-        <template #label>
-          <span class="mr-8">{{ noteJson?.chau }}</span>
-          <span>{{ noteJson?.endPlace }}</span>
-        </template>
-        <template #right-icon>
-          <span class="iconfont icon-share text-black-9" style="font-size: 26px"></span>
-        </template>
-      </van-cell>
-      <van-swipe>
-        <template v-if="noteJson?.imgUrls && noteJson?.imgUrls.length">
-          <van-swipe-item v-for="image in noteJson?.imgUrls" :key="image">
-            <img :src="image" />
-          </van-swipe-item>
-        </template>
-        <van-swipe-item v-else>
-          <img
-            src="~/assets/img/note-create/note_create_banner_bg.png"
-            class="aspect-[316/204] w-full object-cover"
-          />
-        </van-swipe-item>
-
-        <!-- <template #indicator="{ active, total }">
-          <div class="custom-indicator">{{ active + 1 }}/{{ total }}</div>
-        </template> -->
-      </van-swipe>
-      <div class="px-16 pb-16">
-        <div
-          class="w-321 mt-12 line-clamp-2 overflow-hidden truncate max-w-xs text-xl whitespace-normal font-bold text-black-3"
-        >
-          {{ defaultNoteJson?.projectTitle ?? '游记标题' }}
         </div>
         <div class="flex justify-end text-[#999] text-[12px]">
           {{ defaultNoteJson.createTime }}
         </div>
-        <!-- <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%' }"
         >
@@ -386,7 +372,7 @@
               </van-col>
             </van-row>
           </div>
-        </div> -->
+        </div>
         <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="" />
@@ -396,34 +382,6 @@
             <div class="text-sm text-black-3" v-html="con.content"></div>
           </template>
         </div>
-
-        <div class="text-sm text-black-6 py-12 mb-12 box-border border-b-[1px]">
-          <span class="mr-8">出发时间/{{ defaultNoteJson?.departureTime || '' }}</span>
-          <span class="mr-8">出行方式/{{ defaultNoteJson?.travelMode || '' }}</span>
-          <span class="mr-8">出发天数/{{ defaultNoteJson?.countTimes || '' }}</span>
-          <span class="mr-8">游玩人数/{{ defaultNoteJson?.travelNumber || '' }}</span>
-          <span class="mr-8">人物关系/{{ defaultNoteJson?.role || '' }}</span>
-          <span class="mr-8">人均费用/{{ defaultNoteJson?.averageCost || '' }}</span>
-          <span class="mr-8">推荐指数/{{ defaultNoteJson?.recommendationRate || '' }}</span>
-        </div>
-
-        <div class="flex justify-end text-black-3 text-base">
-          <div class="ml-24 flex items-center">
-            <span class="iconfont icon-Thumbs-up text-black-3 mr-4" style="font-size: 24px"></span>
-            点赞
-          </div>
-          <div class="ml-24 flex items-center">
-            <span class="iconfont icon-star text-black-3 mr-4" style="font-size: 24px"></span>
-            收藏
-          </div>
-          <div class="ml-24 flex items-center">
-            <span
-              class="iconfont icon-chat-message text-black-3 mr-4"
-              style="font-size: 24px"
-            ></span>
-            评论
-          </div>
-        </div>
       </div>
       <div
         style="justify-content: space-between"
@@ -474,45 +432,16 @@
 import { useFileDialog } from '@vueuse/core'
 import upload from '~/assets/img/note-create/upload.svg'
 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 userInfoStore = useUserInfoStore()
-const { userInfo } = storeToRefs(userInfoStore)
 
 const dragOptions = {
   disabled: false, // 是否禁用拖拽
   animation: 150 // 拖拽时的动画效果持续时间
 }
 
-const TOPIC_TEXT = 'topic'
-const EIT_TEXT = 'eit'
-const PTITLE_TEXT = 'paragraphTitle'
-const PCONTENT_TEXT = 'paragraphContent'
-
-const userControlsList = ref([
-  {
-    title: '# 话题',
-    fn: TOPIC_TEXT,
-    empty: '暂无话题',
-    apiUrl: '/website/tourism/publishTravelNotes/getTopicListByName'
-  },
-  {
-    title: '@ 用户',
-    fn: EIT_TEXT,
-    empty: '暂无用户',
-    apiUrl: '/website/tourism/publishTravelNotes/getFouceEachFriendsByName'
-  },
-  {
-    title: 'H 段落标题',
-    fn: PTITLE_TEXT
-  },
-  {
-    title: 'P 段落内容',
-    fn: PCONTENT_TEXT
-  }
-])
-
 const { open, onChange } = useFileDialog({
   accept: '.png,.png,.jpeg,.JPG,Png '
 })
@@ -545,12 +474,7 @@ const defaultNoteJson = {
   averageCost: null,
   recommendationRate: null,
   travelNumber: null,
-  travelNotesContent: [],
-  chau: null, // 洲
-  chauId: null, // 洲
-  imgUrls: [], // 头部的图片数组
-  topics: [], // 话题
-  mentions: [] // 艾特的用户 {userName:"",userId:123}
+  travelNotesContent: []
 }
 const noteJson = reactive(defaultNoteJson)
 
@@ -558,6 +482,9 @@ watch(noteJson, () => {}, { deep: true, immediate: true })
 
 const id = useRouteQuery('id')
 
+// onMounted(() => {
+//   getPlaceOptions()
+// }),
 watch(
   id,
   () => {
@@ -591,6 +518,13 @@ const showDialog = (parmas) => {
     .catch(() => {})
 }
 
+// // 获取目的地
+// const placeOptions = ref([])
+// async function getPlaceOptions() {
+//   const { data } = await request('/website/tourism/publishTravelNotes/getWriteBelongTab')
+//   placeOptions.value = data
+// }
+
 // 获取草稿详情
 async function getNoteDetail() {
   try {
@@ -601,9 +535,6 @@ async function getNoteDetail() {
     const data = res.data ?? {}
     Object.keys(noteJson).forEach((key) => {
       noteJson[key] = data[key]
-      noteJson.imgUrls = data.imgUrls ?? []
-      noteJson.topics = data.topics ?? []
-      noteJson.mentions = data.mentions ?? []
       noteJson.travelNotesContent = data.travelNotesContent ?? []
       if (noteJson.travelNotesContent.length === 0) {
         noteJson.travelNotesContent.push({
@@ -614,13 +545,14 @@ async function getNoteDetail() {
       }
     })
 
+    // placeOptions.value.find(item=>item.id)
     if (data?.endPlaceDictMap?.id) {
       noteJson.endPlaceId = data?.endPlaceDictMap?.id
       noteJson.endPlace = data?.endPlaceDictMap?.name
     }
     if (data?.endPlaceDictMap?.name) {
-      noteJson.endPlaceId = data?.endPlaceDictMap?.id
       noteJson.endPlace = data?.endPlaceDictMap?.name
+      noteJson.endPlaceId = data?.endPlaceDictMap?.id
     }
 
     setLoading(false)
@@ -646,9 +578,6 @@ function handleInsertOrEditTitleIndex(index) {
 // 点击编辑大标题,
 function handleInsertOrEditProjectTitle(value) {
   noteJson.travelNotesContent.projectTitle = value
-  if (value.length == 50) {
-    showToast('标题最多输入50个字哦')
-  }
 }
 // 点击编辑或者新增段落标题,弹出dialog
 function handleInsertOrEditTitle(value) {
@@ -847,110 +776,6 @@ async function requestPublish() {
     publishLoading.value = false
   }
 }
-
-// 获取话题的数组
-const topicList = ref([])
-// 艾特用户的数组
-const eitList = ref([])
-const showTopicEit = ref(null)
-
-// 记录点击话题和@ 后的几个数字。
-const topicEitName = ref('')
-
-const topicLoading = ref(false)
-async function getTopicList(parmas) {
-  try {
-    // if (!topicLoading.value) return
-    topicLoading.value = true
-    const { data } = await request(parmas.apiUrl, {
-      query: { name: '' }
-    }).finally(() => (topicLoading.value = false))
-
-    if (parmas.fn == TOPIC_TEXT) {
-      topicList.value = data
-    }
-    if (parmas.fn == EIT_TEXT) {
-      eitList.value = data
-    }
-  } catch (e) {}
-}
-
-// 计算出热门话题
-const hotTopicList = computed(() => {
-  let _hotTopicList = []
-  if (topicList.value && topicList.value.length) {
-    _hotTopicList = topicList.value.filter((el) => el.isHot == 1)
-  }
-  return _hotTopicList
-})
-
-const showExpandTextInput = ref(false)
-// 扩展内容的插件 同时图片放大和缩小
-function expandTextInput() {
-  showExpandTextInput.value = !showExpandTextInput.value
-}
-
-const getInputPosition = (content) => {
-  try {
-    if (!content) return 0
-    const el = $el.querySelector('input, textarea')
-    if (!el) return content.length - 1
-    return el.selectionStart
-  } catch (e) {
-    // console.log(e, '??')
-  }
-}
-
-// 对应的操作
-const handleOperate = (operate) => {
-  try {
-    switch (operate.fn) {
-      case TOPIC_TEXT:
-        if (showTopicEit.value == TOPIC_TEXT) {
-          showTopicEit.value = null
-        } else {
-          noteJson.travelNotesContent[editIndex.value].content += '#'
-          showTopicEit.value = operate.fn
-          getTopicList(operate)
-        }
-
-        // const position = getInputPosition(noteJson.travelNotesContent[editIndex.value].content)
-
-        // const str = noteJson.travelNotesContent[editIndex.value].content
-        // inputValue.value = `${str.slice(0, position)}${'#'}${str.slice(position)}`
-
-        break
-      case EIT_TEXT:
-        if (showTopicEit.value == EIT_TEXT) {
-          showTopicEit.value = null
-        } else {
-          showTopicEit.value = operate.fn
-          noteJson.travelNotesContent[editIndex.value].content += '@'
-          getTopicList(operate)
-        }
-
-        break
-      case PTITLE_TEXT:
-        handleInsertOrEditTitleOk(defaultSectionTitle)
-        break
-      case PCONTENT_TEXT:
-        handleInsertOrEditTitleOk(defaultSectionContent)
-        break
-    }
-  } catch (e) {}
-}
-
-// 点击话题的事件
-function handleTopicAndEit(parmas, pType) {
-  if ((pType = '#')) {
-    noteJson.travelNotesContent[editIndex.value].content += `${pType} ${parmas.topicName}`
-  }
-  if ((pType = '@')) {
-    noteJson.travelNotesContent[editIndex.value].content += `${pType} ${parmas.showName}`
-  }
-}
-
-onMounted(() => {})
 </script>
 
 <style lang="scss" scoped>

+ 513 - 0
src/pages/_yj/[id].vue

@@ -0,0 +1,513 @@
+<template>
+  <div>
+    <div v-if="['success'].includes(status)" @click="pageClick">
+      <div class="p-10">
+        <img v-if="Array.isArray(detailData?.tourismUrlsAfterConvert)" :src="detailData?.tourismUrlsAfterConvert[0]" class="aspect-[316/204] w-full object-cover rounded" />
+        <div class="flex mt-10">
+          <img src="~/assets/img/article_title.png" class="w-[32px] h-[32px] shrink-0" alt="">
+          <div class="ml-10 text-[16px] text-[#333] leading-[28px] font-bold">
+            <span v-if="detailData.isOrigin == 1" class="text-[#FD9A00]">【原创】</span>
+            {{ detailData.projectTitle }}
+          </div>
+        </div>
+        <div class="flex justify-end text-[#999] text-[12px]">
+          {{ detailData.createTime }}
+        </div>
+        <div class="relative pt-15 pb-15 mt-8 rounded 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">{{ detailData?.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 ">{{ detailData?.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">{{ detailData?.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">{{ detailData?.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">{{ detailData?.travelModeDictMap?.name || '' }}</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">{{ detailData?.endPlaceDictMap?.name || '' }}</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">{{ detailData?.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">{{ detailData?.recommendationRate || '' }}</div>
+                </div>
+              </van-col>
+            </van-row>
+          </div>
+        </div>
+        <div class="mt-10 w-full" v-for="con in detailData.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 class="w-full" style="word-wrap: break-word" v-html="con.content"></div>
+          </template>
+        </div>
+
+        <div class="flex justify-end items-center text-[14px] text-[#999] mt-10 ">
+          <div class="flex items-center mr-10">
+            <van-icon name="eye-o" class="mr-5" />{{ detailData.pageViewCount }}
+          </div>
+          <div @click="doStar" class="flex items-center mr-10" :style="{ color: detailData.isLike ? '#FD9A00' : '' }">
+            <van-icon v-if="detailData.isLike" name="good-job" class="mr-5" />
+            <van-icon v-else name="good-job-o" class="mr-5" />
+            {{ detailData.likeCount }}
+          </div>
+          <div class="flex items-center mr-10" @click="handleCollect" :style="{ color: isCollect ? '#FD9A00' : '' }">
+            <van-icon v-if="isCollect" name="star" class="mr-5" />
+            <van-icon v-else name="star-o" class="mr-5" />
+            收藏
+          </div>
+
+          <div @click="share" class="flex items-center">
+            <img src="~/assets/img/yj/share.png" alt="" class="w-[12px] h-[12px] mr-5">分享
+          </div>
+        </div>
+        <div v-if="detailData?.contactCodeConvert"
+          class="flex items-center h-[112px] border rounded-[20px] overflow-hidden mt-10">
+          <div class="w-[112px] h-full bg-[#F5F5F5] flex items-center justify-center rounded-[20px]">
+            <img class="h-[80%] aspect-[1/1] " :src="detailData?.contactCodeConvert" alt="">
+          </div>
+          <div class="flex items-center ml-15">
+            <img src="~/assets/img/yj/leftArrow.png" class="w-[28px]" alt="">
+            <div class="text-[#666666] text-[12px]">长按保存图片,扫码添加好友</div>
+          </div>
+        </div>
+        <template v-if="commentList.length">
+          <template v-for="item in commentList" :key="item.id">
+            <div class="flex mt-10 justify-between" id="commentsBox">
+              <div class="w-[32px] h-[32px] bg-[#ddd] rounded-full shrink-0">
+                <img v-if="item?.headImageUrlDictMap?.name" class="w-full h-full object-cover rounded-full"
+                  :src="item?.headImageUrlDictMap?.name" alt="">
+                <img v-else class="w-full h-full object-cover rounded-full"
+                  src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png" alt="">
+              </div>
+              <div class="flex-1 pl-10 flex justify-between">
+                <div>
+                  <div>
+                    <span class="text-[#f40] text-[12px]">{{ item?.commentUserIdDictMap?.name }}:</span>
+                    <span class="text-[14px] text-[#333]" v-html="coveredContent(item?.commentContent)"></span>
+                  </div>
+                  <div class="text-[#666] text-[10px]">{{ item?.createTime }}</div>
+                </div>
+                <div class="mt-3 shrink-0">
+                  <van-icon @click="deleteComment(item.id)" v-if="item.self" class="mr-15" name="delete-o" size="20px"
+                    color="#666" />
+                  <van-icon @click.stop="addReply(item)" name="comment-o" size="20px" color="#666" />
+                </div>
+              </div>
+            </div>
+            <template v-if="Array.isArray(item.childrenList) && item.childrenList.length">
+              <div class="pl-[32px] mt-10">
+                <div class="pl-12" style="border-left:1px solid #ccc">
+                  <div v-for="subItem in item.childrenList" :key="subItem.id">
+                    <div class="flex justify-between items-start">
+                      <div>
+                        <span class="text-[#f40] text-[12px]">{{ subItem?.commentUserIdDictMap?.name }}<span
+                            class="text-[#333]">回复</span>{{ subItem?.replyUserIdDictMap?.name }}:</span>
+                        <span class="text-[14px] text-[#333]" v-html="coveredContent(subItem?.commentContent)"></span>
+                      </div>
+                      <div class="flex items-center mt-3">
+                        <van-icon v-if="subItem.self" @click="deleteComment(subItem.id)" class="mr-15" name="delete-o"
+                          size="20px" color="#666" />
+                        <van-icon @click.stop="addReply(subItem, item.id)" name="comment-o" size="20px" color="#666" />
+                      </div>
+                    </div>
+                    <div class="text-[#666] text-[10px]">{{ subItem.createTime }}</div>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </template>
+        </template>
+        <template v-else>
+          <div class="bg-[#F5F5F5] rounded-[20px] flex items-center justify-center h-[140px] mt-10">
+            <div>
+              <div>
+                <img class="w-[84px]" src="~/assets/img/yj/no-comments.png" alt="">
+              </div>
+              <div class="text-center text-[#999]">
+                暂无评论
+              </div>
+            </div>
+          </div>
+        </template>
+        <div class="mt-20">
+          <div class="flex items-center space-x-10">
+            <img src="~/assets/img/yj/recomend_travel_note_icon.png" class="h-[27px] w-[36px] object-cover" alt="" srcset="" />
+            <div class="text-[16px] font-bold text-black-3">热门游记</div>
+          </div>
+          <div class="">
+            <NuxtLink :to="`/yj/${item.id}`" class="group flex cursor-pointer items-center space-x-10 py-10 border-b" v-for="(item, index) in dataList.dataList
+" :key="item.id">
+              <div v-if="index<4" class="w-[15px] h-[15px] bg-[#000] text-[#fff] rounded flex items-center justify-center" :style="{background:['#FD9A00','#33B724','#F02626','#CACACA'][index]}" >
+                {{ index + 1 }}
+              </div>
+              <img :src="item?.homeHotPicturesAfterConvert?.length ? item.homeHotPicturesAfterConvert[0] : ''"
+                class="h-65 w-65 shrink-0 rounded-xl object-cover" alt="" />
+              <div class="w-0 flex-1">
+                <div class="truncate text-xl font-semibold text-black-3 group-hover:text-linkHover">
+                  {{ item.projectTitle }}
+                </div>
+                <div class="mt-5 flex items-center justify-between space-x-20 text-base">
+                  <div class="flex-1 truncate text-black-6">
+                    {{ item.remarks }}
+                  </div>
+                </div>
+              </div>
+            </NuxtLink>
+          </div>
+        </div>
+        <div class="h-[100px]"></div>
+        <div @click.stop="" class="fixed bottom-0 left-0 w-full bg-[#fff] pt-10 pb-30 border">
+          <div v-if="replyComment.id" class="text-center relative">
+            回复 <span class="text-[#f40]">{{ replyComment?.commentUserIdDictMap?.name }}:</span>
+            <div class="absolute right-10 top-0">
+              <van-icon name="cross" />
+            </div>
+          </div>
+          <div class="flex items-center ">
+            <div class="rounded-full overflow-hidden w-[32px] h-[32px] shrink-0 ml-5">
+              <img v-if="userInfo?.headImageUrl" class="w-full h-full object-cover rounded-full"
+                :src="userInfo?.headImageUrl" alt="" />
+              <img v-else class="w-full h-full object-cover rounded-full"
+                src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png" alt="" />
+            </div>
+            <div
+              class="relative flex-1 ml-5 mr-5 pl-5 pr-5 pt-4 pb-4 rounded-full h-[50px] border border-[#FD9A00] flex items-center justify-between">
+              <textarea v-model="commentValue" ref="textareaRef"  :placeholder="replyComment.id ? '回复:' : '发布您的评论'"
+                @focus="textareaFocus" class="ml-8 flex-1 h-full" style="resize: none;"></textarea>
+              <img @click="openEmoji" src="~/assets/img/yj/emoji.png" class="w-[22px] h-[22px]" alt="">
+
+            </div>
+            <div @click="addComment"
+              class="pt-6 pb-6 pl-20 pr-20 mr-5 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0">
+              评论
+            </div>
+          </div>
+          <div v-if="showEmoji" class=" h-[300px]  bg-[#fff] overflow-auto">
+            <div @click="closeEmojiBox" class="flex justify-end pr-15 text-[#999] text-[12px]">
+              收起表情
+            </div>
+            <div class="flex items-center flex-wrap">
+              <div v-for="(item, index) in emojiJson" :key="index"
+                class="hover:bg-[#ddd] text-[22px] w-[10%] aspect-[1/1] flex items-center justify-center">
+                <div @click="selectEmoji(index)" v-html="coveredContent(index)"></div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <div v-if="['error'].includes(status)">
+      <div class="text-center">
+        不好意思,找不到这篇游记了~
+      </div>
+      <div @click="goBack" class="text-center underline mt-10 cursor-pointer text-[#4B99EA]">
+        返回
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import dashBorder2 from '~/assets/img/dash-border.png'
+import emojiArr from './emoji'
+import emojiJson from './emoji.json'
+const userInfoStore = useUserInfoStore()
+const authStore = useAuthStore()
+const { token } = storeToRefs(authStore)
+
+const id = useRouteParam("id")
+const router = useRouter()
+const textareaRef = ref(null)
+
+// 游记内容
+const { data: detailData, status } = useMyFetch(
+  `website/tourism/projectTravelNotes/travelNotesDetail?id=${id.value}`
+)
+
+// 热门游记列表
+const { data: dataList } = await useMyFetch(
+  `/website/tourism/projectTravelNotes/homeList?isHotspot=1&pageNum=1&pageSize=4`
+)
+
+// 是否已收藏
+const isCollect = ref(false)
+async function isCollectTravelNotes() {
+  if (!token.value) return
+  const { data } = await request(`website/tourism/projectTravelNotes/isCollectTravelNotes?travelNotesId=${id.value}`)
+  isCollect.value = data
+}
+
+// 收藏/取消收藏
+async function handleCollect() {
+  if (!token.value) {
+    showConfirmDialog({
+      showConfirmDialog: true,
+      title: '提示',
+      message: '登录后可以收藏游记',
+      theme: 'round-button',
+    }).then(async () => { navigateTo({ path: '/login' }) })
+    return
+  }
+  const type = isCollect.value ? 0 : 1
+  showLoadingToast({
+    forbidClick: true,
+    duration: 0,
+  })
+  await request(`/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate`, { method: 'post', body: { type, travelNotesId: id.value } }).finally(() => closeToast())
+  isCollectTravelNotes()
+  showToast(type == 1 ? '收藏成功' : '已取消收藏')
+}
+
+// 获取点赞数量
+async function getStars() {
+  const { data } = await request(`/website/tourism/projectTravelNotes/getLikeCount?travelNotesId=${id.value}`)
+  if (isNaN(data)) return
+  detailData.value.likeCount = data
+}
+
+// 点赞
+const canDoStar = ref(true)
+async function doStar() {
+  if (!canDoStar.value) return
+  canDoStar.value = false
+  request(`/website/tourism/projectTravelNotes/userLikeTravelNotesUpdate`, {
+    method: 'post',
+    body: { travelNotesId: id.value }
+  }).then(() => {
+    detailData.value.isLike = true
+    getStars()
+  }).finally(() => canDoStar.value = true)
+}
+
+// 获取用户信息
+const userInfo = ref({})
+async function getUserInfo() {
+  if (!token.value) return userInfo.value = {}
+  request('/website/tourism/user/view').then(res => {
+    userInfo.value = res.data || {}
+  }, () => {
+    userInfo.value = {}
+  })
+}
+
+// 评论内容
+const commentValue = ref('')
+
+// 是否展示表情
+const showEmoji = ref(false)
+
+// 文本域失焦
+function textareaFocus() {
+  showEmoji.value = false
+}
+
+// 获取评论列表
+const commentList = ref([])
+async function getComments() {
+  const { data } = await request("/website/comment/tourTravelNotesComment/list?travelNoteId=" + id.value)
+  if (!Array.isArray(data) || !data.length) return commentList.value = []
+  commentList.value = data
+}
+
+// 转换评论中的一些非字符emoji
+function coveredContent(val) {
+  if (!val) return ''
+  return val.replace(/\[.*?]/g, function (str) {
+    const baseApi = import.meta.env.VITE_APP_EMOJI_API
+    const emojiName = emojiJson[str]
+    if (!emojiName) return str
+    return `<img src=${baseApi}${emojiJson[str]} style="width: 20px; height: 20px;display: inline-block; vertical-align: middle"/>`
+  })
+}
+
+// 删除评论
+async function deleteComment(id) {
+  if (!id) return
+  showConfirmDialog({
+    message: '确认要删除这条评论吗?',
+    theme: 'round-button',
+  }).then(async () => {
+    showLoadingToast({
+      forbidClick: true,
+      duration: 0,
+    })
+    await request('/website/comment/tourTravelNotesComment/delete', {
+      method: 'post',
+      body: { id }
+    }).finally(() => closeToast())
+    showToast('删除成功')
+    getComments()
+  });
+}
+
+const cursorIndex = ref(0)
+// 打开表情
+function openEmoji() {
+  nextTick(() => {
+    textareaRef.value.selectionStart && (cursorIndex.value = textareaRef.value.selectionStart)
+    showEmoji.value = true
+  })
+}
+// 收起表情
+function closeEmojiBox() {
+  showEmoji.value = false
+  nextTick(() => {
+    textareaRef.value.focus()
+  })
+}
+// 选择表情
+function selectEmoji(emojiStr = '') {
+  const length = emojiStr.length
+  commentValue.value = commentValue.value.slice(0, cursorIndex.value) + emojiStr + commentValue.value.slice(cursorIndex.value)
+  nextTick(() => {
+    cursorIndex.value += length
+    textareaRef.value.setSelectionRange(cursorIndex.value, cursorIndex.value)
+  })
+}
+
+// 回复评论
+const replyComment = ref({})
+function addReply(item, parentId) {
+  if (!token.value) {
+    showConfirmDialog({
+      showConfirmDialog: true,
+      title: '提示',
+      message: '登录后可以发布评论',
+      theme: 'round-button',
+    }).then(async () => { navigateTo({ path: '/login' }) })
+    return
+  }
+  textareaRef.value.focus()
+    replyComment.value = item
+    parentId && (replyComment.value.parentId = parentId)
+}
+
+
+// 发布评论
+const canAddComment = ref(true)
+async function addComment() {
+  if (!canAddComment.value) return
+  if (!token.value) {
+    showConfirmDialog({
+      showConfirmDialog: true,
+      title: '提示',
+      message: '登录后可以发布评论',
+      theme: 'round-button',
+    }).then(async () => { navigateTo({ path: '/login' }) })
+    return
+  }
+  if (!commentValue.value.trim()) {
+    showToast('评论内容不能为空!')
+    return
+  }
+  canAddComment.value = false
+  const body = { travelNoteId: id.value, commentContent: commentValue.value }
+  if (replyComment.value.id) {
+    body.replyCommentId = replyComment.value.id
+    body.replyUserId = replyComment.value.createUserId
+    body.parentId = replyComment.value.parentId
+  }
+  request('website/comment/tourTravelNotesComment/add', { method: 'post', body }).then(() => {
+    commentValue.value = ''
+    showToast('评论发布成功')
+    getComments()
+    showEmoji.value = false
+    document.querySelector('#commentsBox').scrollIntoView({
+      behavior: 'smooth',
+      block: 'start' 
+    })
+  }).finally(() => canAddComment.value = true, replyComment.value = {}, cursorIndex.value = 0)
+}
+function pageClick() {
+  nextTick(() => {
+    showEmoji.value = false
+    textareaRef.value.blur()
+    replyComment.value = {}
+    cursorIndex.value = 0
+  })
+}
+// 分享
+function share() {
+  navigator.clipboard.writeText(location.href).then(() => {
+    showNotify({ type: 'success', message: '游记链接已复制成功,快去分享给好友吧!' });
+  }, (err) => {
+    showNotify({ message: '游记链接分享失败' });
+  })
+}
+
+function goBack() {
+  router.back()
+}
+useSeoMeta({
+  title: "游记详情",
+  ogTitle: detailData?.projectTitle || '精美热门游记',
+  description: '逍遥游,乐逍遥,自由自在',
+  ogDescription: detailData?.projectTitle || '精美热门游记',
+  ogImage: '',
+});
+onMounted(() => {
+  getComments()
+  getUserInfo()
+  isCollectTravelNotes()
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 23 - 0
src/pages/_yj/emoji.js

@@ -0,0 +1,23 @@
+export default [
+    {name:'嘿嘿',emoji:'😀'},
+    {name:'羞涩微笑',emoji:'😊'},
+    {name:'笑哭了',emoji:'😂'},
+    {name:'微笑天使',emoji:'😇'},
+    {name:'喜笑颜开',emoji:'🥰'},
+    {name:'花痴',emoji:'😍'},
+    {name:'飞吻',emoji:'😘'},
+    {name:'亲亲',emoji:'😚'},
+    {name:'好吃',emoji:'😋'},
+    {name:'滑稽',emoji:'🤪'},
+    {name:'吐舌',emoji:'😝'},
+    {name:'发财',emoji:'🤑'},
+    {name:'大便',emoji:'💩'},
+    {name:'OK',emoji:'👌'},
+    {name:'耶',emoji:'✌️'},
+    {name:'拿捏',emoji:'🤏'},
+    {name:'爱你',emoji:'🤟'},
+    {name:'举手',emoji:'🙋'},
+    {name:'耸肩',emoji:'🤷'},
+    {name:'出租车',emoji:'🚕'},
+    {name:'汽车',emoji:'🚗'},
+]

+ 36 - 0
src/pages/_yj/emoji.json

@@ -0,0 +1,36 @@
+{
+  "[爱你]": "daxiao.png",
+  "[白眼]": "baiyan.png",
+  "[不开心]": "bukaixin.png",
+  "[馋]": "chan.png",
+  "[吹口哨]": "chuikoushao.png",
+  "[担心]": "danxin.png",
+  "[大笑]": "daxiao.png",
+  "[得意]": "deyi.png",
+  "[烦]": "fan.png",
+  "[飞吻]": "feiwen.png",
+  "[尴尬]": "ganga.png",
+  "[感冒]": "ganmao.png",
+  "[鬼脸]": "guilian.png",
+  "[害怕]": "haipa.png",
+  "[紧张]": "jinzhang.png",
+  "[开怀大笑]": "kaihuaidaxiao.png",
+  "[开心]": "kaixin.png",
+  "[恐怖]": "kongbu.png",
+  "[酷]": "ku.png",
+  "[魔鬼]": "mogui.png",
+  "[难受]": "nanshou.png",
+  "[轻松]": "qingsong.png",
+  "[傻笑]": "shaxiao.png",
+  "[生气]": "shengqi.png",
+  "[舒服]": "shufu.png",
+  "[睡觉]": "shuijiao.png",
+  "[酸]": "suanle.png",
+  "[调皮]": "tiaopi.png",
+  "[吐舌]": "tushe.png",
+  "[无语]": "wuyu.png",
+  "[嘻嘻]": "xixi.png",
+  "[犹豫]": "youyu.png",
+  "[眨眼]": "zhayan.png",
+  "[抓狂/难过]": "zhuakuangnanguo.png"
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 553 - 322
src/pages/note-create/index.client.vue


+ 1 - 0
src/pages/profile/interaction-message/index.vue

@@ -446,3 +446,4 @@ const handleCurrentChange = () => {
   align-items: center;
 }
 </style>
+../../_yj/emoji.json

+ 1 - 0
src/pages/profile/my-comment.vue

@@ -506,3 +506,4 @@ const handleCurrentChange = () => {
   box-shadow: none;
 }
 </style>
+../_yj/emoji../_yj/emoji.json

+ 1 - 1
src/pages/scan/index.vue

@@ -36,7 +36,7 @@ const openQrcode = async () => {
           width: 250,
           height: 250
         },
-        aspectRatio: window.visualViewport.width / window.visualViewport.height,
+        aspectRatio: window.visualViewport.width / window.visualViewport.height
       }
       if (devices && devices.length) {
         // 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个

+ 372 - 187
src/pages/yj/[id].vue

@@ -1,129 +1,177 @@
 <template>
   <div>
     <div v-if="['success'].includes(status)" @click="pageClick">
+      <van-cell center size="large" :title="userInfo.showName">
+        <template #icon>
+          <div class="w-30 h-30 rounded-full mr-8 overflow-hidden">
+            <img
+              v-if="userInfo.headImageUrl"
+              class="w-full h-full object-cover"
+              :src="userInfo.headImageUrl"
+              alt=""
+            />
+            <img v-else class="w-full h-full object-cover" :src="defaultAvatar" alt="" />
+          </div>
+        </template>
+        <template #label>
+          <span class="mr-8">{{ detailData?.endPlaceDictMap?.name || '' }}</span>
+          <span>{{ detailData?.endPlaceDictMap?.name || '' }}</span>
+        </template>
+        <template #value>
+          <div
+            :class="`mr-7 inline-block h-28 box-border rounded-full px-14 py-3  text-base  font-semibold border ${followState(detailData.status).color}`"
+          >
+            {{ followState(detailData.status).text }}
+          </div>
+        </template>
+        <template #right-icon>
+          <span
+            @click="
+              () => {
+                let origin = location.origin
+                let url = `${origin}/yj/${id}`
+
+                navigator.clipboard.writeText(url).then(
+                  () => {
+                    showNotify({ type: 'success', message: '链接已复制' })
+                  },
+                  () => {
+                    showNotify({ message: '链接复制失败' })
+                  }
+                )
+              }
+            "
+            class="iconfont icon-share text-black-9"
+            style="font-size: 26px"
+          ></span>
+        </template>
+      </van-cell>
+      <div class="relative w-full">
+        <van-swipe
+          @change="(i) => (swipeItemIndex = i + 1)"
+          :autoplay="3000"
+          indicator-color="#FF9300"
+          style="--van-swipe-indicator-margin: 8px"
+        >
+          <template v-if="detailData?.imgUrls && detailData?.imgUrls.length">
+            <van-swipe-item
+              v-for="image in detailData?.imgUrls"
+              :key="image"
+              @click="
+                showImagePreview({
+                  images: detailData?.imgUrls,
+                  startPosition: swipeItemIndex
+                })
+              "
+            >
+              <div class="aspect-[375/502] w-full">
+                <img class="w-full h-full object-cover" :src="image" />
+              </div>
+            </van-swipe-item>
+          </template>
+          <van-swipe-item v-else>
+            <img
+              src="~/assets/img/note-create/note_create_banner_bg.png"
+              class="aspect-[375/502] w-full object-cover"
+            />
+          </van-swipe-item>
+        </van-swipe>
+        <div
+          v-if="detailData?.imgUrls.length"
+          class="absolute top-10 right-20 z-1 w-37 h-24 rounded-full bg-black/[0.3] text-white flex justify-center items-center text-sm"
+        >
+          {{ swipeItemIndex }}/{{ detailData?.imgUrls.length }}
+        </div>
+      </div>
       <div class="p-10">
-        <img v-if="Array.isArray(detailData?.tourismUrlsAfterConvert)" :src="detailData?.tourismUrlsAfterConvert[0]" class="aspect-[316/204] w-full object-cover rounded" />
-        <div class="flex mt-10">
-          <img src="~/assets/img/article_title.png" class="w-[32px] h-[32px] shrink-0" alt="">
+        <div class="flex">
+          <img src="~/assets/img/article_title.png" class="w-[32px] h-[32px] shrink-0" alt="" />
           <div class="ml-10 text-[16px] text-[#333] leading-[28px] font-bold">
             <span v-if="detailData.isOrigin == 1" class="text-[#FD9A00]">【原创】</span>
             {{ detailData.projectTitle }}
           </div>
         </div>
-        <div class="flex justify-end text-[#999] text-[12px]">
-          {{ detailData.createTime }}
-        </div>
-        <div class="relative pt-15 pb-15 mt-8 rounded 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">{{ detailData?.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 ">{{ detailData?.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">{{ detailData?.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">{{ detailData?.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">{{ detailData?.travelModeDictMap?.name || '' }}</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">{{ detailData?.endPlaceDictMap?.name || '' }}</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">{{ detailData?.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">{{ detailData?.recommendationRate || '' }}</div>
-                </div>
-              </van-col>
-            </van-row>
-          </div>
-        </div>
         <div class="mt-10 w-full" v-for="con in detailData.travelNotesContent" :key="con.id">
           <template v-if="con.type == 'image'">
-            <img :src="con.content" class="w-full rounded-xl" alt="">
+            <img :src="con.content" class="w-full rounded-xl" alt="" />
           </template>
           <template v-else>
             <div class="w-full" style="word-wrap: break-word" v-html="con.content"></div>
           </template>
         </div>
 
-        <div class="flex justify-end items-center text-[14px] text-[#999] mt-10 ">
+        <div class="text-sm text-black-6 py-12 box-border">
+          <span class="mr-8">出发时间{{ contentIsEmpty(detailData?.departureTime) }}</span>
+          <span class="mr-8">出行方式{{ contentIsEmpty(detailData?.travelMode) }}</span>
+          <span class="mr-8">出发天数{{ contentIsEmpty(detailData?.countTimes) }}</span>
+          <span class="mr-8">游玩人数{{ contentIsEmpty(detailData?.travelNumber) }}</span>
+          <span class="mr-8">人物关系{{ contentIsEmpty(detailData?.role) }}</span>
+          <span class="mr-8">人均费用{{ contentIsEmpty(detailData?.averageCost) }}</span>
+          <span class="mr-8">推荐指数{{ contentIsEmpty(detailData?.recommendationRate) }}</span>
+        </div>
+
+        <van-cell
+          style="--van-cell-background: #f5f5f5"
+          center
+          is-link
+          class="rounded-lg"
+          value="45人"
+        >
+          <template #icon>
+            <div class="w-30 h-30 overflow-hidden rounded-full mr-8">
+              <img class="w-full h-full object-cover" src="" alt="" />
+            </div>
+          </template>
+          <template #title>
+            <h1 class="text-sm text-black-3">{{ '群聊' }}</h1>
+          </template>
+        </van-cell>
+
+        <div v-if="detailData.createTime" class="text-black-9 text-sm py-12 border-b-[1px]">
+          {{ detailData.createTime }} 发布
+        </div>
+
+        <div class="flex justify-end items-center text-[14px] text-[#999] mt-10">
           <div class="flex items-center mr-10">
-            <van-icon name="eye-o" class="mr-5" />{{ detailData.pageViewCount }}
+            <van-icon name="eye-o" class="mr-5" />
+            {{ detailData.pageViewCount }}
           </div>
-          <div @click="doStar" class="flex items-center mr-10" :style="{ color: detailData.isLike ? '#FD9A00' : '' }">
+          <div
+            @click="doStar"
+            class="flex items-center mr-10"
+            :style="{ color: detailData.isLike ? '#FD9A00' : '' }"
+          >
             <van-icon v-if="detailData.isLike" name="good-job" class="mr-5" />
             <van-icon v-else name="good-job-o" class="mr-5" />
             {{ detailData.likeCount }}
           </div>
-          <div class="flex items-center mr-10" @click="handleCollect" :style="{ color: isCollect ? '#FD9A00' : '' }">
+          <div
+            class="flex items-center mr-10"
+            @click="handleCollect"
+            :style="{ color: isCollect ? '#FD9A00' : '' }"
+          >
             <van-icon v-if="isCollect" name="star" class="mr-5" />
             <van-icon v-else name="star-o" class="mr-5" />
             收藏
           </div>
 
           <div @click="share" class="flex items-center">
-            <img src="~/assets/img/yj/share.png" alt="" class="w-[12px] h-[12px] mr-5">分享
+            <img src="~/assets/img/yj/share.png" alt="" class="w-[12px] h-[12px] mr-5" />
+            分享
           </div>
         </div>
-        <div v-if="detailData?.contactCodeConvert"
-          class="flex items-center h-[112px] border rounded-[20px] overflow-hidden mt-10">
-          <div class="w-[112px] h-full bg-[#F5F5F5] flex items-center justify-center rounded-[20px]">
-            <img class="h-[80%] aspect-[1/1] " :src="detailData?.contactCodeConvert" alt="">
+        <div
+          v-if="detailData?.contactCodeConvert"
+          class="flex items-center h-[112px] border rounded-[20px] overflow-hidden mt-10"
+        >
+          <div
+            class="w-[112px] h-full bg-[#F5F5F5] flex items-center justify-center rounded-[20px]"
+          >
+            <img class="h-[80%] aspect-[1/1]" :src="detailData?.contactCodeConvert" alt="" />
           </div>
           <div class="flex items-center ml-15">
-            <img src="~/assets/img/yj/leftArrow.png" class="w-[28px]" alt="">
+            <img src="~/assets/img/yj/leftArrow.png" class="w-[28px]" alt="" />
             <div class="text-[#666666] text-[12px]">长按保存图片,扫码添加好友</div>
           </div>
         </div>
@@ -131,40 +179,81 @@
           <template v-for="item in commentList" :key="item.id">
             <div class="flex mt-10 justify-between" id="commentsBox">
               <div class="w-[32px] h-[32px] bg-[#ddd] rounded-full shrink-0">
-                <img v-if="item?.headImageUrlDictMap?.name" class="w-full h-full object-cover rounded-full"
-                  :src="item?.headImageUrlDictMap?.name" alt="">
-                <img v-else class="w-full h-full object-cover rounded-full"
-                  src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png" alt="">
+                <img
+                  v-if="item?.headImageUrlDictMap?.name"
+                  class="w-full h-full object-cover rounded-full"
+                  :src="item?.headImageUrlDictMap?.name"
+                  alt=""
+                />
+                <img
+                  v-else
+                  class="w-full h-full object-cover rounded-full"
+                  src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png"
+                  alt=""
+                />
               </div>
               <div class="flex-1 pl-10 flex justify-between">
                 <div>
                   <div>
-                    <span class="text-[#f40] text-[12px]">{{ item?.commentUserIdDictMap?.name }}:</span>
-                    <span class="text-[14px] text-[#333]" v-html="coveredContent(item?.commentContent)"></span>
+                    <span class="text-[#f40] text-[12px]">
+                      {{ item?.commentUserIdDictMap?.name }}:
+                    </span>
+                    <span
+                      class="text-[14px] text-[#333]"
+                      v-html="coveredContent(item?.commentContent)"
+                    ></span>
                   </div>
                   <div class="text-[#666] text-[10px]">{{ item?.createTime }}</div>
                 </div>
                 <div class="mt-3 shrink-0">
-                  <van-icon @click="deleteComment(item.id)" v-if="item.self" class="mr-15" name="delete-o" size="20px"
-                    color="#666" />
-                  <van-icon @click.stop="addReply(item)" name="comment-o" size="20px" color="#666" />
+                  <van-icon
+                    @click="deleteComment(item.id)"
+                    v-if="item.self"
+                    class="mr-15"
+                    name="delete-o"
+                    size="20px"
+                    color="#666"
+                  />
+                  <van-icon
+                    @click.stop="addReply(item)"
+                    name="comment-o"
+                    size="20px"
+                    color="#666"
+                  />
                 </div>
               </div>
             </div>
             <template v-if="Array.isArray(item.childrenList) && item.childrenList.length">
               <div class="pl-[32px] mt-10">
-                <div class="pl-12" style="border-left:1px solid #ccc">
+                <div class="pl-12" style="border-left: 1px solid #ccc">
                   <div v-for="subItem in item.childrenList" :key="subItem.id">
                     <div class="flex justify-between items-start">
                       <div>
-                        <span class="text-[#f40] text-[12px]">{{ subItem?.commentUserIdDictMap?.name }}<span
-                            class="text-[#333]">回复</span>{{ subItem?.replyUserIdDictMap?.name }}:</span>
-                        <span class="text-[14px] text-[#333]" v-html="coveredContent(subItem?.commentContent)"></span>
+                        <span class="text-[#f40] text-[12px]">
+                          {{ subItem?.commentUserIdDictMap?.name }}
+                          <span class="text-[#333]">回复</span>
+                          {{ subItem?.replyUserIdDictMap?.name }}:
+                        </span>
+                        <span
+                          class="text-[14px] text-[#333]"
+                          v-html="coveredContent(subItem?.commentContent)"
+                        ></span>
                       </div>
                       <div class="flex items-center mt-3">
-                        <van-icon v-if="subItem.self" @click="deleteComment(subItem.id)" class="mr-15" name="delete-o"
-                          size="20px" color="#666" />
-                        <van-icon @click.stop="addReply(subItem, item.id)" name="comment-o" size="20px" color="#666" />
+                        <van-icon
+                          v-if="subItem.self"
+                          @click="deleteComment(subItem.id)"
+                          class="mr-15"
+                          name="delete-o"
+                          size="20px"
+                          color="#666"
+                        />
+                        <van-icon
+                          @click.stop="addReply(subItem, item.id)"
+                          name="comment-o"
+                          size="20px"
+                          color="#666"
+                        />
                       </div>
                     </div>
                     <div class="text-[#666] text-[10px]">{{ subItem.createTime }}</div>
@@ -178,27 +267,45 @@
           <div class="bg-[#F5F5F5] rounded-[20px] flex items-center justify-center h-[140px] mt-10">
             <div>
               <div>
-                <img class="w-[84px]" src="~/assets/img/yj/no-comments.png" alt="">
-              </div>
-              <div class="text-center text-[#999]">
-                暂无评论
+                <img class="w-[84px]" src="~/assets/img/yj/no-comments.png" alt="" />
               </div>
+              <div class="text-center text-[#999]">暂无评论</div>
             </div>
           </div>
         </template>
         <div class="mt-20">
           <div class="flex items-center space-x-10">
-            <img src="~/assets/img/yj/recomend_travel_note_icon.png" class="h-[27px] w-[36px] object-cover" alt="" srcset="" />
+            <img
+              src="~/assets/img/yj/recomend_travel_note_icon.png"
+              class="h-[27px] w-[36px] object-cover"
+              alt=""
+              srcset=""
+            />
             <div class="text-[16px] font-bold text-black-3">热门游记</div>
           </div>
           <div class="">
-            <NuxtLink :to="`/yj/${item.id}`" class="group flex cursor-pointer items-center space-x-10 py-10 border-b" v-for="(item, index) in dataList.dataList
-" :key="item.id">
-              <div v-if="index<4" class="w-[15px] h-[15px] bg-[#000] text-[#fff] rounded flex items-center justify-center" :style="{background:['#FD9A00','#33B724','#F02626','#CACACA'][index]}" >
+            <NuxtLink
+              :to="`/yj/${item.id}`"
+              class="group flex cursor-pointer items-center space-x-10 py-10 border-b"
+              v-for="(item, index) in dataList.dataList"
+              :key="item.id"
+            >
+              <div
+                v-if="index < 4"
+                class="w-[15px] h-[15px] bg-[#000] text-[#fff] rounded flex items-center justify-center"
+                :style="{ background: ['#FD9A00', '#33B724', '#F02626', '#CACACA'][index] }"
+              >
                 {{ index + 1 }}
               </div>
-              <img :src="item?.homeHotPicturesAfterConvert?.length ? item.homeHotPicturesAfterConvert[0] : ''"
-                class="h-65 w-65 shrink-0 rounded-xl object-cover" alt="" />
+              <img
+                :src="
+                  item?.homeHotPicturesAfterConvert?.length
+                    ? item.homeHotPicturesAfterConvert[0]
+                    : ''
+                "
+                class="h-65 w-65 shrink-0 rounded-xl object-cover"
+                alt=""
+              />
               <div class="w-0 flex-1">
                 <div class="truncate text-xl font-semibold text-black-3 group-hover:text-linkHover">
                   {{ item.projectTitle }}
@@ -215,37 +322,62 @@
         <div class="h-[100px]"></div>
         <div @click.stop="" class="fixed bottom-0 left-0 w-full bg-[#fff] pt-10 pb-30 border">
           <div v-if="replyComment.id" class="text-center relative">
-            回复 <span class="text-[#f40]">{{ replyComment?.commentUserIdDictMap?.name }}:</span>
+            回复
+            <span class="text-[#f40]">{{ replyComment?.commentUserIdDictMap?.name }}:</span>
             <div class="absolute right-10 top-0">
               <van-icon name="cross" />
             </div>
           </div>
-          <div class="flex items-center ">
+          <div class="flex items-center">
             <div class="rounded-full overflow-hidden w-[32px] h-[32px] shrink-0 ml-5">
-              <img v-if="userInfo?.headImageUrl" class="w-full h-full object-cover rounded-full"
-                :src="userInfo?.headImageUrl" alt="" />
-              <img v-else class="w-full h-full object-cover rounded-full"
-                src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png" alt="" />
+              <img
+                v-if="userInfo?.headImageUrl"
+                class="w-full h-full object-cover rounded-full"
+                :src="userInfo?.headImageUrl"
+                alt=""
+              />
+              <img
+                v-else
+                class="w-full h-full object-cover rounded-full"
+                src="https://www.xiaoyaotravel.com/_nuxt/default_avatar.gSq5JxK1.png"
+                alt=""
+              />
             </div>
             <div
-              class="relative flex-1 ml-5 mr-5 pl-5 pr-5 pt-4 pb-4 rounded-full h-[50px] border border-[#FD9A00] flex items-center justify-between">
-              <textarea v-model="commentValue" ref="textareaRef"  :placeholder="replyComment.id ? '回复:' : '发布您的评论'"
-                @focus="textareaFocus" class="ml-8 flex-1 h-full" style="resize: none;"></textarea>
-              <img @click="openEmoji" src="~/assets/img/yj/emoji.png" class="w-[22px] h-[22px]" alt="">
-
+              class="relative flex-1 ml-5 mr-5 pl-5 pr-5 pt-4 pb-4 rounded-full h-[50px] border border-[#FD9A00] flex items-center justify-between"
+            >
+              <textarea
+                v-model="commentValue"
+                ref="textareaRef"
+                :placeholder="replyComment.id ? '回复:' : '发布您的评论'"
+                @focus="textareaFocus"
+                class="ml-8 flex-1 h-full"
+                style="resize: none"
+              ></textarea>
+              <img
+                @click="openEmoji"
+                src="~/assets/img/yj/emoji.png"
+                class="w-[22px] h-[22px]"
+                alt=""
+              />
             </div>
-            <div @click="addComment"
-              class="pt-6 pb-6 pl-20 pr-20 mr-5 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0">
+            <div
+              @click="addComment"
+              class="pt-6 pb-6 pl-20 pr-20 mr-5 bg-[#FD9A00] text-[#fff] flex items-center justify-center rounded-full shrink-0"
+            >
               评论
             </div>
           </div>
-          <div v-if="showEmoji" class=" h-[300px]  bg-[#fff] overflow-auto">
+          <div v-if="showEmoji" class="h-[300px] bg-[#fff] overflow-auto">
             <div @click="closeEmojiBox" class="flex justify-end pr-15 text-[#999] text-[12px]">
               收起表情
             </div>
             <div class="flex items-center flex-wrap">
-              <div v-for="(item, index) in emojiJson" :key="index"
-                class="hover:bg-[#ddd] text-[22px] w-[10%] aspect-[1/1] flex items-center justify-center">
+              <div
+                v-for="(item, index) in emojiJson"
+                :key="index"
+                class="hover:bg-[#ddd] text-[22px] w-[10%] aspect-[1/1] flex items-center justify-center"
+              >
                 <div @click="selectEmoji(index)" v-html="coveredContent(index)"></div>
               </div>
             </div>
@@ -253,11 +385,9 @@
         </div>
       </div>
     </div>
-    
+
     <div v-if="['error'].includes(status)">
-      <div class="text-center">
-        不好意思,找不到这篇游记了~
-      </div>
+      <div class="text-center">不好意思,找不到这篇游记了~</div>
       <div @click="goBack" class="text-center underline mt-10 cursor-pointer text-[#4B99EA]">
         返回
       </div>
@@ -267,13 +397,12 @@
 
 <script setup>
 import dashBorder2 from '~/assets/img/dash-border.png'
-import emojiArr from './emoji'
 import emojiJson from './emoji.json'
 const userInfoStore = useUserInfoStore()
 const authStore = useAuthStore()
 const { token } = storeToRefs(authStore)
 
-const id = useRouteParam("id")
+const id = useRouteParam('id')
 const router = useRouter()
 const textareaRef = ref(null)
 
@@ -291,7 +420,9 @@ const { data: dataList } = await useMyFetch(
 const isCollect = ref(false)
 async function isCollectTravelNotes() {
   if (!token.value) return
-  const { data } = await request(`website/tourism/projectTravelNotes/isCollectTravelNotes?travelNotesId=${id.value}`)
+  const { data } = await request(
+    `website/tourism/projectTravelNotes/isCollectTravelNotes?travelNotesId=${id.value}`
+  )
   isCollect.value = data
 }
 
@@ -302,23 +433,30 @@ async function handleCollect() {
       showConfirmDialog: true,
       title: '提示',
       message: '登录后可以收藏游记',
-      theme: 'round-button',
-    }).then(async () => { navigateTo({ path: '/login' }) })
+      theme: 'round-button'
+    }).then(async () => {
+      navigateTo({ path: '/login' })
+    })
     return
   }
   const type = isCollect.value ? 0 : 1
   showLoadingToast({
     forbidClick: true,
-    duration: 0,
+    duration: 0
   })
-  await request(`/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate`, { method: 'post', body: { type, travelNotesId: id.value } }).finally(() => closeToast())
+  await request(`/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate`, {
+    method: 'post',
+    body: { type, travelNotesId: id.value }
+  }).finally(() => closeToast())
   isCollectTravelNotes()
   showToast(type == 1 ? '收藏成功' : '已取消收藏')
 }
 
 // 获取点赞数量
 async function getStars() {
-  const { data } = await request(`/website/tourism/projectTravelNotes/getLikeCount?travelNotesId=${id.value}`)
+  const { data } = await request(
+    `/website/tourism/projectTravelNotes/getLikeCount?travelNotesId=${id.value}`
+  )
   if (isNaN(data)) return
   detailData.value.likeCount = data
 }
@@ -331,23 +469,57 @@ async function doStar() {
   request(`/website/tourism/projectTravelNotes/userLikeTravelNotesUpdate`, {
     method: 'post',
     body: { travelNotesId: id.value }
-  }).then(() => {
-    detailData.value.isLike = true
-    getStars()
-  }).finally(() => canDoStar.value = true)
+  })
+    .then(() => {
+      detailData.value.isLike = true
+      getStars()
+    })
+    .finally(() => (canDoStar.value = true))
 }
 
 // 获取用户信息
 const userInfo = ref({})
 async function getUserInfo() {
-  if (!token.value) return userInfo.value = {}
-  request('/website/tourism/user/view').then(res => {
-    userInfo.value = res.data || {}
-  }, () => {
-    userInfo.value = {}
-  })
+  if (!token.value) return (userInfo.value = {})
+  request('/website/tourism/user/view').then(
+    (res) => {
+      userInfo.value = res.data || {}
+    },
+    () => {
+      userInfo.value = {}
+    }
+  )
+}
+
+// 关注状态
+function followState(params) {
+  if (!params) {
+    return {
+      color: 'text-[#FD9A00] border-[#FD9A00]',
+      text: '关注'
+    }
+  }
+
+  if (params == 1) {
+    return {
+      color: 'text-black-9 border-black-9',
+      text: '已关注'
+    }
+  }
+}
+
+// 内容是否为空
+function contentIsEmpty(content) {
+  if (content) {
+    return `/${content}`
+  } else {
+    return ''
+  }
 }
 
+// 游记详情得轮播图下标
+const swipeItemIndex = ref(1)
+
 // 评论内容
 const commentValue = ref('')
 
@@ -362,8 +534,10 @@ function textareaFocus() {
 // 获取评论列表
 const commentList = ref([])
 async function getComments() {
-  const { data } = await request("/website/comment/tourTravelNotesComment/list?travelNoteId=" + id.value)
-  if (!Array.isArray(data) || !data.length) return commentList.value = []
+  const { data } = await request(
+    '/website/comment/tourTravelNotesComment/list?travelNoteId=' + id.value
+  )
+  if (!Array.isArray(data) || !data.length) return (commentList.value = [])
   commentList.value = data
 }
 
@@ -383,11 +557,11 @@ async function deleteComment(id) {
   if (!id) return
   showConfirmDialog({
     message: '确认要删除这条评论吗?',
-    theme: 'round-button',
+    theme: 'round-button'
   }).then(async () => {
     showLoadingToast({
       forbidClick: true,
-      duration: 0,
+      duration: 0
     })
     await request('/website/comment/tourTravelNotesComment/delete', {
       method: 'post',
@@ -395,7 +569,7 @@ async function deleteComment(id) {
     }).finally(() => closeToast())
     showToast('删除成功')
     getComments()
-  });
+  })
 }
 
 const cursorIndex = ref(0)
@@ -416,7 +590,10 @@ function closeEmojiBox() {
 // 选择表情
 function selectEmoji(emojiStr = '') {
   const length = emojiStr.length
-  commentValue.value = commentValue.value.slice(0, cursorIndex.value) + emojiStr + commentValue.value.slice(cursorIndex.value)
+  commentValue.value =
+    commentValue.value.slice(0, cursorIndex.value) +
+    emojiStr +
+    commentValue.value.slice(cursorIndex.value)
   nextTick(() => {
     cursorIndex.value += length
     textareaRef.value.setSelectionRange(cursorIndex.value, cursorIndex.value)
@@ -431,16 +608,17 @@ function addReply(item, parentId) {
       showConfirmDialog: true,
       title: '提示',
       message: '登录后可以发布评论',
-      theme: 'round-button',
-    }).then(async () => { navigateTo({ path: '/login' }) })
+      theme: 'round-button'
+    }).then(async () => {
+      navigateTo({ path: '/login' })
+    })
     return
   }
   textareaRef.value.focus()
-    replyComment.value = item
-    parentId && (replyComment.value.parentId = parentId)
+  replyComment.value = item
+  parentId && (replyComment.value.parentId = parentId)
 }
 
-
 // 发布评论
 const canAddComment = ref(true)
 async function addComment() {
@@ -450,8 +628,10 @@ async function addComment() {
       showConfirmDialog: true,
       title: '提示',
       message: '登录后可以发布评论',
-      theme: 'round-button',
-    }).then(async () => { navigateTo({ path: '/login' }) })
+      theme: 'round-button'
+    }).then(async () => {
+      navigateTo({ path: '/login' })
+    })
     return
   }
   if (!commentValue.value.trim()) {
@@ -465,16 +645,18 @@ async function addComment() {
     body.replyUserId = replyComment.value.createUserId
     body.parentId = replyComment.value.parentId
   }
-  request('website/comment/tourTravelNotesComment/add', { method: 'post', body }).then(() => {
-    commentValue.value = ''
-    showToast('评论发布成功')
-    getComments()
-    showEmoji.value = false
-    document.querySelector('#commentsBox').scrollIntoView({
-      behavior: 'smooth',
-      block: 'start' 
+  request('website/comment/tourTravelNotesComment/add', { method: 'post', body })
+    .then(() => {
+      commentValue.value = ''
+      showToast('评论发布成功')
+      getComments()
+      showEmoji.value = false
+      document.querySelector('#commentsBox').scrollIntoView({
+        behavior: 'smooth',
+        block: 'start'
+      })
     })
-  }).finally(() => canAddComment.value = true, replyComment.value = {}, cursorIndex.value = 0)
+    .finally(() => (canAddComment.value = true), (replyComment.value = {}), (cursorIndex.value = 0))
 }
 function pageClick() {
   nextTick(() => {
@@ -486,23 +668,26 @@ function pageClick() {
 }
 // 分享
 function share() {
-  navigator.clipboard.writeText(location.href).then(() => {
-    showNotify({ type: 'success', message: '游记链接已复制成功,快去分享给好友吧!' });
-  }, (err) => {
-    showNotify({ message: '游记链接分享失败' });
-  })
+  navigator.clipboard.writeText(location.href).then(
+    () => {
+      showNotify({ type: 'success', message: '游记链接已复制成功,快去分享给好友吧!' })
+    },
+    (err) => {
+      showNotify({ message: '游记链接分享失败' })
+    }
+  )
 }
 
 function goBack() {
   router.back()
 }
 useSeoMeta({
-  title: "游记详情",
+  title: '游记详情',
   ogTitle: detailData?.projectTitle || '精美热门游记',
   description: '逍遥游,乐逍遥,自由自在',
   ogDescription: detailData?.projectTitle || '精美热门游记',
-  ogImage: '',
-});
+  ogImage: ''
+})
 onMounted(() => {
   getComments()
   getUserInfo()
@@ -510,4 +695,4 @@ onMounted(() => {
 })
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped></style>

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.