suwenjiang 1 месяц назад
Родитель
Сommit
d21eff0f3f

+ 4 - 4
.env.development

@@ -3,8 +3,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:8082/
+VITE_APP_IM_URL=ws://101.126.146.250:8082/system/message
 
 # 陈英政
 # VITE_APP_BASE_URL=http://101.126.146.250:8084/
@@ -31,9 +31,9 @@ VITE_APP_ENV=development
 # VITE_APP_IM_URL=ws://q9943037p3.goho.co/system/message
 
 # 张维本地
-VITE_APP_BASE_URL=http://192.168.1.73:8082/
+# VITE_APP_BASE_URL=http://192.168.1.73:8082/
 # 本地socoket
-VITE_APP_IM_URL=ws://192.168.1.73:8082/system/message
+# VITE_APP_IM_URL=ws://192.168.1.73:8082/system/message
 
 # 花生壳
 # VITE_APP_BASE_URL=http://5nfhmg.natappfree.cc

+ 1 - 0
src/components/CreateNote/Form.vue

@@ -164,6 +164,7 @@
           :label-width="labelWidth"
           name="calendar"
           clearable
+          readonly
           size="large"
           label="出发时间"
           autocomplete="off"

+ 13 - 3
src/components/CreateNote/PublishResultModal.client.vue

@@ -30,7 +30,7 @@
         <van-button round plain color="#FF9300" type="primary" @click="handleCheck">
           去查看
         </van-button>
-        <van-button round type="primary" color="#FF9300" @click="handleNextNote">
+        <van-button round type="primary" color="#FF9300" @click="updateQueryAndRefresh">
           继续发布
         </van-button>
       </div>
@@ -40,10 +40,10 @@
 
 <script setup>
 const visible = defineModel('visible', false)
-
+const router = useRouter()
 const emit = defineEmits(['submitOk'])
 
-function handleNextNote() {
+async function handleNextNote() {
   visible.value = false
   navigateTo('/note-create', {
     replace: true
@@ -58,6 +58,16 @@ function handleCheck() {
     }
   })
 }
+
+const updateQueryAndRefresh = () => {
+  router
+    .replace({
+      path: '/note-create'
+    })
+    .then(() => {
+      window.location.reload()
+    })
+}
 </script>
 
 <style lang="scss" scoped></style>

+ 9 - 5
src/components/Profile/Collection/Topic.vue

@@ -1,12 +1,15 @@
 <template>
   <!-- 话题 -->
-  <NuxtLink :to="`/yj/${itemData.id}`" class="bg-white p-10 box-border flex space-x-10 rounded-xl">
+  <NuxtLink
+    :to="`/topic?topicName=${itemData.name}`"
+    class="bg-white p-10 box-border flex space-x-10 rounded-xl"
+  >
     <van-image
-      :src="formatImgSrc(itemData.tourismUrlsAfterConvert)"
-      width="120px"
-      height="90px"
+      :src="topic"
+      width="100px"
+      height="100px"
       radius="8px"
-      class="shrink-0"
+      class="shrink-0 mr-4"
     ></van-image>
 
     <div class="flex-1 w-0 relative">
@@ -30,6 +33,7 @@
 </template>
 
 <script setup>
+import topic from '~/assets/img/topic/topic.png'
 defineProps({
   itemData: {
     type: Object,

+ 366 - 320
src/pages/note-create/index.client.vue

@@ -1,52 +1,44 @@
 <template>
-  <div v-if="!loading" class="box-border pb-110">
+  <div v-if="!loading" class="h-[100vh] box-border pb-110">
     <div v-if="!previewOptions.show">
       <CreateNoteHeaderImage
         v-model:bannerUrl="noteJson.travelNotesBanner"
         v-model:imgUrls="noteJson.imgUrls"
         v-model:show="showExpandTextInput"
       />
+      <div ref="projectTitleRef">
+        <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"
+          @focus="showExpandTextInput = true"
+          placeholder="请输入游记标题"
+          maxlength="50"
+        ></van-field>
+      </div>
 
-      <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"
-        @focus="showExpandTextInput = true"
-        @blur="showExpandTextInput = false"
-        placeholder="请输入游记标题"
-        maxlength="50"
-      ></van-field>
       <div class="border-b-[1px] mx-16"></div>
 
       <div style="overflow: hidden; overflow-y: scroll" class="h-200 mb-12">
-        <div class="mb-12 relative box-border">
+        <div ref="editorFather" :class="`min-h-160 mx-12 my-16 w-[93%] mb-20 text-sm  `">
           <div
-            id="view-note"
-            contenteditable
-            class="inputSectionContent w-[93%] box-border min-h-100 mx-12 my-16 text-sm"
-            ref="inputDiv"
-            @click="handleInsertOrEditTitleIndex2"
-            @input="handleInsertOrEditTitleText"
-            @focus="showExpandTextInput = true"
-            @blur="showExpandTextInput = false"
-            v-html="noteJson?.tourTourismProjectTravelNotesWriteContentDto?.content"
+            ref="editor"
+            class="inputSectionContent"
+            v-html="noteJson?.tourTourismProjectTravelNotesWriteContentDto.content"
           ></div>
-          <!-- <div class="min-h-100 mx-12 my-16 w-full mb-20 text-sm">
-            <div ref="editor" id="editor" class="min-h-100"></div>
-          </div> -->
         </div>
       </div>
 
-      <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"
@@ -68,7 +60,7 @@
         </template>
 
         <template v-if="showTopicEit == EIT_TEXT">
-          <!-- 艾特的好友 -->
+          艾特的好友
           <div
             v-for="item in eitList"
             :key="item?.userId"
@@ -81,21 +73,24 @@
             <p class="text-sm text-black-6 line-clamp-1">{{ item?.showName }}</p>
           </div>
         </template>
-      </div>
+      </div> -->
       <div
-        :class="`${showExpandTextInput ? 'fixed bottom-0 left-0' : ''} px-16 flex justify-start mb-12`"
+        :class="`${showExpandTextInput ? 'fixed bottom-390 left-0' : ''} w-full  px-16 flex justify-between mb-12`"
       >
-        <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]"
-        >
-          {{ operate?.title }}
-        </button>
+        <div class="flex shrink-0 justify-start">
+          <button
+            v-for="(operate, i) in userControlsList"
+            :key="operate?.title + i"
+            @click="openMention(operate.icon)"
+            :ref="(el) => (checkboxRefs[i] = el)"
+            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]"
+          >
+            {{ operate?.title }}
+          </button>
+        </div>
 
         <button
-          @click="expandTextInput"
+          @click.stop="showExpandTextInput = !showExpandTextInput"
           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]"
         >
           <img
@@ -260,13 +255,25 @@
         ></div>
 
         <div class="text-sm text-black-6 py-12 mb-12 box-border border-b-[1px]">
-          <span class="mr-8">出发时间{{ contentIsEmpty(defaultNoteJson?.departureTime) }}</span>
-          <span class="mr-8">出行方式{{ contentIsEmpty(defaultNoteJson?.travelMode) }}</span>
-          <span class="mr-8">出发天数{{ contentIsEmpty(defaultNoteJson?.countTimes) }}</span>
-          <span class="mr-8">游玩人数{{ contentIsEmpty(defaultNoteJson?.travelNumber) }}</span>
-          <span class="mr-8">人物关系{{ contentIsEmpty(defaultNoteJson?.role) }}</span>
-          <span class="mr-8">人均费用{{ contentIsEmpty(defaultNoteJson?.averageCost) }}</span>
-          <span class="mr-8">
+          <span v-if="detailData?.departureTime" class="mr-8">
+            出发时间{{ contentIsEmpty(defaultNoteJson?.departureTime) }}
+          </span>
+          <span v-if="detailData?.travelMode" class="mr-8">
+            出行方式{{ contentIsEmpty(defaultNoteJson?.travelMode) }}
+          </span>
+          <span v-if="detailData?.countTimes" class="mr-8">
+            出发天数{{ contentIsEmpty(defaultNoteJson?.countTimes) }}
+          </span>
+          <span v-if="detailData?.travelNumber" class="mr-8">
+            游玩人数{{ contentIsEmpty(defaultNoteJson?.travelNumber) }}
+          </span>
+          <span v-if="detailData?.role" class="mr-8">
+            人物关系{{ contentIsEmpty(defaultNoteJson?.role) }}
+          </span>
+          <span v-if="detailData?.averageCost" class="mr-8">
+            人均费用{{ contentIsEmpty(defaultNoteJson?.averageCost) }}
+          </span>
+          <span v-if="detailData?.recommendationRate" class="mr-8">
             推荐指数{{ contentIsEmpty(defaultNoteJson?.recommendationRate) }}
           </span>
         </div>
@@ -330,6 +337,7 @@
       v-model:visible="userInfoOptions.show"
       @submit-ok="handleCollectUserInfoOk"
     />
+    <!--   继续发布组件  -->
     <CreateNotePublishResultModal v-model:visible="publishResultModalOptions" />
   </div>
 </template>
@@ -337,85 +345,42 @@
 <script setup>
 import upload from '~/assets/img/note-create/upload.svg'
 import draft from '~/assets/img/note-create/draft.svg'
-// import { VueDraggable } from 'vue-draggable-plus'
 import defaultAvatar from '~/assets/img/default_avatar.png'
-// import { nanoid } from 'nanoid'
-// import Quill from 'quill'
-// import 'quill-mention/dist/quill.mention.min.css'
-// import { Mention, MentionBlot } from 'quill-mention'
-// Quill.register({ 'blots/mention': MentionBlot, 'modules/mention': Mention })
-
-// import { cloneDeep } from 'lodash-es'
+import Quill from 'quill'
+import 'quill-mention/dist/quill.mention.min.css'
+import { Mention, MentionBlot } from 'quill-mention'
+Quill.register({ 'blots/mention': MentionBlot, 'modules/mention': Mention })
 
 const userInfoStore = useUserInfoStore()
 const { userInfo } = storeToRefs(userInfoStore)
 
-// const editor = ref(null)
-// const editorInnerHTML = ref('')
-
-// const getMember = () => {
-//   let domStr = editor.value.outerHTML
-//   let reg = /<span[^>]+data-id=['"]([^'"]+)['"]+/g
-//   let result = [],
-//     temp
-//   while ((temp = reg.exec(domStr)) != null) {
-//     if (temp[0].includes('data-denotation-char="@"')) result.push({ id: temp[1] })
-//   }
-//   return result
-// }
-// const getTalk = () => {
-//   let domStr = editor.value.outerHTML
-//   let reg = /<span[^>]+data-id=['"]([^'"]+)['"]+/g
-//   let result = [],
-//     temp
-//   while ((temp = reg.exec(domStr)) != null) {
-//     if (temp[0].includes('data-denotation-char="#"')) result.push({ id: temp[1] })
-//   }
-//   return result
-// }
-
 const TOPIC_TEXT = 'topic'
 const EIT_TEXT = 'eit'
-const PTITLE_TEXT = 'paragraphTitle'
-const PCONTENT_TEXT = 'paragraphContent'
 
+const checkboxRefs = ref([null, null])
 const userControlsList = ref([
   {
+    icon: '#',
     title: '# 话题',
     fn: TOPIC_TEXT,
     empty: '暂无话题',
     apiUrl: '/website/tourism/publishTravelNotes/getTopicListByName'
   },
   {
+    icon: '@',
     title: '@ 用户',
     fn: EIT_TEXT,
     empty: '暂无用户',
     apiUrl: '/website/tourism/publishTravelNotes/getFouceEachFriendsByName'
   }
-  // {
-  //   title: 'H 段落标题',
-  //   fn: PTITLE_TEXT
-  // },
-  // {
-  //   title: 'P 段落内容',
-  //   fn: PCONTENT_TEXT
-  // }
 ])
 
 const { loading, setLoading } = useLoading()
 loading.value = false
 
-const defaultSectionTitle = {
-  type: 'sectionTitle',
-  content: ''
-}
-const defaultSectionContent = {
-  type: 'sectionContent',
-  content: ''
-}
-
 const swipeItemIndex = ref(1)
 const inputDiv = ref(null)
+const projectTitleRef = ref(null)
 
 const defaultNoteJson = {
   travelNotesBanner: null,
@@ -439,13 +404,13 @@ const defaultNoteJson = {
   chauId: null, // 洲 id
   imgUrls: [], // 头部的图片数组
   topics: [], // 话题
+  topicsList: [], //保存草稿箱用来校验 话题是否新增的
   mentions: [] // 艾特的用户 {userName:"",userId:123}
 }
+const id = useRouteQuery('id')
 const noteJson = reactive(defaultNoteJson)
-
 watch(noteJson, () => {}, { deep: true, immediate: true })
 
-const id = useRouteQuery('id')
 let currentMention2 = '' // 当前正在输入的 # 用户名
 
 watch(
@@ -457,13 +422,6 @@ watch(
   { immediate: true }
 )
 
-// // 删除的弹窗内容
-// const deleteDialogContent = {
-//   title: '温馨提示',
-//   message: '是否删除',
-//   confirmButtonColor: '#FF9300'
-// }
-
 // 保存草稿的弹窗内容
 const draftDialogContent = {
   title: '是否保存到草稿箱',
@@ -489,7 +447,8 @@ async function getNoteDetail() {
     const res = await request(
       `/website/tourism/publishTravelNotes/getDraftDetail?writeId=${id.value}`
     )
-    const data = res.data ?? {}
+    const data = res.data ?? defaultNoteJson
+    // console.log(data)
 
     for (let i in noteJson) {
       if (data[i]) {
@@ -508,7 +467,7 @@ async function getNoteDetail() {
       noteJson.endPlaceId = data?.endPlaceDictMap?.id
       noteJson.endPlace = data?.endPlaceDictMap?.name
     }
-    console.log(noteJson, 'noteJson')
+    // console.log(noteJson, 'noteJson')
 
     setLoading(false)
   } catch (error) {
@@ -517,23 +476,8 @@ async function getNoteDetail() {
 }
 
 /************ 插入段落标题逻辑 ********** */
-// const insertTilteOptions = reactive({
-//   show: false,
-//   content: null,
-//   editIndex: null
-// })
-
-const editIndex = ref(null)
-
-function handleInsertOrEditTitleIndex2(event) {
-  // editIndex.value = index
-  // 隐藏建议框
-  // if (!inputDiv.contains(event.target) && !suggestionsBox.contains(event.target)) {
-  //   suggestionsBox.style.display = 'none'
-  // } else {
-  //   suggestionsBox.style.display = 'block'
-  // }
-}
+
+// const editIndex = ref(null)
 
 // 点击编辑大标题,
 function handleInsertOrEditProjectTitle(value) {
@@ -543,47 +487,58 @@ function handleInsertOrEditProjectTitle(value) {
   }
 }
 
-let cursorPosition = { offsetX: 0, offsetY: 0 } // 光标位置
+// let cursorPosition = { offsetX: 0, offsetY: 0 } // 光标位置
 
 // 点击编辑或者新增段落标题,
-const eidContent = ref('') //记录艾特后输入的内容
-
-function handleInsertOrEditTitleText(value) {
-  const selection = window.getSelection()
-  cursorPosition = selection.getRangeAt(0).getBoundingClientRect()
-  let text = value.target.innerHTML
-
-  let lastAtSign = -1
-  let lastAtSign2 = -1
+// const eidContent = ref('') //记录艾特后输入的内容
+// function handleInsertOrEditTitleText(value) {
+//   const selection = window.getSelection()
+//   cursorPosition = selection.getRangeAt(0).getBoundingClientRect()
+//   let text = value.target.innerHTML
+
+//   let lastAtSign = -1
+//   let lastAtSign2 = -1
+
+//   if (text) {
+//     lastAtSign = text.indexOf('@')
+//     lastAtSign2 = text.indexOf('#')
+//   } else {
+//     currentMention2 = ''
+//     lastAtSign = -1
+//     lastAtSign2 = -1
+//   }
 
-  if (text) {
-    lastAtSign = text.indexOf('@')
-    lastAtSign2 = text.indexOf('#')
-  } else {
-    currentMention2 = ''
-    lastAtSign = -1
-    lastAtSign2 = -1
-  }
+//   currentMention2 = text
+//   // 如果最后输入的是 @,显示用户列表
+//   if (lastAtSign !== -1 && text[lastAtSign + 1] !== ' ') {
+//     eidContent.value = text.slice(lastAtSign) // 获取 @ 后的部分 包含@符号
 
-  currentMention2 = text
-  // 如果最后输入的是 @,显示用户列表
-  if (lastAtSign !== -1 && text[lastAtSign + 1] !== ' ') {
-    eidContent.value = text.slice(lastAtSign) // 获取 @ 后的部分 包含@符号
+//     showTopicEit.value = userControlsList.value[1].fn
+//     getTopicList(userControlsList.value[1])
+//   }
 
-    showTopicEit.value = userControlsList.value[1].fn
-    getTopicList(userControlsList.value[1])
-  }
+//   if (lastAtSign2 !== -1 && text[lastAtSign2 + 1] !== ' ') {
+//     eidContent.value = text.slice(lastAtSign2) // 获取 # 后的部分 包含@符号
 
-  if (lastAtSign2 !== -1 && text[lastAtSign2 + 1] !== ' ') {
-    eidContent.value = text.slice(lastAtSign2) // 获取 # 后的部分 包含@符号
+//     showTopicEit.value = userControlsList.value[0].fn
+//     getTopicList(userControlsList.value[0])
+//   }
+// }
 
-    showTopicEit.value = userControlsList.value[0].fn
-    getTopicList(userControlsList.value[0])
+// 提取@和# 的内容
+const getMention = (type) => {
+  if (!type) return []
+  let domStr = editor.value.outerHTML
+  // let reg = /<span[^>]+data-id=['"]([^'"]+)['"]+/g;
+  let reg = /<span[^>]*\bdata-id="([^">]+)"[^>]*\bdata-value="([^">]+)"/g
+  let result = [],
+    temp
+  while ((temp = reg.exec(domStr)) != null) {
+    console.log(temp[1], temp[2], temp[0])
+    if (temp[0].includes(`data-denotation-char="${type}"`))
+      result.push({ value: temp[1], label: temp[2] })
   }
-
-  // if (lastAtSign == -1 || lastAtSign2 == -1) {
-  //   noteJson.tourTourismProjectTravelNotesWriteContentDto.content = currentMention2
-  // }
+  return result
 }
 
 /******************插入正文相关逻辑*******************/
@@ -595,9 +550,44 @@ async function handleSaveDraft() {
   try {
     parmas = { ...noteJson }
     parmas.endPlace = noteJson.endPlaceId
+    const innerHTML = editor.value.innerHTML
+      .replace('ql-editor', '')
+      .replace('contenteditable', 'true')
+
+    parmas.tourTourismProjectTravelNotesWriteContentDto.content = innerHTML ?? ''
 
-    if (inputDiv.value.innerHTML) {
-      parmas.tourTourismProjectTravelNotesWriteContentDto.content = inputDiv.value.innerHTML
+    const talkList = getMention('#')
+
+    if (talkList.length) {
+      parmas.topics = talkList.map((item) => {
+        if (item.label == item.value) {
+          return {
+            id: '',
+            name: item.label
+          }
+        } else {
+          return {
+            id: item.value,
+            name: item.label
+          }
+        }
+      })
+    }
+
+    if (parmas?.topicsList.length) {
+      parmas.topics.forEach((i) => {
+        const matchingItem = parmas.topicsList.find((o) => o.name === i.name)
+        if (matchingItem && i.id === '') {
+          i.id = matchingItem.id
+        }
+      })
+    }
+    console.log(parmas.topics, ' parmas.topics')
+
+    let memberList = getMention('@')
+
+    if (memberList.length) {
+      parmas.mentions = memberList.map((item) => ({ userName: item.label, userId: item.value }))
     }
 
     await request('/website/tourism/publishTravelNotes/saveDraft', {
@@ -607,8 +597,12 @@ async function handleSaveDraft() {
         id: id?.value
       }
     })
-
     showToast('草稿保存成功')
+    // 后端保存草稿没有对 topics 做新增的处理
+    navigateTo({
+      path: '/profile/notes?tab=draft',
+      replace: true
+    })
   } finally {
   }
 }
@@ -620,8 +614,11 @@ const previewOptions = reactive({
 
 function handlePreview() {
   previewOptions.show = !previewOptions.show
+  const innerHTML = editor.value.innerHTML
+    .replace('ql-editor', '')
+    .replace('contenteditable', 'true')
 
-  noteJson.tourTourismProjectTravelNotesWriteContentDto.content = inputDiv.value.innerHTML
+  noteJson.tourTourismProjectTravelNotesWriteContentDto.content = innerHTML ?? ''
 }
 
 // 收集个人信息
@@ -643,6 +640,15 @@ function handlePublishRule(length, endPlace) {
   }
 }
 
+// 触发 mention 搜索功能
+const openMention = (type) => {
+  const range = quillContent.getSelection()
+  const index = range?.index ?? 0
+  quillContent.setSelection(index)
+  const mentionModule = quillContent.getModule('mention')
+  mentionModule.openMenu(type)
+}
+
 // 发布
 async function handlePublish() {
   if (!noteJson.imgUrls.length) {
@@ -653,30 +659,15 @@ async function handlePublish() {
     })
     return
   }
-  // if (!noteJson.projectTitle) {
-  //   showNotify({
-  //     type: 'warning',
-  //     message: '请输入游记标题',
-  //     duration: 3000
-  //   })
-  //   return
-  // }
+
   if (!noteJson.endPlace) {
     showNotify({
       type: 'warning',
-      message: '请选择目的地',
+      message: '请选择地区',
       duration: 3000
     })
     return
   }
-  // if (noteJson.travelNotesContent.length === 0) {
-  //   showNotify({
-  //     type: 'warning',
-  //     message: '游记内容不能为空',
-  //     duration: 3000
-  //   })
-  //   return
-  // }
 
   const { data: isPerfect } = await request('/website/tourism/publishTravelNotes/isPerfect')
   if (isPerfect === 0) {
@@ -690,17 +681,49 @@ async function handlePublish() {
 const publishLoading = ref(false)
 
 async function requestPublish() {
-  let parmas = {}
   try {
     publishLoading.value = true
+    let parmas = {}
 
     parmas = { ...noteJson }
     if (noteJson.endPlaceId) {
       parmas.endPlace = noteJson.endPlaceId
     }
 
-    if (inputDiv.value.innerHTML) {
-      parmas.tourTourismProjectTravelNotesWriteContentDto.content = inputDiv.value.innerHTML
+    //TODO 取笔记内容
+    const innerHTML = editor.value.innerHTML
+      .replace('ql-editor', '')
+      .replace('contenteditable', 'false')
+
+    if (innerHTML) {
+      parmas.tourTourismProjectTravelNotesWriteContentDto.content = innerHTML
+    }
+
+    // 后端可能会要求你把@的人或话题ID传回去
+    // const memberList = getMention('@')
+    const talkList = getMention('#')
+
+    console.log(talkList, 'talkList')
+    if (talkList.length) {
+      parmas.topics = talkList.map((item) => {
+        if (item.label == item.value) {
+          return {
+            id: '',
+            name: item.label
+          }
+        } else {
+          return {
+            id: item.value,
+            name: item.label
+          }
+        }
+      })
+    }
+
+    let memberList = getMention('@')
+
+    if (memberList.length) {
+      parmas.mentions = memberList.map((item) => ({ userName: item.label, userId: item.value }))
     }
 
     await request('/website/tourism/publishTravelNotes/publishDraft', {
@@ -712,6 +735,8 @@ async function requestPublish() {
     })
 
     publishResultModalOptions.value = true
+
+    editor.value.innerHTML = ''
     publishLoading.value = false
   } catch (error) {
     publishLoading.value = false
@@ -732,13 +757,14 @@ const queryParmas = reactive({
 })
 
 const topicLoading = ref(false)
-async function getTopicList(parmas) {
+async function getTopicList(parmas, searchText) {
   try {
     // if (!topicLoading.value) return
     topicLoading.value = true
     const { data } = await request(parmas.apiUrl, {
       query: {
-        ...queryParmas
+        ...queryParmas,
+        name: searchText
       }
     }).finally(() => (topicLoading.value = false))
 
@@ -768,77 +794,37 @@ const hotTopicList = computed(() => {
 })
 
 const showExpandTextInput = ref(false)
-// 扩展内容的插件 同时图片放大和缩小
-function expandTextInput() {
-  showExpandTextInput.value = !showExpandTextInput.value
-}
 
 // 对应的操作
-const handleOperate = (operate) => {
-  try {
-    switch (operate.fn) {
-      case TOPIC_TEXT:
-        if (showTopicEit.value == TOPIC_TEXT) {
-          showTopicEit.value = null
-        } else {
-          noteJson.tourTourismProjectTravelNotesWriteContentDto.content =
-            inputDiv.value.innerHTML + '#'
-          showTopicEit.value = operate.fn
-          getTopicList(operate)
-          // handleInsertOrEditTitleText(noteJson.tourTourismProjectTravelNotesWriteContentDto.content)
-        }
-        break
-      case EIT_TEXT:
-        if (showTopicEit.value == EIT_TEXT) {
-          showTopicEit.value = null
-        } else {
-          showTopicEit.value = operate.fn
-          noteJson.tourTourismProjectTravelNotesWriteContentDto.content =
-            inputDiv.value.innerHTML + '@'
-          getTopicList(operate)
-          // handleInsertOrEditTitleText(noteJson.tourTourismProjectTravelNotesWriteContentDto.content)
-        }
+// const handleOperate = (operate) => {
+//   try {
+//     switch (operate.fn) {
+//       case TOPIC_TEXT:
+//         if (showTopicEit.value == TOPIC_TEXT) {
+//           showTopicEit.value = null
+//         } else {
+//           noteJson.tourTourismProjectTravelNotesWriteContentDto.content =
+//             inputDiv.value.innerHTML + '#'
+//           showTopicEit.value = operate.fn
+//           getTopicList(operate)
+//           // handleInsertOrEditTitleText(noteJson.tourTourismProjectTravelNotesWriteContentDto.content)
+//         }
+//         break
+//       case EIT_TEXT:
+//         if (showTopicEit.value == EIT_TEXT) {
+//           showTopicEit.value = null
+//         } else {
+//           showTopicEit.value = operate.fn
+//           noteJson.tourTourismProjectTravelNotesWriteContentDto.content =
+//             inputDiv.value.innerHTML + '@'
+//           getTopicList(operate)
+//           // handleInsertOrEditTitleText(noteJson.tourTourismProjectTravelNotesWriteContentDto.content)
+//         }
 
-        break
-      case PTITLE_TEXT:
-        handleInsertOrEditTitleOk(defaultSectionTitle)
-        break
-      case PCONTENT_TEXT:
-        handleInsertOrEditTitleOk(defaultSectionContent)
-        break
-    }
-  } catch (e) {}
-}
-const bindFn = () => {
-  // 获取文档中的所有 span 标签
-  const container = document.getElementById('view-note')
-  const spans = container.querySelectorAll('span')
-  spans.forEach((span) => {
-    if (span.getAttribute('data-denotation-char') === '@') {
-      span.addEventListener('click', (event) => {
-        // console.log('@用户ID', span.getAttribute('data-id'))
-        // console.log('@用户名字', span.innerHTML)
-        // alert('@用户:' + span.innerText)
-        navigateTo({
-          path: `/profile-others/${span.getAttribute('data-id')}`
-        })
-      })
-    }
-    if (span.getAttribute('data-denotation-char') === '#') {
-      span.addEventListener('click', (event) => {
-        // console.log('话题ID', span.getAttribute('data-id'))
-        // console.log('话题内容', span.innerHTML)
-        // alert('话题内容:' + span.innerText)
-        navigateTo({
-          path: '/topic',
-          query: {
-            topicName: span.innerText
-          }
-        })
-      })
-    }
-  })
-}
+//         break
+//     }
+//   } catch (e) {}
+// }
 
 // 点击话题的事件
 function handleTopicAndEit(parmas, pType) {
@@ -849,14 +835,14 @@ function handleTopicAndEit(parmas, pType) {
       if (contentText.includes('#')) {
         contentText = contentText.replace(
           new RegExp(eidContent.value, 'g'),
-          `<span class="mention" data-denotation-char='#' >#${parmas.name}</span> `
+          `<span contenteditable="false" class="mention" data-denotation-char='#' >#${parmas.name}</span> `
         )
         showTopicEit.value = null
         eidContent.value = ''
       } else {
         contentText = contentText.replace(
           new RegExp(eidContent.value, 'g'),
-          `<span class="mention" data-denotation-char='#'  >#${parmas.name}</span>`
+          `<span contenteditable="false"  class="mention" data-denotation-char='#'  >#${parmas.name}</span>`
         )
       }
       let findIndex = noteJson.topics.findIndex((i) => i?.name == parmas.name)
@@ -868,7 +854,7 @@ function handleTopicAndEit(parmas, pType) {
       if (contentText.includes('@')) {
         contentText = contentText.replace(
           new RegExp(eidContent.value, 'g'),
-          `<span class="mention" data-denotation-char="@" data-id="${parmas.userId}" >@${parmas.showName}</span>`
+          `<span contenteditable="false" class="mention" data-denotation-char="@" data-id="${parmas.userId}"  >@${parmas.showName}</span>`
         )
 
         showTopicEit.value = null
@@ -876,7 +862,7 @@ function handleTopicAndEit(parmas, pType) {
       } else {
         contentText = contentText.replace(
           new RegExp(eidContent.value, 'g'),
-          `<span class="mention" data-denotation-char="@" data-id="${parmas.userId}" >@${parmas.showName}</span>`
+          `<span contenteditable="false" class="mention" data-denotation-char="@" data-id="${parmas.userId}" >@${parmas.showName}</span>`
         )
       }
 
@@ -903,55 +889,123 @@ function contentIsEmpty(content) {
   }
 }
 
-// const initEdit = () => {
-//   new Quill(editor.value, {
-//     placeholder: '请输入内容...',
-//     modules: {
-//       mention: {
-//         allowedChars: /^[\u4e00-\u9fa5]*$/, //匹配中文搜索
-//         mentionDenotationChars: ['@', '#'],
-//         positioningStrategy: 'fixed',
-//         renderItem: (data) => {
-//           // 这里文档是可以返回html的,但是没有显示正确
-//           return data.value
-//         },
-//         renderLoading: () => {
-//           return 'Loading...'
-//         },
-//         source: (searchTerm, renderList, mentionChar) => {
-//           console.log(searchTerm, 'searchTerm')
-//           console.log(renderList, 'renderList')
-//           console.log(mentionChar, 'mentionChar')
-
-//           let list = []
-//           if (mentionChar === '@') {
-//             // 调用接口 获取数据 传searchTerm字段实现搜索效果
-//             getTopicList(userControlsList.value[1])
-//             list = cloneDeep(eitList.value)
-//           } else {
-//             // 调用接口 获取数据 传searchTerm字段实现搜索效果
-//             getTopicList(userControlsList.value[0])
-//             list = cloneDeep(topicList.value)
-//           }
-
-//           if (!searchTerm) {
-//             renderList(list, searchTerm)
-//           } else {
-//             const matches = []
-//             for (let i = 0; i < list.length; i++)
-//               if (list[i].value.toLowerCase().indexOf(searchTerm.toLowerCase()))
-//                 matches.push(list[i])
-//             renderList(matches, searchTerm)
-//           }
-//         }
-//       }
-//     }
-//   })
-// }
+const editor = ref(null)
+let quillContent = null
+const initEdit = () => {
+  // console.log(editor.value, 'editor-ref')
+  quillContent = new Quill(editor.value, {
+    placeholder: '请输入内容...',
+    modules: {
+      mention: {
+        allowedChars: /[\s\S]*$/, //支持任意字符得正则
+        mentionDenotationChars: ['@', '#'],
+        positioningStrategy: 'fixed',
+        renderItem: (data) => {
+          // 这里文档是可以返回html的,但是没有显示正确
+          return data.value
+        },
+        renderLoading: () => {
+          return 'Loading...'
+        },
+        source: async (searchTerm, renderList, mentionChar) => {
+          // console.log(searchTerm, 'searchTerm')
+          // console.log(renderList, 'renderList')
+          // console.log(mentionChar, 'mentionChar')
+
+          let responseData = [],
+            requestDta = {
+              pageNum: 1,
+              pageSize: 10,
+              name: searchTerm
+            }
+
+          if (mentionChar === '@') {
+            // 调用接口 获取数据 传searchTerm字段实现搜索效果
+            const { data } = await request(
+              '/website/tourism/publishTravelNotes/getFouceEachFriendsByName',
+              {
+                query: requestDta
+              }
+            )
+
+            if (data) {
+              eitList.value = data
+            }
+            responseData = data?.map((o) => {
+              return {
+                id: o.userId,
+                value: o.showName,
+                icon: o.headImageUrl
+              }
+            })
+          } else {
+            const { data } = await request(
+              '/website/tourism/publishTravelNotes/getTopicListByName',
+              {
+                query: requestDta
+              }
+            )
+
+            if (data) {
+              topicList.value = data
+            }
+            responseData = data?.map((o) => {
+              return {
+                id: o.id || o.name,
+                value: o.name,
+                count: o.totalViewCount ?? 0
+              }
+            })
+          }
+
+          if (!searchTerm) {
+            renderList(responseData, searchTerm)
+          } else {
+            const matches = []
+            for (let i = 0; i < responseData.length; i++)
+              if (~responseData[i].value.toLowerCase().indexOf(searchTerm.toLowerCase()))
+                matches.push(responseData[i])
+            renderList(matches, searchTerm)
+          }
+        }
+      }
+    }
+  })
+  // 监听获取焦点事件
+  quillContent.root.addEventListener('focus', () => {
+    console.log('quillContent编辑器获取了焦点')
+    showExpandTextInput.value = true
+  })
+}
 
-// onMounted(() => {
-//   // initEdit()
-// })
+// 判断是否点击的非输入框 || @按钮 #按钮
+const editorFather = ref(null)
+const handleClickOutside = (event) => {
+  let projectTitleRefCompEl = projectTitleRef.value
+  const isChatInputCompEl =
+    [checkboxRefs.value[0], checkboxRefs.value[1]].some((o) => o === event.target) ||
+    editorFather.value.contains(event.target) ||
+    projectTitleRefCompEl.contains(event.target)
+
+  if (!isChatInputCompEl) {
+    // 不是点输入框部分
+    showExpandTextInput.value = false
+  }
+}
+
+watch(
+  editor,
+  (val) => {
+    if (val && !quillContent) initEdit()
+  },
+  { immediate: true }
+)
+
+onMounted(() => {
+  useEventListener('click', handleClickOutside, { target: document })
+  useEventListener('mousedown', handleClickOutside, { target: document })
+  useEventListener('touchstart', handleClickOutside, { target: document })
+})
 </script>
 
 <style lang="scss" scoped>
@@ -962,7 +1016,7 @@ function contentIsEmpty(content) {
   outline: none;
 }
 
-.inputSectionContent:empty:before {
+::v-deep .inputSectionContent:empty:before {
   content: '请输入内容...';
   color: #e7e7e7;
 }
@@ -975,15 +1029,12 @@ function contentIsEmpty(content) {
   color: #2c405b;
   font-weight: bold;
   margin-left: 4px;
+  background-color: transparent;
 }
 
-.ql-editor {
-  border: 1px solid #a3a3a3;
-  border-radius: 6px;
-}
-
-.ql-editor:focus {
-  border: 1px solid #409eff;
+::v-deep .ql-editor:focus {
+  caret-color: #ff9300 !important;
+  outline: none;
 }
 
 .ql-mention-list-container {
@@ -999,11 +1050,6 @@ function contentIsEmpty(content) {
   background-color: #f5f7fa !important;
 }
 
-.mention {
-  color: #409eff;
-  background-color: transparent;
-}
-
 .member-item {
   display: flex;
   align-items: center;

+ 16 - 22
src/pages/profile-others/[id].vue

@@ -41,7 +41,11 @@
 
           <div class="ml-8">
             <h1 class="text-black-3 font-medium text-xl mb-8">{{ othersUserInfo?.showName }}</h1>
-            <p class="text-sm text-black-3">{{ othersUserInfo?.personalSign }}</p>
+            <p class="text-sm line-clamp-2 text-black-3">
+              {{
+                othersUserInfo?.personalSign
+              }}asdjvaghsdavgshdsdahsd2asbdjhasd卢卡斯百度哈桑广大萨达撒看见是大家说的噶话说的说的话京噶手机号大噶十九大
+            </p>
           </div>
         </div>
 
@@ -49,24 +53,24 @@
           <div>
             <span class="text-black-9 mr-4">关注</span>
             <span class="text-black-3 font-medium">
-              {{ formatNumberLetter(othersUserInfo?.numberOfConcern) }}
+              {{ transferCount(othersUserInfo?.numberOfConcern) }}
             </span>
           </div>
           <div>
             <span class="text-black-9 mr-4">粉丝</span>
             <span class="text-black-3 font-medium">
-              {{ formatNumberLetter(othersUserInfo?.numberOfFollowers) }}
+              {{ transferCount(othersUserInfo?.numberOfFollowers) }}
             </span>
           </div>
           <div>
             <span class="text-black-9 mr-4">获赞</span>
             <span class="text-black-3 font-medium">
-              {{ formatNumberLetter(othersUserInfo?.praiseNum) }}
+              {{ transferCount(othersUserInfo?.praiseNum) }}
             </span>
           </div>
         </div>
 
-        <div class="mt-15 flex justify-between">
+        <div class="mt-10 flex justify-between">
           <button
             @click="
               navigateTo({
@@ -80,7 +84,7 @@
           <div class="flex items-center">
             <van-button
               v-if="othersUserInfo?.state == 0 || othersUserInfo?.state == 4"
-              style="width: 72px"
+              style="width: 72px; height: 28px"
               size="small"
               type="primary"
               round
@@ -98,7 +102,7 @@
               {{ followState(othersUserInfo?.state).text }}
             </button>
             <van-button
-              style="width: 72px; margin-left: 12px"
+              style="width: 72px; height: 28px; margin-left: 12px"
               size="small"
               type="primary"
               round
@@ -162,21 +166,11 @@
               <span class="w-[70%] ml-4 text-black-9 text-sm">{{ i?.name }}</span>
             </div>
 
-            <div class="flex shrink-0 justify-start items-cneter text-black-9 text-sm">
-              <img
-                v-if="i.isLike"
-                class="w-16 h-16 mr-4"
-                src="~/assets/img/profile-others/Like2.svg"
-                alt=""
-                @click="() => {}"
-              />
-              <img
-                v-else
-                class="w-16 h-16 mr-4"
-                src="~/assets/img/profile-others/Like.svg"
-                alt=""
-                @click="() => {}"
-              />
+            <div class="flex shrink-0 justify-start items-center text-black-9 text-sm">
+              <span
+                class="iconfont icon-Thumbs-up text-black-9 mr-4"
+                style="font-size: 16px"
+              ></span>
               {{ formatNumberLetter(i?.likeCount) }}
             </div>
           </div>

+ 6 - 3
src/pages/profile/collection.client.vue

@@ -112,7 +112,8 @@ async function getCollectionListTopic() {
 function handleCancel(item) {
   showConfirmDialog({
     title: '提示',
-    message: '确认取消收藏吗'
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
   }).then(() => {
     request('/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate', {
       method: 'post',
@@ -132,7 +133,8 @@ function handleCancel(item) {
 function handleCommentCancel(item) {
   showConfirmDialog({
     title: '提示',
-    message: '确认取消收藏吗'
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
   }).then(() => {
     request('/website/comment/tourTravelNotesComment/commentCollectCancle', {
       method: 'post',
@@ -149,7 +151,8 @@ function handleCommentCancel(item) {
 function handleTopicCancel(item) {
   showConfirmDialog({
     title: '提示',
-    message: '确认取消收藏吗'
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
   }).then(() => {
     request('/website/tourism/travelNotesTopic/cancelCollection', {
       method: 'post',

+ 0 - 110
src/pages/test/_index.vue

@@ -1,110 +0,0 @@
-<template>
-  <div>
-    <van-button class="mt-50" @click="openPermission">打开录音权限</van-button>
-    <div class="flex">
-      <van-button class="mt-50" @click="startRecording">开始录音</van-button>
-      <van-button class="mt-50" @click="stopRecording">关闭并下载录音</van-button>
-    </div>
-  </div>
-</template>
-<script setup>
-// https://github.com/xiangyuecn/Recorder
-// import VConsole from 'vconsole';
-import Recorder from "recorder-core";
-//需要使用到的音频格式编码引擎
-import 'recorder-core/src/engine/mp3'
-import 'recorder-core/src/engine/mp3-engine'
-//可选的扩展编码引擎
-import 'recorder-core/src/extensions/waveview'
-// new VConsole({ theme: 'dark' });
-
-const videoConfig = {
-  type: 'mp3',
-  bitRate: 16,
-  sampleRate: 16000,
-  duration: 0,
-  durationTxt: "0",
-  powerLevel: 0,
-  logs: []
-}
-let recorderInstance = null
-const openPermission = () => {
-  recorderInstance = Recorder({
-    type: 'mp3',
-    bitRate: 16,
-    sampleRate: 16000,
-    duration: 0,
-    onProcess: function (buffers, powerLevel, duration, sampleRate) {
-      console.log('录制中~')
-    }
-  });
-  recorderInstance.open(function () {
-    alert('录音已打开')
-  }, function (msg, isUserNotAllow) {
-    alert('录音打开失败')
-  });
-}
-
-const startRecording = () => {
-  try {
-    if (!recorderInstance || !Recorder.IsOpen()) {
-      alert('未打开录音')
-      return
-    }
-    alert('开始录音')
-    recorderInstance.start()
-  } catch (e) {
-    alert(e)
-  }
-}
-const stopRecording = () => {
-  if (!recorderInstance || !Recorder.IsOpen()) {
-    alert('未打开录音')
-    return
-  }
-  recorderInstance.stop(
-      (blob, duration) => {
-        alert('录制成功')
-        const o = {
-          blob: blob,
-          duration: duration,
-          durationTxt: formatMs(duration),
-          rec: recorderInstance
-        }
-        let name = "rec-" + o.duration + "ms-" + (o.rec.set.bitRate || "-") + "kbps-" + (o.rec.set.sampleRate || "-") + "hz." + (o.rec.set.type || (/\w+$/.exec(o.blob.type) || [])[0] || "unknown");
-        let downA = document.createElement("A");
-        downA.href = (window.URL || webkitURL).createObjectURL(o.blob);
-        downA.download = name;
-        downA.click();
-        alert('下载成功')
-      },
-      (e) => {
-        alert(e + '录音失败')
-      }
-  )
-
-
-}
-
-
-const formatMs = (ms, all) => {
-  let ss = ms % 1000;
-  ms = (ms - ss) / 1000;
-  let s = ms % 60;
-  ms = (ms - s) / 60;
-  let m = ms % 60;
-  ms = (ms - m) / 60;
-  let h = ms;
-  let t = (h ? h + ":" : "")
-      + (all || h + m ? ("0" + m).substr(-2) + ":" : "")
-      + (all || h + m + s ? ("0" + s).substr(-2) + "″" : "")
-      + ("00" + ss).substr(-3);
-  return t;
-}
-
-</script>
-<style scoped lang="scss">
-* {
-  user-select: none;
-}
-</style>

+ 0 - 145
src/pages/test/index.vue

@@ -1,145 +0,0 @@
-<template>
-  <div class="test-page flex flex-col" oncontextmenu="return false;">
-    <div class="flex flex-col">
-      <template v-for="(message, i) in messageList" :key="i">
-        <ChatMessage :message="message"></ChatMessage>
-      </template>
-    </div>
-
-    <div class="flex mt-auto py-20 flex-col bg-[#999]">
-      <van-uploader
-        :preview-image="false"
-        :after-read="upLoadImg"
-        accept="image/*"
-        :multiple="false"
-        :max-count="1"
-      >
-        <img src="~/assets/img/scan/pic.png" height="32" width="32" alt="" />
-      </van-uploader>
-      <!--      <template v-if="inRecording">
-        <div class="flex flex-row px-20 justify-around">
-          <van-button @click="cancelRecording">取消</van-button>
-          <van-button @click="handleStopRecording" type="warning">完成并发送</van-button>
-        </div>
-        <div class="flex flex-row p-20 justify-center text-white text-base">
-          <van-loading class="mr-5"/>
-          正在说话
-        </div>
-      </template>
-      <template v-else>
-        <van-button type="primary" @click="handleTouchstart">点击说话</van-button>
-      </template>-->
-    </div>
-  </div>
-</template>
-<script setup>
-import ChatMessage from '../chat/components/chat-message'
-import { useRecording } from '~/pages/test/useRecording'
-// import VConsole from 'vconsole';
-// new VConsole({ theme: 'dark' });
-
-let messageList = ref([
-  {
-    type: 'link',
-    messageContent: '大概更.baidu.com',
-    viewType: 0
-  },
-  {
-    type: 'link',
-    messageContent: '大概更多如果更多人的人人待https://fanyi.baidu.com',
-    viewType: 0
-  },
-  {
-    type: 'link',
-    messageContent: 'rdrdgdrwrhttps://fastly.jsdelivr.net/npm/@vant/assets/logo.png',
-    viewType: 1
-  },
-  {
-    type: 'text',
-    messageContent:
-      '发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息',
-    viewType: 0
-  },
-  {
-    type: 'text',
-    messageContent:
-      '发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息发送文字消息',
-    viewType: 1
-  },
-  {
-    type: 'image',
-    messageContent: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg',
-    viewType: 0
-  },
-  {
-    type: 'image',
-    messageContent: null,
-    viewType: 1
-  },
-  {
-    type: 'image',
-    messageContent: 'https://fastly.jsdelivr.net/npm/@vant/assets/logo.png',
-    viewType: 1
-  }
-])
-
-const { inRecording, startRecording, stopRecording, cancelRecording } = useRecording()
-const handleTouchstart = async () => {
-  try {
-    await startRecording()
-  } catch (e) {
-  } finally {
-  }
-}
-
-const handleStopRecording = async () => {
-  try {
-    const { success, errorMessage, audio } = await stopRecording()
-    if (!success) {
-      showToast(errorMessage)
-      return
-    }
-    console.log(audio, '---audio---')
-    const formData = new FormData()
-    formData.append('uploadFile', audio.blob)
-    formData.append('asImage', false)
-    formData.append('fieldName', 'messageContent')
-    const res = await request(`/website/tourMessage/upload`, {
-      method: 'post',
-      body: formData
-    })
-    console.log(res, 'resresres')
-  } catch (e) {
-    console.log(e, 'handleStopRecording')
-  } finally {
-  }
-}
-
-const upLoadImg = async (e, b) => {
-  try {
-    console.log(e.file)
-    messageList.value.push({
-      type: 'image',
-      messageContent: e.file,
-      viewType: 0
-    })
-  } catch (e) {}
-}
-onMounted(() => {
-  /*  document.addEventListener('contextmenu', function(e) {
-      e.preventDefault();
-    });*/
-})
-</script>
-<style scoped lang="scss">
-* {
-  user-select: none;
-}
-
-.test-page {
-  height: calc(100vh - 50px);
-  width: 100%;
-  padding: 20px;
-  box-sizing: border-box;
-}
-</style>

+ 0 - 184
src/pages/test/useRecording.js

@@ -1,184 +0,0 @@
-// https://github.com/xiangyuecn/Recorder
-
-import Recorder from "recorder-core";
-//需要使用到的音频格式编码引擎
-import 'recorder-core/src/engine/mp3'
-import 'recorder-core/src/engine/mp3-engine'
-//可选的扩展编码引擎
-import 'recorder-core/src/extensions/waveview'
-
-/*const videoConfig = {
-    type: 'mp3',
-    bitRate: 16,
-    sampleRate: 16000,
-    duration: 0,
-    durationTxt: "0",
-    powerLevel: 0,
-    logs: []
-}*/
-export const useRecording = () => {
-  let recorderInstance = null;
-  let inRecording = ref(false)
-  const openPermission = () => {
-    return new Promise((resolve, reject) => {
-      if (recorderInstance && Recorder.IsOpen()) resolve()
-      if (!recorderInstance) {
-        recorderInstance = Recorder({
-          type: 'mp3',
-          bitRate: 16,
-          sampleRate: 16000,
-          duration: 0,
-          onProcess: function (buffers, powerLevel, duration, sampleRate) {
-            console.log('录制中~')
-            inRecording.value = true
-          }
-        });
-        recorderInstance.open(
-          () => {
-            resolve()
-          },
-          () => {
-            reject()
-          }
-        )
-        return
-      }
-      if (!Recorder.IsOpen()) {
-        recorderInstance.open(
-          () => {
-            resolve()
-          },
-          () => {
-            reject()
-          }
-        )
-        return;
-      }
-    })
-  }
-
-  const startRecording = async () => {
-    try {
-      await openPermission()
-      recorderInstance.start()
-    } catch (e) {
-      console.error(e, 'startRecording')
-    }
-  }
-  const stopRecording = async () => {
-    return new Promise((resolve, reject) => {
-      if (!recorderInstance || !Recorder.IsOpen()) {
-        console.log('未开启录音!')
-        resolve({
-          success: false,
-          errorMessage: '未开启录音'
-        })
-      }
-
-      recorderInstance.stop(
-        (blob, duration) => {
-          inRecording.value = false
-          console.log('----录制完成-----', blob, duration)
-          if ((duration / 1000) < 1) {
-            console.log(duration, '录音小于一秒')
-            resolve({
-              success: false,
-              errorMessage: '说话时间太短'
-            })
-          } else {
-            console.log(duration, '录音合格')
-            resolve({
-              success: true,
-              audio: {
-                blob: blob,
-                duration: duration,
-                durationTxt: formatMs(duration),
-                href: (window.URL || webkitURL).createObjectURL(blob)
-              },
-              errorMessage: ''
-            })
-            /*const o = {
-              blob: blob,
-              duration: duration,
-              durationTxt: formatMs(duration),
-              rec: recorderInstance
-            }
-            let name = "rec-" + o.duration + "ms-" + (o.rec.set.bitRate || "-") + "kbps-" + (o.rec.set.sampleRate || "-") + "hz." + (o.rec.set.type || (/\w+$/.exec(o.blob.type) || [])[0] || "unknown");
-            let downA = document.createElement("A");
-            downA.href = (window.URL || webkitURL).createObjectURL(o.blob);
-            downA.download = name;
-            downA.click();
-            alert('下载成功')*/
-          }
-        },
-        (e) => {
-          inRecording.value = false
-          resolve({
-            success: false,
-            errorMessage: e
-          })
-        }
-      )
-    })
-  }
-  const cancelRecording = async () => {
-    return new Promise((resolve) => {
-      if (!recorderInstance || !Recorder.IsOpen()) {
-        console.log('未开启录音!')
-        resolve({
-          success: true,
-          errorMessage: ''
-        })
-      }
-
-      recorderInstance.stop(
-        (blob, duration) => {
-          inRecording.value = false
-          resolve({
-            success: true,
-            errorMessage: ''
-          })
-
-        },
-        (e) => {
-          inRecording.value = false
-          resolve({
-            success: false,
-            errorMessage: e
-          })
-        }
-      )
-    })
-  }
-  const formatMs = (ms, all) => {
-    let ss = ms % 1000;
-    ms = (ms - ss) / 1000;
-    let s = ms % 60;
-    ms = (ms - s) / 60;
-    let m = ms % 60;
-    ms = (ms - m) / 60;
-    let h = ms;
-    let t = (h ? h + ":" : "")
-      + (all || h + m ? ("0" + m).substr(-2) + ":" : "")
-      + (all || h + m + s ? ("0" + s).substr(-2) + "″" : "")
-      + ("00" + ss).substr(-3);
-    return t;
-  }
-
-  const closeRecording = () => {
-    recorderInstance && recorderInstance.close()
-  }
-
-  onUnmounted(() => {
-    closeRecording()
-  })
-  return {
-    inRecording, // 是否在录音中
-    openPermission,// 开启录音系统权限
-    startRecording,// 开始录音
-    stopRecording,// 停止录音
-    cancelRecording,//  取消录音
-    closeRecording,// 关闭录音权限
-  }
-
-}

+ 0 - 476
src/pages/test22.vue

@@ -1,476 +0,0 @@
-<template>
-  <div class="screen">
-    <div class="frame">
-      <header class="header">
-        <!-- <Close class="close-instance" color="#666666" /> -->
-        <div class="text-wrapper">单独购买</div>
-      </header>
-
-      <div class="input">
-        <div class="div">
-          <div class="item-label">
-            <div class="text">
-              <div class="label">出发日期</div>
-              <div class="required">*</div>
-            </div>
-          </div>
-          <div class="content">请选择出发日期</div>
-        </div>
-        <div class="view">
-          <div class="ICON" />
-        </div>
-      </div>
-
-      <div class="view-2">
-        <div class="text">
-          <div class="label">成人数量</div>
-          <div class="required-2">*</div>
-        </div>
-        <div class="view-3">
-          <Remove class="icon-instance-node" />
-          <div class="text-wrapper-2">0</div>
-          <Add class="icon-instance-node" />
-        </div>
-      </div>
-
-      <div class="view-2">
-        <div class="text">
-          <div class="label">儿童数量</div>
-          <div class="required-2">*</div>
-        </div>
-        <div class="view-3">
-          <!-- <Remove class="icon-instance-node" /> -->
-          <div class="text-wrapper-2">0</div>
-          <!-- <Add class="icon-instance-node" /> -->
-        </div>
-      </div>
-
-      <div class="input-2">
-        <div class="div">
-          <div class="item-label">
-            <div class="text">
-              <div class="label">联系人</div>
-              <div class="required-2">*</div>
-            </div>
-          </div>
-          <div class="content-2">请输入联系人</div>
-        </div>
-        <div class="view">
-          <div class="ICON" />
-        </div>
-      </div>
-
-      <div class="input-2">
-        <div class="div">
-          <div class="item-label">
-            <div class="text">
-              <div class="label">联系电话</div>
-              <div class="required-2">*</div>
-            </div>
-          </div>
-          <div class="content-2">请输入联系电话</div>
-        </div>
-        <div class="view">
-          <div class="ICON" />
-        </div>
-      </div>
-
-      <div class="input-2">
-        <div class="div">
-          <div class="item-label">
-            <div class="text">
-              <div class="label">微信号</div>
-              <div class="required-2">*</div>
-            </div>
-          </div>
-          <div class="content-2">请输入微信号</div>
-        </div>
-        <div class="view">
-          <div class="ICON" />
-        </div>
-      </div>
-
-      <div class="input-2">
-        <div class="div">
-          <div class="item-label">
-            <div class="text">
-              <div class="label">备用电话</div>
-              <div class="required">*</div>
-            </div>
-          </div>
-          <div class="content-2">请输入备用联系电话</div>
-        </div>
-        <div class="view">
-          <div class="ICON" />
-        </div>
-      </div>
-    </div>
-
-    <div class="view-4">
-      <div class="frame-2">
-        <div class="group">
-          <div class="text-wrapper-3">4500</div>
-          <div class="text-wrapper-4">.00</div>
-          <div class="text-wrapper-5">¥</div>
-        </div>
-      </div>
-      <div class="div-wrapper">
-        <div class="text-wrapper-6">提交</div>
-      </div>
-    </div>
-
-    <div class="ios-bars-home">
-      <div class="rectangle" />
-    </div>
-  </div>
-</template>
-
-<script></script>
-
-<style>
-.screen {
-  align-items: center;
-  background-color: #ffffff;
-  display: flex;
-  flex-direction: column;
-  gap: 8px;
-  position: relative;
-}
-
-.screen .frame {
-  align-items: flex-start;
-  align-self: stretch;
-  display: flex;
-  flex: 0 0 auto;
-  flex-direction: column;
-  position: relative;
-  width: 100%;
-}
-
-.screen .header {
-  align-self: stretch;
-  background-color: #ffffff;
-  border-radius: 16px 16px 0px 0px;
-  height: 48px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .close-instance {
-  height: 24px !important;
-  left: 12px !important;
-  position: absolute !important;
-  top: 12px !important;
-  width: 24px !important;
-}
-
-.screen .text-wrapper {
-  color: #333333;
-  font-family: 'PingFang SC-Semibold', Helvetica;
-  font-size: 16px;
-  font-weight: 400;
-  height: 24px;
-  left: 156px;
-  letter-spacing: 0;
-  line-height: 24px;
-  position: absolute;
-  top: 11px;
-  white-space: nowrap;
-}
-
-.screen .input {
-  align-items: center;
-  align-self: stretch;
-  background-color: var(--gray-white);
-  display: flex;
-  flex: 0 0 auto;
-  gap: 12px;
-  padding: 0px 0px 0px 12px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .div {
-  align-items: flex-start;
-  display: flex;
-  flex: 1;
-  flex-grow: 1;
-  gap: 16px;
-  height: 56px;
-  padding: 16px 16px 16px 0px;
-  position: relative;
-}
-
-.screen .item-label {
-  align-items: center;
-  display: flex;
-  gap: 4px;
-  position: relative;
-  width: 81px;
-}
-
-.screen .text {
-  align-items: flex-start;
-  display: flex;
-  flex: 1;
-  flex-grow: 1;
-  gap: 4px;
-  position: relative;
-}
-
-.screen .label {
-  color: var(--texticonfont-gy1-100);
-  font-family: var(--body-large-font-family);
-  font-size: var(--body-large-font-size);
-  font-style: var(--body-large-font-style);
-  font-weight: var(--body-large-font-weight);
-  letter-spacing: var(--body-large-letter-spacing);
-  line-height: var(--body-large-line-height);
-  margin-top: -1px;
-  position: relative;
-  white-space: nowrap;
-  width: fit-content;
-}
-
-.screen .required {
-  color: var(--error-error6-normal);
-  font-family: var(--body-large-font-family);
-  font-size: var(--body-large-font-size);
-  font-style: var(--body-large-font-style);
-  font-weight: var(--body-large-font-weight);
-  letter-spacing: var(--body-large-letter-spacing);
-  line-height: var(--body-large-line-height);
-  margin-top: -1px;
-  opacity: 0;
-  position: relative;
-  white-space: nowrap;
-  width: fit-content;
-}
-
-.screen .content {
-  color: #999999;
-  flex: 1;
-  font-family: var(--body-large-font-family);
-  font-size: var(--body-large-font-size);
-  font-style: var(--body-large-font-style);
-  font-weight: var(--body-large-font-weight);
-  letter-spacing: var(--body-large-letter-spacing);
-  line-height: var(--body-large-line-height);
-  margin-top: -0.5px;
-  position: relative;
-}
-
-.screen .view {
-  align-items: center;
-  display: inline-flex;
-  flex: 0 0 auto;
-  gap: 4px;
-  justify-content: flex-end;
-  padding: 12px;
-  position: relative;
-}
-
-.screen .ICON {
-  background-image: url(./chevron-right.svg);
-  background-size: 100% 100%;
-  height: 24px;
-  position: relative;
-  width: 24px;
-}
-
-.screen .view-2 {
-  align-items: center;
-  align-self: stretch;
-  background-color: var(--white);
-  display: flex;
-  flex: 0 0 auto;
-  justify-content: space-between;
-  padding: 12px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .required-2 {
-  color: var(--error-error6-normal);
-  font-family: var(--body-large-font-family);
-  font-size: var(--body-large-font-size);
-  font-style: var(--body-large-font-style);
-  font-weight: var(--body-large-font-weight);
-  letter-spacing: var(--body-large-letter-spacing);
-  line-height: var(--body-large-line-height);
-  margin-top: -1px;
-  position: relative;
-  white-space: nowrap;
-  width: fit-content;
-}
-
-.screen .view-3 {
-  align-items: center;
-  display: inline-flex;
-  flex: 0 0 auto;
-  gap: 16px;
-  height: 24px;
-  justify-content: flex-end;
-  position: relative;
-}
-
-.screen .icon-instance-node {
-  height: 22px !important;
-  position: relative !important;
-  width: 22px !important;
-}
-
-.screen .text-wrapper-2 {
-  color: var(--font-gy1-90);
-  font-family: var(---font-family);
-  font-size: var(---font-size);
-  font-style: var(---font-style);
-  font-weight: var(---font-weight);
-  letter-spacing: var(---letter-spacing);
-  line-height: var(---line-height);
-  margin-top: -1px;
-  position: relative;
-  text-align: center;
-  white-space: nowrap;
-  width: fit-content;
-}
-
-.screen .input-2 {
-  align-items: center;
-  align-self: stretch;
-  background-color: var(--gray-white);
-  display: flex;
-  flex: 0 0 auto;
-  gap: 16px;
-  padding: 0px 0px 0px 12px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .content-2 {
-  color: var(--texticonfont-gy3-40);
-  flex: 1;
-  font-family: var(--body-large-font-family);
-  font-size: var(--body-large-font-size);
-  font-style: var(--body-large-font-style);
-  font-weight: var(--body-large-font-weight);
-  letter-spacing: var(--body-large-letter-spacing);
-  line-height: var(--body-large-line-height);
-  margin-top: -0.5px;
-  position: relative;
-}
-
-.screen .view-4 {
-  align-items: flex-start;
-  align-self: stretch;
-  display: flex;
-  flex: 0 0 auto;
-  gap: 8px;
-  justify-content: center;
-  padding: 0px 12px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .frame-2 {
-  height: 40px;
-  position: relative;
-  width: 125px;
-}
-
-.screen .group {
-  height: 22px;
-  position: relative;
-  top: 14px;
-  width: 82px;
-}
-
-.screen .text-wrapper-3 {
-  color: #ff0000;
-  font-family: 'DIN-Medium', Helvetica;
-  font-size: 22px;
-  font-weight: 500;
-  left: 10px;
-  letter-spacing: 0;
-  line-height: 22px;
-  position: absolute;
-  text-align: center;
-  top: 0;
-  white-space: nowrap;
-}
-
-.screen .text-wrapper-4 {
-  color: #ff0000;
-  font-family: 'DIN-Medium', Helvetica;
-  font-size: 14px;
-  font-weight: 500;
-  left: 57px;
-  letter-spacing: 0;
-  line-height: 14px;
-  position: absolute;
-  text-align: center;
-  top: 7px;
-  white-space: nowrap;
-}
-
-.screen .text-wrapper-5 {
-  color: #ff0000;
-  font-family: 'DIN-Medium', Helvetica;
-  font-size: 10px;
-  font-weight: 500;
-  left: 0;
-  letter-spacing: 0;
-  line-height: 10px;
-  position: absolute;
-  text-align: center;
-  top: 11px;
-  white-space: nowrap;
-}
-
-.screen .div-wrapper {
-  align-items: center;
-  background-color: var(--brand-brand7-normal);
-  border-radius: 6px;
-  display: flex;
-  flex: 1;
-  flex-grow: 1;
-  gap: 4px;
-  justify-content: center;
-  overflow: hidden;
-  padding: 8px 16px;
-  position: relative;
-}
-
-.screen .text-wrapper-6 {
-  color: var(--texticonfont-wh1-100);
-  font-family: var(--mark-large-font-family);
-  font-size: var(--mark-large-font-size);
-  font-style: var(--mark-large-font-style);
-  font-weight: var(--mark-large-font-weight);
-  letter-spacing: var(--mark-large-letter-spacing);
-  line-height: var(--mark-large-line-height);
-  margin-top: -1px;
-  position: relative;
-  text-align: center;
-  white-space: nowrap;
-  width: fit-content;
-}
-
-.screen .ios-bars-home {
-  align-self: stretch;
-  background-color: #ffffff;
-  height: 34px;
-  position: relative;
-  width: 100%;
-}
-
-.screen .rectangle {
-  background-color: #000000;
-  border-radius: 100px;
-  height: 7px;
-  left: 120px;
-  position: relative;
-  top: 19px;
-  width: 136px;
-}
-</style>

+ 7 - 17
src/pages/topic/index.vue

@@ -141,22 +141,12 @@
                   </span>
                 </div>
 
-                <div class="text-black-9 shrink-0 text-sm flex justify-start items-center">
-                  <img
-                    v-if="itemData?.isLike"
-                    @click.prevent="doSta(itemData)"
-                    class="w-16 h-16 mr-4"
-                    src="~/assets/img/profile-others/Like2.svg"
-                    alt=""
-                  />
-                  <img
-                    v-else
-                    @click.prevent="doStar(itemData)"
-                    class="w-16 h-16 mr-4"
-                    src="~/assets/img/profile-others/Like.svg"
-                    alt=""
-                  />
-                  <span>{{ transferCount(itemData?.likeCount) }}</span>
+                <div class="text-black-9 shrink-0 text-base flex justify-start items-center">
+                  <span
+                    class="iconfont icon-Thumbs-up text-black-9 mr-4"
+                    style="font-size: 16px"
+                  ></span>
+                  {{ transferCount(itemData?.likeCount) }}
                 </div>
               </div>
             </div>
@@ -188,7 +178,7 @@ const dataList = ref([])
 const loading = ref(true)
 const finished = ref(false)
 
-const topicName = computed(() => route.query.topicName ?? '2025年')
+const topicName = computed(() => route.query.topicName)
 
 // 搜索页面的请求
 const recordList = ref([])

+ 10 - 67
src/pages/travel-notes/index.vue

@@ -148,62 +148,6 @@
         >
           <div class="w-full box-border flex justify-between flex-wrap">
             <template v-for="itemData in dataList">
-              <!-- <NuxtLink
-              class="group flex relative cursor-pointer bg-white pb-10 mt-20"
-              :to="`/yj/${itemData.id}`"
-            >
-              <div class="aspect-[120/80] h-80 shrink-0 rounded overflow-hidden bg-[#ddd]">
-                <img
-                  v-if="Array.isArray(itemData?.tourismUrlsAfterConvert)"
-                  :src="itemData?.tourismUrlsAfterConvert[0]"
-                  class="w-full h-full rounded object-cover"
-                  alt=""
-                  srcset=""
-                />
-              </div>
-              <div
-                class="h-80 pl-[8px] flex flex-col text-[#FD9A00] justify-between w-[calc(100%-120px)]"
-              >
-                <div class="truncate w-full text-[14px] font-bold">
-                  <img
-                    v-if="itemData.isOriginal == 1"
-                    src="~/assets/img/yuanchuang.png"
-                    class="mt-3 w-[30px] h-[16px]"
-                    alt=""
-                    style="float: left"
-                  />
-                  {{ itemData.projectTitle }}
-                </div>
-                <div class="w-full overflow-x-auto scrollbar" v-if="itemData.noteLabel">
-                  <div class="flex flex-nowrap">
-                    <div
-                      v-for="tag in convertTag(itemData.noteLabel)"
-                      class="rounded-full text-[#666] border-[#666] text-[10px] pr-6 pl-6 float-left mr-10 shrink-0"
-                      style="border: 0.5px solid #666666"
-                    >
-                      {{ tag }}
-                    </div>
-                  </div>
-                </div>
-                <div class="flex justify-end items-center text-[12px] text-[#999]">
-                  <div class="flex items-center mr-10">
-                    <van-icon name="eye-o" class="mr-5" />
-                    {{ transferCount(itemData.pageViewCount) }}
-                  </div>
-                  <div class="flex items-center mr-10">
-                    <van-icon name="good-job-o" class="mr-5" />
-                    {{ transferCount(itemData.likeCount) }}
-                  </div>
-                </div>
-              </div>
-              <div class="w-full h-10 absolute top-[100%] left-0 flex items-center justify-between">
-                <div
-                  v-for="item in 40"
-                  class="w-[3%] h-[1px] border border-[#ddd]"
-                  style="transform: scale(0.5)"
-                ></div>
-              </div>
-            </NuxtLink> -->
               <NuxtLink
                 class="w-[50%] relative cursor-pointer bg-white pb-10"
                 :to="`/yj/${itemData.id}`"
@@ -249,13 +193,13 @@
                       <span class="ml-4 text-black-9 text-sm">{{ itemData?.createName }}</span>
                     </div>
 
-                    <div class="text-black-9 text-sm flex justify-start items-center">
-                      <img
-                        class="w-16 h-16 mr-4"
-                        src="~/assets/img/profile-others/Like.svg"
-                        alt=""
-                      />
-                      <span>{{ transferCount(itemData?.likeCount) }}</span>
+                    <div class="text-black-9 text-base flex justify-start items-center">
+                      <span
+                        class="iconfont icon-Thumbs-up text-black-9"
+                        style="font-size: 16px"
+                      ></span>
+
+                      <span class="ml-4">{{ transferCount(itemData?.likeCount) }}</span>
                     </div>
                   </div>
                 </div>
@@ -384,11 +328,10 @@ const finished = ref(false)
 const travelWriteType = ref(0)
 const writeTypeList = ref([
   { text: '全部', value: 0 },
-  { text: '原创', value: 1 }
+  { text: '原创', value: 1 },
+  { text: '非原创', value: 2 }
 ])
-const writeTypeText = computed(() =>
-  writeTypeList.value[travelWriteType.value].value ? '原创' : '是否原创'
-)
+const writeTypeText = computed(() => writeTypeList.value[travelWriteType.value].text)
 watch(travelWriteType, () => {
   pageNum.value = 1
   dataList.value = []

+ 1 - 1
src/pages/view-group-chat/[id].vue

@@ -83,7 +83,7 @@ const saveLoading = ref(false)
 
 // 加入群聊
 const handleJoinGroup = (item) => {
-  if (!item.status) {
+  if (item.status == 0) {
     getGroupAdd(item.id)
   }
   if (item.status == 1) {

+ 105 - 84
src/pages/yj/[id].vue

@@ -75,8 +75,8 @@
         <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-black-3 leading-[28px] font-bold">
-            <span v-if="detailData.isOrigin == 1" class="text-[#FD9A00]">【原创】</span>
-            {{ detailData.projectTitle }}
+            <span v-if="detailData?.isOrigin == 1" class="text-[#FD9A00]">【原创】</span>
+            {{ detailData?.projectTitle }}
           </div>
         </div>
 
@@ -87,26 +87,41 @@
           <template v-if="con.type !== 'image'">
             <div class="w-full" style="word-wrap: break-word" v-html="con.content"></div>
           </template>
-        </div> -->
+        </div>     @click="bindFn"-->
         <div
           id="view-note"
+          ref="editor"
           class="mt-10 w-full"
           style="word-wrap: break-word"
-          @click="bindFn"
           v-html="detailData?.tourTourismProjectTravelNotesWriteContent?.content"
         ></div>
 
         <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>
+          <span v-if="detailData?.departureTime" class="mr-8">
+            出发时间{{ contentIsEmpty(detailData?.departureTime) }}
+          </span>
+          <span v-if="detailData?.travelMode" class="mr-8">
+            出行方式{{ contentIsEmpty(detailData?.travelMode) }}
+          </span>
+          <span v-if="detailData?.countTimes" class="mr-8">
+            出发天数{{ contentIsEmpty(detailData?.countTimes) }}
+          </span>
+          <span v-if="detailData?.travelNumber" class="mr-8">
+            游玩人数{{ contentIsEmpty(detailData?.travelNumber) }}
+          </span>
+          <span v-if="detailData?.role" class="mr-8">
+            人物关系{{ contentIsEmpty(detailData?.role) }}
+          </span>
+          <span v-if="detailData?.averageCost" class="mr-8">
+            人均费用{{ contentIsEmpty(detailData?.averageCost) }}
+          </span>
+          <span v-if="detailData?.recommendationRate" class="mr-8">
+            推荐指数{{ contentIsEmpty(detailData?.recommendationRate) }}
+          </span>
         </div>
 
         <van-cell
+          v-if="detailData?.tourImGroup"
           style="--van-cell-background: #f5f5f5"
           center
           is-link
@@ -241,17 +256,17 @@
                   <span class="text-sm">
                     <span
                       @click.stop="handleCommentCollect(item)"
-                      :class="`iconfont ${item.isCollect ? 'icon-star-fill text-[#FF9300] ' : 'icon-star text-black-3'}   mr-4`"
+                      :class="`iconfont ${item?.isCollect ? 'icon-star-fill text-[#FF9300] ' : 'icon-star text-black-3'}   mr-4`"
                       style="font-size: 13px"
                     ></span>
+                    <span class="mr-10">{{ item?.collectNum }}</span>
 
-                    <span class="mr-10">{{ item.collectNum }}</span>
                     <span
-                      @click.stop="doCommenteStar"
-                      class="iconfont icon-Thumbs-up text-black-3 mr-4"
+                      @click.stop="doCommenteStar(item)"
+                      :class="`iconfont ${item?.isLike ? ' icon-like-fill text-[#FF476A]' : 'icon-Thumbs-up text-black-3'}  mr-4`"
                       style="font-size: 13px"
                     ></span>
-                    <span class="mr-10">{{ item.likeNum }}</span>
+                    <span class="mr-10">{{ item?.likeNum }}</span>
                   </span>
                 </div>
               </div>
@@ -324,14 +339,14 @@
                       <span class="text-sm">
                         <span
                           @click.stop="handleCommentCollect(subItem)"
-                          class="iconfont icon-star text-black-3 mr-4"
+                          :class="`iconfont ${subItem?.isCollect ? 'icon-star-fill text-[#FF9300] ' : 'icon-star text-black-3'}   mr-4`"
                           style="font-size: 13px"
                         ></span>
                         <span class="mr-10">{{ subItem.collectNum }}</span>
-                        <!-- icon-like-fill  doCommenteStar -->
+
                         <span
-                          @click.stop="showLike = !showLike"
-                          :class="`iconfont ${showLike ? ' icon-like-fill text-[#FF476A]' : 'icon-Thumbs-up text-black-3'}  mr-4`"
+                          @click.stop="doCommenteStar(subItem)"
+                          :class="`iconfont ${subItem.isLike ? ' icon-like-fill text-[#FF476A]' : 'icon-Thumbs-up text-black-3'}  mr-4`"
                           style="font-size: 13px"
                         ></span>
                         <span class="mr-10">{{ subItem.likeNum }}</span>
@@ -398,18 +413,18 @@
             is-link
             @click="
               navigateTo({
-                path: `/profile-others/${detailData.groupOwnerId}`
+                path: `/profile-others/${detailData?.groupOwnerId}`
               })
             "
           >
             <template #title>
               <h1 class="text-sm text-black-3 line-clamp-1">
-                {{ detailData.groupOwnerName }}
+                {{ detailData?.groupOwnerName }}
               </h1>
             </template>
             <template #icon>
               <div class="w-24 h-24 rounded-full overflow-hidden mr-8">
-                <img class="w-full h-full objct-cover" :src="detailData.groupOwnerImage" alt="" />
+                <img class="w-full h-full objct-cover" :src="detailData?.groupOwnerImage" alt="" />
               </div>
             </template>
             <template #value>
@@ -515,7 +530,7 @@
             <div class="flex items-center mr-10" @click.stop="handleCollect">
               <van-icon v-if="isCollect" size="24" color="#FD9A00" name="star" class="mr-5" />
               <van-icon v-else name="star-o" size="24" color="#333333" class="mr-5" />
-              {{ formatNumberLetter(detailData.likeCount) }}
+              {{ formatNumberLetter(detailData.collectCount) }}
             </div>
             <div class="flex items-center" @click.stop="">
               <span
@@ -558,6 +573,9 @@ const { data: detailData, status } = useMyFetch(
     }
   }
 )
+// // 计算数量
+// const collectCount = computed(() => detailData.value.collectCount)
+// const collectCount = ref(0)
 
 // 热门游记列表
 const { data: dataList } = await useMyFetch(
@@ -574,6 +592,14 @@ async function isCollectTravelNotes() {
   isCollect.value = data
 }
 
+// 查询游记收藏的数量
+async function getCollectCount() {
+  const { data } = await request(
+    `/website/tourism/projectTravelNotes/getCollectCount?id=${id.value}`
+  )
+  detailData.value.collectCount = data
+}
+
 // 收藏/取消收藏
 async function handleCollect() {
   if (!token.value) {
@@ -588,6 +614,7 @@ async function handleCollect() {
     return
   }
   const type = isCollect.value ? 0 : 1
+
   showLoadingToast({
     forbidClick: true,
     duration: 0
@@ -596,6 +623,7 @@ async function handleCollect() {
     method: 'post',
     body: { type, travelNotesId: id.value }
   }).finally(() => closeToast())
+  getCollectCount()
   isCollectTravelNotes()
   showToast(type == 1 ? '收藏成功' : '已取消收藏')
 }
@@ -640,35 +668,24 @@ async function handleCommentCollect(parmas) {
     return
   }
   const type = parmas.isCollect ? 0 : 1
+
+  let url = parmas.isCollect
+    ? '/website/comment/tourTravelNotesComment/commentCollectCancle'
+    : '/website/comment/tourTravelNotesComment/commentCollect'
+  let body = parmas.isCollect ? parmas.id : { commentId: parmas.id }
   showLoadingToast({
     forbidClick: true,
     duration: 0
   })
-  await request(`/website/comment/tourTravelNotesComment/commentCollect`, {
+
+  await request(url, {
     method: 'post',
-    body: { commentId: parmas.id }
+    body
   }).finally(() => closeToast())
   getComments()
   showToast(type == 1 ? '收藏成功' : '已取消收藏')
 }
 
-// 评论点赞
-const showLike = ref(false)
-const isCommentStarLoading = ref(true)
-async function doCommenteStar() {
-  if (!isCommentStarLoading.value) return
-  isCommentStarLoading.value = false
-  request(`/website/tourism/projectTravelNotes/userLikeTravelNotesUpdate`, {
-    method: 'post',
-    body: { travelNotesId: id.value }
-  })
-    .then(() => {
-      detailData.value.isLike = true
-      getStars()
-    })
-    .finally(() => (isCommentStarLoading.value = true))
-}
-
 // 获取用户信息
 const userInfo = ref({})
 async function getUserInfo() {
@@ -773,6 +790,22 @@ async function getComments() {
   }
 }
 
+const isCommentStarLoading = ref(true)
+async function doCommenteStar(params) {
+  if (!isCommentStarLoading.value) return
+  isCommentStarLoading.value = false
+  let url = params.isLike
+    ? '/website/comment/tourTravelNotesComment/commentLikeCancle'
+    : '/website/comment/tourTravelNotesComment/commentLike'
+  const type = params.isLike ? 0 : 1
+  await request(url, {
+    method: 'post',
+    body: params.id
+  }).finally(() => (isCommentStarLoading.value = true))
+  getComments()
+  showToast(type == 1 ? '点赞成功' : '已取消点赞')
+}
+
 // 转换评论中的一些非字符emoji
 function coveredContent(val) {
   if (!val) return ''
@@ -947,58 +980,50 @@ function openShowInput() {
 function goBack() {
   router.back()
 }
+
+const editor = ref(null)
 // 给预览的地方绑定点击事件
-const bindFn = async () => {
+const bindFn = () => {
   // 获取文档中的所有 span 标签
-  await nextTick(() => {
+  nextTick(() => {
     const container = document.getElementById('view-note')
     const spans = container?.querySelectorAll('span')
-    console.log(spans, 'spans')
-
     spans?.forEach((span) => {
-      console.log(
-        span.getAttribute('data-denotation-char'),
-        "span.getAttribute('data-denotation-char')"
-      )
-      // console.log('@用户ID', span.getAttribute('data-id'))
       if (span.getAttribute('data-denotation-char') === '@') {
-        navigateTo({
-          path: `/profile-others/${span.getAttribute('data-id')}`
+        span.addEventListener('click', (event) => {
+          // console.log('@用户ID', span.getAttribute('data-id'))
+          // console.log('@用户名字', span.innerHTML)
+          navigateTo({
+            path: `/profile-others/${span.getAttribute('data-id')}`
+          })
         })
-        // span.addEventListener('click', (event) => {
-        //   console.log('@用户ID', span.getAttribute('data-id'))
-        //   // console.log('@用户名字', span.innerHTML)
-        //   // alert('@用户:' + span.innerText)
-        //   navigateTo({
-        //     path: `/profile-others/${span.getAttribute('data-id')}`
-        //   })
-        // })
       }
       if (span.getAttribute('data-denotation-char') === '#') {
-        let topicName = span.innerText.replace('#', '')
-        navigateTo({
-          path: '/topic',
-          query: {
-            topicName
-          }
+        span.addEventListener('click', (event) => {
+          // console.log('话题ID', span.getAttribute('data-id'))
+          // console.log('话题内容', span.innerText)
+          let topicName = span.innerText.replace('#', '')
+          topicName = topicName.trim()
+          navigateTo({
+            path: `/topic`,
+            query: {
+              topicName
+            }
+          })
         })
-        // span.addEventListener('click', (event) => {
-        //   console.log('话题ID', span.getAttribute('data-id'))
-        //   console.log('话题内容', span.innerText)
-        //   let topicName = span.innerText.replace('#', '')
-
-        //   navigateTo({
-        //     path: '/topic',
-        //     query: {
-        //       topicName
-        //     }
-        //   })
-        // })
       }
     })
   })
 }
 
+watch(
+  editor,
+  (val) => {
+    if (val) bindFn()
+  },
+  { immediate: true }
+)
+
 useSeoMeta({
   title: '游记详情',
   ogTitle: detailData?.projectTitle || '精美热门游记',
@@ -1007,10 +1032,6 @@ useSeoMeta({
   ogImage: ''
 })
 onMounted(() => {
-  // useEventListener('click', openShowInput, { target: document })
-  // useEventListener('mousedown', openShowInput, { target: document })
-  // useEventListener('touchstart', openShowInput, { target: document })
-
   getComments()
   getUserInfo()
   isCollectTravelNotes()