Forráskód Böngészése

Merge remote-tracking branch 'origin/write_travel_notes-revision' into dev

# Conflicts:
#	src/pages/note-create/index.client.vue
suwenjiang 4 hete
szülő
commit
712b986101
58 módosított fájl, 5737 hozzáadás és 2274 törlés
  1. 7 2
      .env.development
  2. 3 0
      package.json
  3. 166 126
      pnpm-lock.yaml
  4. 287 0
      single-add.vue
  5. 939 0
      src/assets/css/quill.snow.css
  6. 502 262
      src/assets/iconfont/demo_index.html
  7. 147 83
      src/assets/iconfont/iconfont.css
  8. 0 0
      src/assets/iconfont/iconfont.js
  9. 311 199
      src/assets/iconfont/iconfont.json
  10. 12 13
      src/assets/iconfont/iconfont.svg
  11. BIN
      src/assets/iconfont/iconfont.ttf
  12. BIN
      src/assets/iconfont/iconfont.woff
  13. BIN
      src/assets/iconfont/iconfont.woff2
  14. 5 0
      src/assets/img/note-create/check.svg
  15. 6 0
      src/assets/img/note-create/expand-text-input.svg
  16. 8 0
      src/assets/img/note-create/location.svg
  17. 6 0
      src/assets/img/note-create/orange-expand-text-input.svg
  18. 9 0
      src/assets/img/profile-others/Female.svg
  19. 5 0
      src/assets/img/profile-others/Like.svg
  20. 5 0
      src/assets/img/profile-others/Like2.svg
  21. BIN
      src/assets/img/topic/topic.png
  22. BIN
      src/assets/img/topic/yj.png
  23. 299 142
      src/components/CreateNote/Form.vue
  24. 148 0
      src/components/CreateNote/HeaderImage.vue
  25. 122 0
      src/components/CreateNote/Mention.vue
  26. 13 3
      src/components/CreateNote/PublishResultModal.client.vue
  27. 7 10
      src/components/Home/TravelNotes/Item.vue
  28. 11 18
      src/components/Home/TravelNotes/index.client.vue
  29. 1 1
      src/components/NavigationBar/LeftMenu.vue
  30. 56 0
      src/components/Profile/Collection/Comment.vue
  31. 47 0
      src/components/Profile/Collection/Topic.vue
  32. 19 21
      src/components/Profile/Collection/TravelNoteCell.vue
  33. 1 0
      src/components/Profile/InteractionMessage/ReceiveComment.vue
  34. 1 1
      src/components/Profile/Notes/Auditing/Item.vue
  35. 2 2
      src/components/Profile/Notes/Draft/Item.vue
  36. 4 2
      src/components/Profile/Notes/Draft/index.vue
  37. 32 15
      src/components/Profile/Notes/Published/Item.vue
  38. 41 12
      src/components/Profile/Notes/Published/index.vue
  39. 1 1
      src/components/Profile/Notes/Rejected/Item.vue
  40. 13 16
      src/components/Profile/Notes/Tabs.vue
  41. 0 2
      src/pages/chat/group-chat.vue
  42. 0 2
      src/pages/chat/single-chat.vue
  43. 389 468
      src/pages/note-create/index.client.vue
  44. 318 0
      src/pages/profile-others/[id].vue
  45. 177 33
      src/pages/profile/collection.client.vue
  46. 1 1
      src/pages/profile/index.vue
  47. 1 0
      src/pages/profile/interaction-message/index.vue
  48. 1 0
      src/pages/profile/my-comment.vue
  49. 3 5
      src/pages/profile/notes/index.vue
  50. 1 2
      src/pages/scan/index.vue
  51. 0 110
      src/pages/test/_index.vue
  52. 0 145
      src/pages/test/index.vue
  53. 0 184
      src/pages/test/useRecording.js
  54. 328 0
      src/pages/topic/index.vue
  55. 365 128
      src/pages/travel-notes/index.vue
  56. 184 0
      src/pages/view-group-chat/[id].vue
  57. 637 211
      src/pages/yj/[id].vue
  58. 96 54
      src/utils/index.js

+ 7 - 2
.env.development

@@ -6,6 +6,10 @@ VITE_APP_ENV=development
 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
+
 
 
 
@@ -30,9 +34,10 @@ VITE_APP_IM_URL=ws://192.168.1.44:8082/system/message
 # 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_BASE_URL=http://4eqxwr.natappfree.cc
-# VITE_APP_IM_URL=ws://4eqxwr.natappfree.cc/system/message
+# VITE_APP_BASE_URL=http://5nfhmg.natappfree.cc
+# VITE_APP_IM_URL=ws://5nfhmg.natappfree.cc/system/message
 
 
 # VITE_APP_BASE_URL=http://192.168.1.204:8082

+ 3 - 0
package.json

@@ -30,6 +30,8 @@
     "nuxt-swiper": "^2.0.0",
     "pinia": "^2.2.2",
     "pinyin-pro": "^3.26.0",
+    "quill": "^2.0.3",
+    "quill-mention": "^6.0.2",
     "reconnecting-websocket": "^4.4.0",
     "recorder-core": "^1.3.25011100",
     "vconsole": "^3.15.1",
@@ -37,6 +39,7 @@
     "vue-clipboard3": "^2.0.0",
     "vue-cropper": "^1.1.4",
     "vue-draggable-plus": "^0.6.0",
+    "vue-mention": "^1.1.0",
     "vue-router": "latest",
     "vue3-seamless-scroll": "^2.0.1"
   },

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 166 - 126
pnpm-lock.yaml


+ 287 - 0
single-add.vue

@@ -0,0 +1,287 @@
+<template>
+  <div class="w-full h-[100vh]">
+    <ChatHeaderBar title="选择互关好友" />
+
+    <ChatSearch v-model:searchString="showName" @search="search" placeholder="请输入关键词" />
+
+    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+      <ChatEmpty
+        image="search"
+        v-if="!addDataList?.length && !loading"
+        title="暂无数据"
+        top="100"
+      />
+
+      <van-list
+        v-else-if="addDataList.length"
+        v-model:loading="loading"
+        error-text="获取失败"
+        finished-text="-- 没有更多了 --"
+        :finished="finished"
+        :immediate-check="false"
+      >
+        <!--    @load="getLoadList"  -->
+        <div style="height: calc(100vh - 170px)">
+          <van-checkbox-group v-model="checked">
+            <!-- <van-index-bar highlight-color="#FD9A00" index-list :sticky="false"> -->
+            <template v-for="(item, index) in addDataList" :key="item?.attentionIdDictMap?.userId">
+              <!-- <van-index-anchor index="A" /> -->
+              <van-cell center clickable @click="toggle(item)">
+                <template #icon>
+                  <div class="flex justify-start">
+                    <van-checkbox
+                      checked-color="#FD9A00"
+                      :name="item?.attentionIdDictMap?.userId"
+                      :ref="(el) => (checkboxRefs[item?.attentionIdDictMap?.userId] = el)"
+                      @click.stop="toggle(item)"
+                    />
+
+                    <div class="w-40 h-40 ml-13 mr-12 rounded-full overflow-hidden">
+                      <img
+                        v-if="item?.attentionIdDictMap?.headImageUrl"
+                        class="w-full h-full shrink-0 object-cover"
+                        :src="item?.attentionIdDictMap?.headImageUrl"
+                        alt=""
+                      />
+
+                      <img
+                        class="w-full h-full shrink-0 object-cover"
+                        src="~/assets/img/default_avatar.png"
+                        alt=""
+                      />
+                    </div>
+                  </div>
+                </template>
+                <template #title>
+                  <div class="flex items-center">
+                    <h1 class="text-xl text-black-3">
+                      {{ item?.attentionIdDictMap?.showName }}
+                    </h1>
+                    <van-tag
+                      v-if="item.fansStatus == 2"
+                      style="margin-left: 5px; padding: 3px 6px"
+                      color="#F7F8FA"
+                      text-color="#666666"
+                    >
+                      相互关注
+                    </van-tag>
+                  </div>
+                </template>
+              </van-cell>
+            </template>
+            <!-- </van-index-bar> -->
+          </van-checkbox-group>
+        </div>
+      </van-list>
+    </van-pull-refresh>
+    <div
+      class="w-full box-border p-16 pb-40 bg-white fixed bottom-0 left-0 flex justify-between items-center shadow-[0px_-4px_4px_0px_rgba(0,0,0,0.1)]"
+    >
+      <div class="shrink-0 flex justify-start items-center">
+        <div class="w-118 shrink-0 flex justify-start items-center overflow-hidden">
+          <div
+            v-for="(item, index) in checkedList.slice(0, 5)"
+            :key="index + 'avatar'"
+            :class="`w-36 h-36  ${index == 0 ? '' : '-ml-16'} shrink-0 rounded-full overflow-hidden`"
+          >
+            <img
+              v-if="item?.attentionIdDictMap?.headImageUrl"
+              class="w-full h-full object-cover"
+              :src="item?.attentionIdDictMap?.headImageUrl"
+              alt=""
+            />
+            <img
+              v-else
+              class="w-full h-full shrink-0 object-cover"
+              src="~/assets/img/default_avatar.png"
+              alt=""
+            />
+          </div>
+        </div>
+
+        <div v-if="checkedList.length > 5" class="shrink-0 w-24 h-24 ml-8">
+          <img class="w-full h-full object-cover" src="~/assets/img/chat/ellipsis.svg" alt="" />
+        </div>
+      </div>
+      <van-button
+        :loading="isLoading"
+        :disabled="checkedList.length > 0 ? false : true"
+        @click="handleCreateGroup"
+        style="width: 160px"
+        class="shrink-0"
+        block
+        size="large"
+        color="#FD9A00"
+        round
+      >
+        新建
+        <span v-if="checkedList.length">({{ checkedList.length }})</span>
+      </van-button>
+    </div>
+  </div>
+</template>
+<script setup>
+const route = useRoute()
+const router = useRouter()
+
+definePageMeta({
+  layout: false
+})
+
+onMounted(() => {
+  getList()
+})
+// 对方的那个id
+const toUserId = computed(() => route.query?.toUserId ?? '')
+const refreshing = ref(false)
+const loading = ref(false)
+const finished = ref(false)
+
+const checked = ref([])
+const checkedList = ref([])
+const showName = ref('')
+const checkboxRefs = ref([])
+
+// 字母的数组
+const letterList = ref([])
+
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  flagPage: 1
+})
+
+const addDataList = ref([])
+const filterDataList = ref([])
+
+const searchText = computed(() => (showName.value ? '暂无互关好友' : '暂无搜索结果'))
+
+// 选中要邀请的人
+const toggle = (item) => {
+  let index = checkedList.value.findIndex(
+    (el) => el?.attentionIdDictMap?.userId == item?.attentionIdDictMap?.userId
+  )
+
+  if (index != -1) {
+    checkedList.value.splice(index, 1)
+  } else {
+    checkedList.value.push(item)
+  }
+
+  checkboxRefs.value[item?.attentionIdDictMap?.userId].toggle()
+}
+
+const search = () => {
+  finished.value = true
+  if (showName.value) {
+    addDataList.value = filterDataList.value.filter((item) =>
+      item.attentionIdDictMap.name.includes(showName.value)
+    )
+  } else {
+    addDataList.value = filterDataList.value
+  }
+}
+
+// 刷新
+const onRefresh = () => {
+  queryParams.pageNum = 1
+  addDataList.value = []
+  filterDataList.value = []
+  getList()
+}
+
+// 获取数据
+const getList = async () => {
+  try {
+    let url = `/website/tourism/fans/getFriends`
+
+    loading.value = true
+    let {
+      data: { dataList, totalCount }
+    } = await request(url, {
+      query: {
+        ...queryParams
+      }
+    })
+
+    if (Array.isArray(dataList) && dataList?.length) {
+      addDataList.value = dataList
+
+      nextTick(() => {
+        checkboxRefs.value[toUserId.value].toggle()
+        let item = dataList.find((el) => el?.attentionIdDictMap?.userId == toUserId.value)
+        if (item) {
+          checkedList.value.push(item)
+        } else {
+          router.back()
+        }
+      })
+    } else {
+      addDataList.value = []
+    }
+
+    loading.value = false
+    refreshing.value = false
+    if (addDataList.value.length >= totalCount) {
+      finished.value = true
+    } else {
+      finished.value = false
+    }
+  } catch (err) {
+  } finally {
+    refreshing.value = false
+    loading.value = false
+  }
+}
+
+// 节流
+const isLoading = ref(false)
+
+function handleKeyDown(event) {
+  // 启动节流
+  // 1000ms 后解除节流
+  // setTimeout(() => {
+  //   isThrottled.value = false
+  // }, 3000)
+}
+
+// 创建多人聊天
+async function handleCreateGroup() {
+  if (!isLoading.value) {
+    isLoading.value = true
+    try {
+      showLoadingToast({
+        message: '准备开始群聊...',
+        duration: 100000
+      })
+
+      let { data } = await request('/website/tourGroup/createGroup', {
+        method: 'post',
+        body: {
+          createType: 2,
+          ids: [...checked.value]
+        }
+      })
+
+      if (data) {
+        navigateTo({
+          path: '/chat/group-chat',
+          query: {
+            groupId: data
+          },
+          replace: true
+        })
+        isLoading.value = false
+      }
+    } catch (error) {
+    } finally {
+      closeToast()
+    }
+  }
+}
+
+useSeoMeta({
+  title: '我的消息'
+})
+</script>
+<style lang="scss" scoped></style>

+ 939 - 0
src/assets/css/quill.snow.css

@@ -0,0 +1,939 @@
+.ql-container {
+    box-sizing: border-box;
+    font-family: Helvetica, Arial, sans-serif;
+    font-size: 13px;
+    height: 100%;
+    margin: 0;
+    position: relative;
+}
+.ql-container.ql-disabled .ql-tooltip {
+    visibility: hidden;
+}
+.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
+    pointer-events: none;
+}
+.ql-clipboard {
+    left: -100000px;
+    height: 1px;
+    overflow-y: hidden;
+    position: absolute;
+    top: 50%;
+    display: none;
+}
+.ql-clipboard p {
+    margin: 0;
+    padding: 0;
+}
+.ql-editor {
+    box-sizing: border-box;
+    line-height: 1.42;
+    height: 100%;
+    outline: none;
+    overflow-y: auto;
+    padding: 12px 15px;
+    tab-size: 4;
+    tab-size: 4;
+    text-align: left;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+.ql-editor > * {
+    cursor: text;
+}
+.ql-editor p,
+.ql-editor ol,
+.ql-editor ul,
+.ql-editor pre,
+.ql-editor blockquote,
+.ql-editor h1,
+.ql-editor h2,
+.ql-editor h3,
+.ql-editor h4,
+.ql-editor h5,
+.ql-editor h6 {
+    margin: 0;
+    padding: 0;
+    counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol,
+.ql-editor ul {
+    padding-left: 1.5em;
+}
+.ql-editor ol > li,
+.ql-editor ul > li {
+    list-style-type: none;
+}
+.ql-editor ul > li::before {
+    content: "\2022";
+}
+.ql-editor ul[data-checked="true"],
+.ql-editor ul[data-checked="false"] {
+    pointer-events: none;
+}
+.ql-editor ul[data-checked="true"] > li *,
+.ql-editor ul[data-checked="false"] > li * {
+    pointer-events: all;
+}
+.ql-editor ul[data-checked="true"] > li::before,
+.ql-editor ul[data-checked="false"] > li::before {
+    color: #777;
+    cursor: pointer;
+    pointer-events: all;
+}
+.ql-editor ul[data-checked="true"] > li::before {
+    content: "\2611";
+}
+.ql-editor ul[data-checked="false"] > li::before {
+    content: "\2610";
+}
+.ql-editor li::before {
+    display: inline-block;
+    white-space: nowrap;
+    width: 1.2em;
+}
+.ql-editor li:not(.ql-direction-rtl)::before {
+    margin-left: -1.5em;
+    margin-right: 0.3em;
+    text-align: right;
+}
+.ql-editor li.ql-direction-rtl::before {
+    margin-left: 0.3em;
+    margin-right: -1.5em;
+}
+.ql-editor ol li:not(.ql-direction-rtl),
+.ql-editor ul li:not(.ql-direction-rtl) {
+    padding-left: 1.5em;
+}
+.ql-editor ol li.ql-direction-rtl,
+.ql-editor ul li.ql-direction-rtl {
+    padding-right: 1.5em;
+}
+.ql-editor ol li {
+    counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+    counter-increment: list-0;
+}
+.ql-editor ol li::before {
+    content: counter(list-0, decimal) ". ";
+}
+.ql-editor ol li.ql-indent-1 {
+    counter-increment: list-1;
+}
+.ql-editor ol li.ql-indent-1::before {
+    content: counter(list-1, lower-alpha) ". ";
+}
+.ql-editor ol li.ql-indent-1 {
+    counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-2 {
+    counter-increment: list-2;
+}
+.ql-editor ol li.ql-indent-2::before {
+    content: counter(list-2, lower-roman) ". ";
+}
+.ql-editor ol li.ql-indent-2 {
+    counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-3 {
+    counter-increment: list-3;
+}
+.ql-editor ol li.ql-indent-3::before {
+    content: counter(list-3, decimal) ". ";
+}
+.ql-editor ol li.ql-indent-3 {
+    counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-4 {
+    counter-increment: list-4;
+}
+.ql-editor ol li.ql-indent-4::before {
+    content: counter(list-4, lower-alpha) ". ";
+}
+.ql-editor ol li.ql-indent-4 {
+    counter-reset: list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-5 {
+    counter-increment: list-5;
+}
+.ql-editor ol li.ql-indent-5::before {
+    content: counter(list-5, lower-roman) ". ";
+}
+.ql-editor ol li.ql-indent-5 {
+    counter-reset: list-6 list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-6 {
+    counter-increment: list-6;
+}
+.ql-editor ol li.ql-indent-6::before {
+    content: counter(list-6, decimal) ". ";
+}
+.ql-editor ol li.ql-indent-6 {
+    counter-reset: list-7 list-8 list-9;
+}
+.ql-editor ol li.ql-indent-7 {
+    counter-increment: list-7;
+}
+.ql-editor ol li.ql-indent-7::before {
+    content: counter(list-7, lower-alpha) ". ";
+}
+.ql-editor ol li.ql-indent-7 {
+    counter-reset: list-8 list-9;
+}
+.ql-editor ol li.ql-indent-8 {
+    counter-increment: list-8;
+}
+.ql-editor ol li.ql-indent-8::before {
+    content: counter(list-8, lower-roman) ". ";
+}
+.ql-editor ol li.ql-indent-8 {
+    counter-reset: list-9;
+}
+.ql-editor ol li.ql-indent-9 {
+    counter-increment: list-9;
+}
+.ql-editor ol li.ql-indent-9::before {
+    content: counter(list-9, decimal) ". ";
+}
+.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
+    padding-left: 3em;
+}
+.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
+    padding-left: 4.5em;
+}
+.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
+    padding-right: 3em;
+}
+.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
+    padding-right: 4.5em;
+}
+.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
+    padding-left: 6em;
+}
+.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
+    padding-left: 7.5em;
+}
+.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
+    padding-right: 6em;
+}
+.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
+    padding-right: 7.5em;
+}
+.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
+    padding-left: 9em;
+}
+.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
+    padding-left: 10.5em;
+}
+.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
+    padding-right: 9em;
+}
+.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
+    padding-right: 10.5em;
+}
+.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
+    padding-left: 12em;
+}
+.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
+    padding-left: 13.5em;
+}
+.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
+    padding-right: 12em;
+}
+.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
+    padding-right: 13.5em;
+}
+.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
+    padding-left: 15em;
+}
+.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
+    padding-left: 16.5em;
+}
+.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
+    padding-right: 15em;
+}
+.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
+    padding-right: 16.5em;
+}
+.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
+    padding-left: 18em;
+}
+.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
+    padding-left: 19.5em;
+}
+.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
+    padding-right: 18em;
+}
+.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
+    padding-right: 19.5em;
+}
+.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
+    padding-left: 21em;
+}
+.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
+    padding-left: 22.5em;
+}
+.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
+    padding-right: 21em;
+}
+.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
+    padding-right: 22.5em;
+}
+.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
+    padding-left: 24em;
+}
+.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
+    padding-left: 25.5em;
+}
+.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
+    padding-right: 24em;
+}
+.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
+    padding-right: 25.5em;
+}
+.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
+    padding-left: 27em;
+}
+.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
+    padding-left: 28.5em;
+}
+.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
+    padding-right: 27em;
+}
+.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
+    padding-right: 28.5em;
+}
+.ql-editor .ql-video {
+    display: block;
+    max-width: 100%;
+}
+.ql-editor .ql-video.ql-align-center {
+    margin: 0 auto;
+}
+.ql-editor .ql-video.ql-align-right {
+    margin: 0 0 0 auto;
+}
+.ql-editor .ql-bg-black {
+    background-color: #000;
+}
+.ql-editor .ql-bg-red {
+    background-color: #e60000;
+}
+.ql-editor .ql-bg-orange {
+    background-color: #f90;
+}
+.ql-editor .ql-bg-yellow {
+    background-color: #ff0;
+}
+.ql-editor .ql-bg-green {
+    background-color: #008a00;
+}
+.ql-editor .ql-bg-blue {
+    background-color: #06c;
+}
+.ql-editor .ql-bg-purple {
+    background-color: #93f;
+}
+.ql-editor .ql-color-white {
+    color: #fff;
+}
+.ql-editor .ql-color-red {
+    color: #e60000;
+}
+.ql-editor .ql-color-orange {
+    color: #f90;
+}
+.ql-editor .ql-color-yellow {
+    color: #ff0;
+}
+.ql-editor .ql-color-green {
+    color: #008a00;
+}
+.ql-editor .ql-color-blue {
+    color: #06c;
+}
+.ql-editor .ql-color-purple {
+    color: #93f;
+}
+.ql-editor .ql-font-serif {
+    font-family: Georgia, "Times New Roman", serif;
+}
+.ql-editor .ql-font-monospace {
+    font-family: Monaco, "Courier New", monospace;
+}
+.ql-editor .ql-size-small {
+    font-size: 0.75em;
+}
+.ql-editor .ql-size-large {
+    font-size: 1.5em;
+}
+.ql-editor .ql-size-huge {
+    font-size: 2.5em;
+}
+.ql-editor .ql-direction-rtl {
+    direction: rtl;
+    text-align: inherit;
+}
+.ql-editor .ql-align-center {
+    text-align: center;
+}
+.ql-editor .ql-align-justify {
+    text-align: justify;
+}
+.ql-editor .ql-align-right {
+    text-align: right;
+}
+.ql-editor.ql-blank::before {
+    color: #909399;
+    content: attr(data-placeholder);
+    left: 15px;
+    pointer-events: none;
+    position: absolute;
+    right: 15px;
+}
+.ql-snow.ql-toolbar::after,
+.ql-snow .ql-toolbar::after {
+    clear: both;
+    content: "";
+    display: table;
+}
+.ql-snow.ql-toolbar button,
+.ql-snow .ql-toolbar button {
+    background: none;
+    border: none;
+    cursor: pointer;
+    display: inline-block;
+    float: left;
+    height: 24px;
+    padding: 3px 5px;
+    width: 28px;
+}
+.ql-snow.ql-toolbar button svg,
+.ql-snow .ql-toolbar button svg {
+    float: left;
+    height: 100%;
+}
+.ql-snow.ql-toolbar button:active:hover,
+.ql-snow .ql-toolbar button:active:hover {
+    outline: none;
+}
+.ql-snow.ql-toolbar input.ql-image[type="file"],
+.ql-snow .ql-toolbar input.ql-image[type="file"] {
+    display: none;
+}
+.ql-snow.ql-toolbar button:hover,
+.ql-snow .ql-toolbar button:hover,
+.ql-snow.ql-toolbar button:focus,
+.ql-snow .ql-toolbar button:focus,
+.ql-snow.ql-toolbar button.ql-active,
+.ql-snow .ql-toolbar button.ql-active,
+.ql-snow.ql-toolbar .ql-picker-label:hover,
+.ql-snow .ql-toolbar .ql-picker-label:hover,
+.ql-snow.ql-toolbar .ql-picker-label.ql-active,
+.ql-snow .ql-toolbar .ql-picker-label.ql-active,
+.ql-snow.ql-toolbar .ql-picker-item:hover,
+.ql-snow .ql-toolbar .ql-picker-item:hover,
+.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
+.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
+    color: #06c;
+}
+.ql-snow.ql-toolbar button:hover .ql-fill,
+.ql-snow .ql-toolbar button:hover .ql-fill,
+.ql-snow.ql-toolbar button:focus .ql-fill,
+.ql-snow .ql-toolbar button:focus .ql-fill,
+.ql-snow.ql-toolbar button.ql-active .ql-fill,
+.ql-snow .ql-toolbar button.ql-active .ql-fill,
+.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,
+.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,
+.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,
+.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,
+.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,
+.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,
+.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
+.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
+.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
+.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
+.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
+    fill: #06c;
+}
+.ql-snow.ql-toolbar button:hover .ql-stroke,
+.ql-snow .ql-toolbar button:hover .ql-stroke,
+.ql-snow.ql-toolbar button:focus .ql-stroke,
+.ql-snow .ql-toolbar button:focus .ql-stroke,
+.ql-snow.ql-toolbar button.ql-active .ql-stroke,
+.ql-snow .ql-toolbar button.ql-active .ql-stroke,
+.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,
+.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,
+.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
+.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
+.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,
+.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,
+.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
+.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
+.ql-snow.ql-toolbar button:hover .ql-stroke-miter,
+.ql-snow .ql-toolbar button:hover .ql-stroke-miter,
+.ql-snow.ql-toolbar button:focus .ql-stroke-miter,
+.ql-snow .ql-toolbar button:focus .ql-stroke-miter,
+.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,
+.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,
+.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
+.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
+.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
+.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
+.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
+.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
+.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,
+.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
+    stroke: #06c;
+}
+@media (pointer: coarse) {
+    .ql-snow.ql-toolbar button:hover:not(.ql-active),
+    .ql-snow .ql-toolbar button:hover:not(.ql-active) {
+        color: #444;
+    }
+    .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,
+    .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,
+    .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,
+    .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill {
+        fill: #444;
+    }
+    .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,
+    .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,
+    .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,
+    .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter {
+        stroke: #444;
+    }
+}
+.ql-snow {
+    box-sizing: border-box;
+}
+.ql-snow * {
+    box-sizing: border-box;
+}
+.ql-snow .ql-hidden {
+    display: none;
+}
+.ql-snow .ql-out-bottom,
+.ql-snow .ql-out-top {
+    visibility: hidden;
+}
+.ql-snow .ql-tooltip {
+    position: absolute;
+    transform: translateY(10px);
+}
+.ql-snow .ql-tooltip a {
+    cursor: pointer;
+    text-decoration: none;
+}
+.ql-snow .ql-tooltip.ql-flip {
+    transform: translateY(-10px);
+}
+.ql-snow .ql-formats {
+    display: inline-block;
+    vertical-align: middle;
+}
+.ql-snow .ql-formats::after {
+    clear: both;
+    content: "";
+    display: table;
+}
+.ql-snow .ql-stroke {
+    fill: none;
+    stroke: #444;
+    stroke-linecap: round;
+    stroke-linejoin: round;
+    stroke-width: 2;
+}
+.ql-snow .ql-stroke-miter {
+    fill: none;
+    stroke: #444;
+    stroke-miterlimit: 10;
+    stroke-width: 2;
+}
+.ql-snow .ql-fill,
+.ql-snow .ql-stroke.ql-fill {
+    fill: #444;
+}
+.ql-snow .ql-empty {
+    fill: none;
+}
+.ql-snow .ql-even {
+    fill-rule: evenodd;
+}
+.ql-snow .ql-thin,
+.ql-snow .ql-stroke.ql-thin {
+    stroke-width: 1;
+}
+.ql-snow .ql-transparent {
+    opacity: 0.4;
+}
+.ql-snow .ql-direction svg:last-child {
+    display: none;
+}
+.ql-snow .ql-direction.ql-active svg:last-child {
+    display: inline;
+}
+.ql-snow .ql-direction.ql-active svg:first-child {
+    display: none;
+}
+.ql-snow .ql-editor h1 {
+    font-size: 2em;
+}
+.ql-snow .ql-editor h2 {
+    font-size: 1.5em;
+}
+.ql-snow .ql-editor h3 {
+    font-size: 1.17em;
+}
+.ql-snow .ql-editor h4 {
+    font-size: 1em;
+}
+.ql-snow .ql-editor h5 {
+    font-size: 0.83em;
+}
+.ql-snow .ql-editor h6 {
+    font-size: 0.67em;
+}
+.ql-snow .ql-editor a {
+    text-decoration: underline;
+}
+.ql-snow .ql-editor blockquote {
+    border-left: 4px solid #ccc;
+    margin-bottom: 5px;
+    margin-top: 5px;
+    padding-left: 16px;
+}
+.ql-snow .ql-editor code,
+.ql-snow .ql-editor pre {
+    background-color: #f0f0f0;
+    border-radius: 3px;
+}
+.ql-snow .ql-editor pre {
+    white-space: pre-wrap;
+    margin-bottom: 5px;
+    margin-top: 5px;
+    padding: 5px 10px;
+}
+.ql-snow .ql-editor code {
+    font-size: 85%;
+    padding: 2px 4px;
+}
+.ql-snow .ql-editor pre.ql-syntax {
+    background-color: #23241f;
+    color: #f8f8f2;
+    overflow: visible;
+}
+.ql-snow .ql-editor img {
+    max-width: 100%;
+}
+.ql-snow .ql-picker {
+    color: #444;
+    display: inline-block;
+    float: left;
+    font-size: 14px;
+    font-weight: 500;
+    height: 24px;
+    position: relative;
+    vertical-align: middle;
+}
+.ql-snow .ql-picker-label {
+    cursor: pointer;
+    display: inline-block;
+    height: 100%;
+    padding-left: 8px;
+    padding-right: 2px;
+    position: relative;
+    width: 100%;
+}
+.ql-snow .ql-picker-label::before {
+    display: inline-block;
+    line-height: 22px;
+}
+.ql-snow .ql-picker-options {
+    background-color: #fff;
+    display: none;
+    min-width: 100%;
+    padding: 4px 8px;
+    position: absolute;
+    white-space: nowrap;
+}
+.ql-snow .ql-picker-options .ql-picker-item {
+    cursor: pointer;
+    display: block;
+    padding-bottom: 5px;
+    padding-top: 5px;
+}
+.ql-snow .ql-picker.ql-expanded .ql-picker-label {
+    color: #ccc;
+    z-index: 2;
+}
+.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill {
+    fill: #ccc;
+}
+.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
+    stroke: #ccc;
+}
+.ql-snow .ql-picker.ql-expanded .ql-picker-options {
+    display: block;
+    margin-top: -1px;
+    top: 100%;
+    z-index: 1;
+}
+.ql-snow .ql-color-picker,
+.ql-snow .ql-icon-picker {
+    width: 28px;
+}
+.ql-snow .ql-color-picker .ql-picker-label,
+.ql-snow .ql-icon-picker .ql-picker-label {
+    padding: 2px 4px;
+}
+.ql-snow .ql-color-picker .ql-picker-label svg,
+.ql-snow .ql-icon-picker .ql-picker-label svg {
+    right: 4px;
+}
+.ql-snow .ql-icon-picker .ql-picker-options {
+    padding: 4px 0;
+}
+.ql-snow .ql-icon-picker .ql-picker-item {
+    height: 24px;
+    width: 24px;
+    padding: 2px 4px;
+}
+.ql-snow .ql-color-picker .ql-picker-options {
+    padding: 3px 5px;
+    width: 152px;
+}
+.ql-snow .ql-color-picker .ql-picker-item {
+    border: 1px solid transparent;
+    float: left;
+    height: 16px;
+    margin: 2px;
+    padding: 0;
+    width: 16px;
+}
+.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
+    position: absolute;
+    margin-top: -9px;
+    right: 0;
+    top: 50%;
+    width: 18px;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=""])::before,
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=""])::before,
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=""])::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=""])::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=""])::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=""])::before {
+    content: attr(data-label);
+}
+.ql-snow .ql-picker.ql-header {
+    width: 98px;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+    content: "Normal";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+    content: "Heading 1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+    content: "Heading 2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+    content: "Heading 3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+    content: "Heading 4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+    content: "Heading 5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+    content: "Heading 6";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+    font-size: 2em;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+    font-size: 1.5em;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+    font-size: 1.17em;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+    font-size: 1em;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+    font-size: 0.83em;
+}
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+    font-size: 0.67em;
+}
+.ql-snow .ql-picker.ql-font {
+    width: 108px;
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+    content: "Sans Serif";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+    content: "Serif";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+    content: "Monospace";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+    font-family: Georgia, "Times New Roman", serif;
+}
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+    font-family: Monaco, "Courier New", monospace;
+}
+.ql-snow .ql-picker.ql-size {
+    width: 98px;
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+    content: "Normal";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+    content: "Small";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+    content: "Large";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+    content: "Huge";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+    font-size: 10px;
+}
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+    font-size: 18px;
+}
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+    font-size: 32px;
+}
+.ql-snow .ql-color-picker.ql-background .ql-picker-item {
+    background-color: #fff;
+}
+.ql-snow .ql-color-picker.ql-color .ql-picker-item {
+    background-color: #000;
+}
+.ql-toolbar.ql-snow {
+    border: 1px solid #ccc;
+    box-sizing: border-box;
+    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+    padding: 8px;
+}
+.ql-toolbar.ql-snow .ql-formats {
+    margin-right: 15px;
+}
+.ql-toolbar.ql-snow .ql-picker-label {
+    border: 1px solid transparent;
+}
+.ql-toolbar.ql-snow .ql-picker-options {
+    border: 1px solid transparent;
+    box-shadow: rgb(0 0 0 / 20%) 0 2px 8px;
+}
+.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
+    border-color: #ccc;
+}
+.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
+    border-color: #ccc;
+}
+.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,
+.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover {
+    border-color: #000;
+}
+.ql-toolbar.ql-snow + .ql-container.ql-snow {
+    border-top: 0;
+}
+.ql-snow .ql-tooltip {
+    background-color: #fff;
+    border: 1px solid #ccc;
+    box-shadow: 0 0 5px #ddd;
+    color: #444;
+    padding: 5px 12px;
+    white-space: nowrap;
+}
+.ql-snow .ql-tooltip::before {
+    content: "Visit URL:";
+    line-height: 26px;
+    margin-right: 8px;
+}
+.ql-snow .ql-tooltip input[type="text"] {
+    display: none;
+    border: 1px solid #ccc;
+    font-size: 13px;
+    height: 26px;
+    margin: 0;
+    padding: 3px 5px;
+    width: 170px;
+}
+.ql-snow .ql-tooltip a.ql-preview {
+    display: inline-block;
+    max-width: 200px;
+    overflow-x: hidden;
+    text-overflow: ellipsis;
+    vertical-align: top;
+}
+.ql-snow .ql-tooltip a.ql-action::after {
+    border-right: 1px solid #ccc;
+    content: "Edit";
+    margin-left: 16px;
+    padding-right: 8px;
+}
+.ql-snow .ql-tooltip a.ql-remove::before {
+    content: "Remove";
+    margin-left: 8px;
+}
+.ql-snow .ql-tooltip a {
+    line-height: 26px;
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-preview,
+.ql-snow .ql-tooltip.ql-editing a.ql-remove {
+    display: none;
+}
+.ql-snow .ql-tooltip.ql-editing input[type="text"] {
+    display: inline-block;
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+    border-right: 0;
+    content: "Save";
+    padding-right: 0;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+    content: "Enter link:";
+}
+.ql-snow .ql-tooltip[data-mode="formula"]::before {
+    content: "Enter formula:";
+}
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+    content: "Enter video:";
+}
+.ql-snow a {
+    color: #06c;
+}
+.ql-container.ql-snow {
+    border: 1px solid #ccc;
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 502 - 262
src/assets/iconfont/demo_index.html


+ 147 - 83
src/assets/iconfont/iconfont.css

@@ -1,9 +1,9 @@
 @font-face {
-  font-family: "iconfont"; /* Project id 4723464 */
-  src: url('iconfont.woff2?t=1736319276637') format('woff2'),
-       url('iconfont.woff?t=1736319276637') format('woff'),
-       url('iconfont.ttf?t=1736319276637') format('truetype'),
-       url('iconfont.svg?t=1736319276637#iconfont') format('svg');
+  font-family: "iconfont"; /* Project id 4820751 */
+  src: url('iconfont.woff2?t=1738918368855') format('woff2'),
+       url('iconfont.woff?t=1738918368855') format('woff'),
+       url('iconfont.ttf?t=1738918368855') format('truetype'),
+       url('iconfont.svg?t=1738918368855#iconfont') format('svg');
 }
 
 .iconfont {
@@ -14,68 +14,104 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
-.icon-delete-three:before {
-  content: "\e7d5";
+.icon-Female:before {
+  content: "\e7e5";
 }
 
-.icon-copy:before {
-  content: "\e7d3";
+.icon-Male:before {
+  content: "\e7e4";
 }
 
-.icon-quote:before {
-  content: "\e7d4";
+.icon-profile:before {
+  content: "\e60f";
 }
 
-.icon-send:before {
-  content: "\e7d2";
+.icon-arrow_right:before {
+  content: "\e60d";
 }
 
-.icon-comment-two:before {
-  content: "\e7cd";
+.icon-fire-fill:before {
+  content: "\e866";
 }
 
-.icon-eit:before {
-  content: "\e7ce";
+.icon-eye-fill:before {
+  content: "\e869";
 }
 
-.icon-comments:before {
-  content: "\e7cf";
+.icon-like-fill:before {
+  content: "\e86a";
 }
 
-.icon-comment-one:before {
-  content: "\e7d0";
+.icon-location-fill:before {
+  content: "\e868";
 }
 
-.icon-like:before {
-  content: "\e7d1";
+.icon-close:before {
+  content: "\e7fc";
 }
 
-.icon-set-top:before {
-  content: "\e7c7";
+.icon-caret-down:before {
+  content: "\e8ec";
 }
 
-.icon-pic-two:before {
-  content: "\e7c6";
+.icon-plus-circle-fill:before {
+  content: "\e845";
 }
 
-.icon-close-remind:before {
-  content: "\e7c8";
+.icon-image-fill:before {
+  content: "\e860";
 }
 
-.icon-log:before {
-  content: "\e7c9";
+.icon-setting:before {
+  content: "\e78e";
 }
 
-.icon-jubaoguanli:before {
-  content: "\e7ca";
+.icon-edit-square:before {
+  content: "\e791";
 }
 
-.icon-setting-one:before {
-  content: "\e7cb";
+.icon-delete-two:before {
+  content: "\e7c3";
 }
 
-.icon-delete-one:before {
-  content: "\e7cc";
+.icon-plus:before {
+  content: "\e8fe";
+}
+
+.icon-star-fill:before {
+  content: "\e86b";
+}
+
+.icon-star:before {
+  content: "\e7df";
+}
+
+.icon-smile:before {
+  content: "\e783";
+}
+
+.icon-message:before {
+  content: "\e78a";
+}
+
+.icon-menu:before {
+  content: "\e7f4";
+}
+
+.icon-right:before {
+  content: "\e7eb";
+}
+
+.icon-left:before {
+  content: "\e7ec";
+}
+
+.icon-info-circle:before {
+  content: "\e77e";
+}
+
+.icon-caret-up:before {
+  content: "\e8ed";
 }
 
 .icon-close-one:before {
@@ -98,95 +134,123 @@
   content: "\e7c5";
 }
 
-.icon-caret-up:before {
-  content: "\e8ed";
+.icon-pic-two:before {
+  content: "\e7c6";
 }
 
-.icon-info-circle:before {
-  content: "\e77e";
+.icon-close-remind:before {
+  content: "\e7c8";
 }
 
-.icon-left:before {
-  content: "\e7ec";
+.icon-log:before {
+  content: "\e7c9";
 }
 
-.icon-right:before {
-  content: "\e7eb";
+.icon-jubaoguanli:before {
+  content: "\e7ca";
 }
 
-.icon-menu:before {
-  content: "\e7f4";
+.icon-setting-one:before {
+  content: "\e7cb";
 }
 
-.icon-message:before {
-  content: "\e78a";
+.icon-delete-one:before {
+  content: "\e7cc";
 }
 
-.icon-smile:before {
-  content: "\e783";
+.icon-set-top:before {
+  content: "\e7c7";
 }
 
-.icon-star:before {
-  content: "\e7df";
+.icon-comment-two:before {
+  content: "\e7cd";
 }
 
-.icon-star-fill:before {
-  content: "\e86b";
+.icon-eit:before {
+  content: "\e7ce";
 }
 
-.icon-plus:before {
-  content: "\e8fe";
+.icon-comments:before {
+  content: "\e7cf";
 }
 
-.icon-edit-square:before {
-  content: "\e791";
+.icon-comment-one:before {
+  content: "\e7d0";
 }
 
-.icon-delete-two:before {
-  content: "\e7c3";
+.icon-like:before {
+  content: "\e7d1";
 }
 
-.icon-setting:before {
-  content: "\e78e";
+.icon-send:before {
+  content: "\e7d2";
 }
 
-.icon-plus-circle-fill:before {
-  content: "\e845";
+.icon-copy:before {
+  content: "\e7d3";
 }
 
-.icon-image-fill:before {
-  content: "\e860";
+.icon-quote:before {
+  content: "\e7d4";
 }
 
-.icon-close:before {
-  content: "\e7fc";
+.icon-delete-three:before {
+  content: "\e7d5";
 }
 
-.icon-caret-down:before {
-  content: "\e8ec";
+.icon-edit-1:before {
+  content: "\e7d7";
 }
 
-.icon-location-fill:before {
-  content: "\e868";
+.icon-logout:before {
+  content: "\e7d8";
 }
 
-.icon-fire-fill:before {
-  content: "\e866";
+.icon-chat-message:before {
+  content: "\e7d9";
 }
 
-.icon-eye-fill:before {
-  content: "\e869";
+.icon-chevron-down:before {
+  content: "\e7da";
 }
 
-.icon-like-fill:before {
-  content: "\e86a";
+.icon-caret-down-small:before {
+  content: "\e7db";
 }
 
-.icon-arrow_right:before {
-  content: "\e60d";
+.icon-cart:before {
+  content: "\e7dc";
 }
 
-.icon-profile:before {
-  content: "\e60f";
+.icon-lock:before {
+  content: "\e7dd";
+}
+
+.icon-unlock:before {
+  content: "\e7e0";
+}
+
+.icon-more:before {
+  content: "\e7e1";
+}
+
+.icon-location:before {
+  content: "\e7e2";
+}
+
+.icon-chatgroup:before {
+  content: "\e7de";
+}
+
+.icon-share:before {
+  content: "\e7d6";
+}
+
+.icon-Thumbs-up:before {
+  content: "\e7e3";
+}
+
+.icon-eye:before {
+  content: "\e78f";
 }
 

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
src/assets/iconfont/iconfont.js


+ 311 - 199
src/assets/iconfont/iconfont.json

@@ -1,121 +1,184 @@
 {
-  "id": "4723464",
-  "name": "xyy-web",
+  "id": "4820751",
+  "name": "xxy-web-two",
   "font_family": "iconfont",
   "css_prefix_text": "icon-",
-  "description": "",
+  "description": "逍遥游",
   "glyphs": [
     {
-      "icon_id": "43078637",
-      "name": "delete-three",
-      "font_class": "delete-three",
-      "unicode": "e7d5",
-      "unicode_decimal": 59349
+      "icon_id": "43272273",
+      "name": "Female",
+      "font_class": "Female",
+      "unicode": "e7e5",
+      "unicode_decimal": 59365
     },
     {
-      "icon_id": "43078629",
-      "name": "copy",
-      "font_class": "copy",
-      "unicode": "e7d3",
-      "unicode_decimal": 59347
+      "icon_id": "43272253",
+      "name": "Male",
+      "font_class": "Male",
+      "unicode": "e7e4",
+      "unicode_decimal": 59364
     },
     {
-      "icon_id": "43078628",
-      "name": "quote",
-      "font_class": "quote",
-      "unicode": "e7d4",
-      "unicode_decimal": 59348
+      "icon_id": "11813183",
+      "name": "profile",
+      "font_class": "profile",
+      "unicode": "e60f",
+      "unicode_decimal": 58895
     },
     {
-      "icon_id": "43073198",
-      "name": "send",
-      "font_class": "send",
-      "unicode": "e7d2",
-      "unicode_decimal": 59346
+      "icon_id": "14678715",
+      "name": "arrow_right",
+      "font_class": "arrow_right",
+      "unicode": "e60d",
+      "unicode_decimal": 58893
     },
     {
-      "icon_id": "43073203",
-      "name": "comment-two",
-      "font_class": "comment-two",
-      "unicode": "e7cd",
-      "unicode_decimal": 59341
+      "icon_id": "4936652",
+      "name": "fire-fill",
+      "font_class": "fire-fill",
+      "unicode": "e866",
+      "unicode_decimal": 59494
     },
     {
-      "icon_id": "43073202",
-      "name": "eit",
-      "font_class": "eit",
-      "unicode": "e7ce",
-      "unicode_decimal": 59342
+      "icon_id": "4936668",
+      "name": "eye-fill",
+      "font_class": "eye-fill",
+      "unicode": "e869",
+      "unicode_decimal": 59497
     },
     {
-      "icon_id": "43073200",
-      "name": "comments",
-      "font_class": "comments",
-      "unicode": "e7cf",
-      "unicode_decimal": 59343
+      "icon_id": "4936669",
+      "name": "like-fill",
+      "font_class": "like-fill",
+      "unicode": "e86a",
+      "unicode_decimal": 59498
     },
     {
-      "icon_id": "43073199",
-      "name": "comment-one",
-      "font_class": "comment-one",
-      "unicode": "e7d0",
-      "unicode_decimal": 59344
+      "icon_id": "4936659",
+      "name": "location-fill",
+      "font_class": "location-fill",
+      "unicode": "e868",
+      "unicode_decimal": 59496
     },
     {
-      "icon_id": "43073201",
-      "name": "like",
-      "font_class": "like",
-      "unicode": "e7d1",
-      "unicode_decimal": 59345
+      "icon_id": "4767096",
+      "name": "close",
+      "font_class": "close",
+      "unicode": "e7fc",
+      "unicode_decimal": 59388
     },
     {
-      "icon_id": "43063382",
-      "name": "set-top",
-      "font_class": "set-top",
-      "unicode": "e7c7",
-      "unicode_decimal": 59335
+      "icon_id": "6598339",
+      "name": "caret-down",
+      "font_class": "caret-down",
+      "unicode": "e8ec",
+      "unicode_decimal": 59628
     },
     {
-      "icon_id": "43063327",
-      "name": "pic-two",
-      "font_class": "pic-two",
-      "unicode": "e7c6",
-      "unicode_decimal": 59334
+      "icon_id": "4936486",
+      "name": "plus-circle-fill",
+      "font_class": "plus-circle-fill",
+      "unicode": "e845",
+      "unicode_decimal": 59461
     },
     {
-      "icon_id": "43063326",
-      "name": "close-remind",
-      "font_class": "close-remind",
-      "unicode": "e7c8",
-      "unicode_decimal": 59336
+      "icon_id": "4936630",
+      "name": "image-fill",
+      "font_class": "image-fill",
+      "unicode": "e860",
+      "unicode_decimal": 59488
     },
     {
-      "icon_id": "43063324",
-      "name": "log",
-      "font_class": "log",
-      "unicode": "e7c9",
-      "unicode_decimal": 59337
+      "icon_id": "4765891",
+      "name": "setting",
+      "font_class": "setting",
+      "unicode": "e78e",
+      "unicode_decimal": 59278
     },
     {
-      "icon_id": "43063325",
-      "name": "jubaoguanli",
-      "font_class": "jubaoguanli",
-      "unicode": "e7ca",
-      "unicode_decimal": 59338
+      "icon_id": "4765957",
+      "name": "edit-square",
+      "font_class": "edit-square",
+      "unicode": "e791",
+      "unicode_decimal": 59281
     },
     {
-      "icon_id": "43063323",
-      "name": "setting",
-      "font_class": "setting-one",
-      "unicode": "e7cb",
-      "unicode_decimal": 59339
+      "icon_id": "4766676",
+      "name": "delete",
+      "font_class": "delete-two",
+      "unicode": "e7c3",
+      "unicode_decimal": 59331
     },
     {
-      "icon_id": "43063322",
-      "name": "delete-one",
-      "font_class": "delete-one",
-      "unicode": "e7cc",
-      "unicode_decimal": 59340
+      "icon_id": "7834345",
+      "name": "plus",
+      "font_class": "plus",
+      "unicode": "e8fe",
+      "unicode_decimal": 59646
+    },
+    {
+      "icon_id": "4936673",
+      "name": "star-fill",
+      "font_class": "star-fill",
+      "unicode": "e86b",
+      "unicode_decimal": 59499
+    },
+    {
+      "icon_id": "4766954",
+      "name": "star",
+      "font_class": "star",
+      "unicode": "e7df",
+      "unicode_decimal": 59359
+    },
+    {
+      "icon_id": "4765739",
+      "name": "smile",
+      "font_class": "smile",
+      "unicode": "e783",
+      "unicode_decimal": 59267
+    },
+    {
+      "icon_id": "4765866",
+      "name": "message",
+      "font_class": "message",
+      "unicode": "e78a",
+      "unicode_decimal": 59274
+    },
+    {
+      "icon_id": "4767059",
+      "name": "menu",
+      "font_class": "menu",
+      "unicode": "e7f4",
+      "unicode_decimal": 59380
+    },
+    {
+      "icon_id": "4767011",
+      "name": "right",
+      "font_class": "right",
+      "unicode": "e7eb",
+      "unicode_decimal": 59371
+    },
+    {
+      "icon_id": "4767012",
+      "name": "left",
+      "font_class": "left",
+      "unicode": "e7ec",
+      "unicode_decimal": 59372
+    },
+    {
+      "icon_id": "4765727",
+      "name": "info-circle",
+      "font_class": "info-circle",
+      "unicode": "e77e",
+      "unicode_decimal": 59262
+    },
+    {
+      "icon_id": "6598341",
+      "name": "caret-up",
+      "font_class": "caret-up",
+      "unicode": "e8ed",
+      "unicode_decimal": 59629
     },
     {
       "icon_id": "43062458",
@@ -147,171 +210,220 @@
     },
     {
       "icon_id": "43062462",
-      "name": "peoples-two",
+      "name": "peoples-two ",
       "font_class": "peoples-two",
       "unicode": "e7c5",
       "unicode_decimal": 59333
     },
     {
-      "icon_id": "6598341",
-      "name": "caret-up",
-      "font_class": "caret-up",
-      "unicode": "e8ed",
-      "unicode_decimal": 59629
+      "icon_id": "43063327",
+      "name": "pic-two",
+      "font_class": "pic-two",
+      "unicode": "e7c6",
+      "unicode_decimal": 59334
     },
     {
-      "icon_id": "4765727",
-      "name": "info-circle",
-      "font_class": "info-circle",
-      "unicode": "e77e",
-      "unicode_decimal": 59262
+      "icon_id": "43063326",
+      "name": "close-remind",
+      "font_class": "close-remind",
+      "unicode": "e7c8",
+      "unicode_decimal": 59336
     },
     {
-      "icon_id": "4767012",
-      "name": "left",
-      "font_class": "left",
-      "unicode": "e7ec",
-      "unicode_decimal": 59372
+      "icon_id": "43063324",
+      "name": "log",
+      "font_class": "log",
+      "unicode": "e7c9",
+      "unicode_decimal": 59337
     },
     {
-      "icon_id": "4767011",
-      "name": "right",
-      "font_class": "right",
-      "unicode": "e7eb",
-      "unicode_decimal": 59371
+      "icon_id": "43063325",
+      "name": "jubaoguanli",
+      "font_class": "jubaoguanli",
+      "unicode": "e7ca",
+      "unicode_decimal": 59338
     },
     {
-      "icon_id": "4767059",
-      "name": "menu",
-      "font_class": "menu",
-      "unicode": "e7f4",
-      "unicode_decimal": 59380
+      "icon_id": "43063323",
+      "name": "setting",
+      "font_class": "setting-one",
+      "unicode": "e7cb",
+      "unicode_decimal": 59339
     },
     {
-      "icon_id": "4765866",
-      "name": "message",
-      "font_class": "message",
-      "unicode": "e78a",
-      "unicode_decimal": 59274
+      "icon_id": "43063322",
+      "name": "delete",
+      "font_class": "delete-one",
+      "unicode": "e7cc",
+      "unicode_decimal": 59340
     },
     {
-      "icon_id": "4765739",
-      "name": "smile",
-      "font_class": "smile",
-      "unicode": "e783",
-      "unicode_decimal": 59267
+      "icon_id": "43063382",
+      "name": "set-top",
+      "font_class": "set-top",
+      "unicode": "e7c7",
+      "unicode_decimal": 59335
     },
     {
-      "icon_id": "4766954",
-      "name": "star",
-      "font_class": "star",
-      "unicode": "e7df",
-      "unicode_decimal": 59359
+      "icon_id": "43073203",
+      "name": "comment-two",
+      "font_class": "comment-two",
+      "unicode": "e7cd",
+      "unicode_decimal": 59341
     },
     {
-      "icon_id": "4936673",
-      "name": "star-fill",
-      "font_class": "star-fill",
-      "unicode": "e86b",
-      "unicode_decimal": 59499
+      "icon_id": "43073202",
+      "name": "tiji",
+      "font_class": "eit",
+      "unicode": "e7ce",
+      "unicode_decimal": 59342
     },
     {
-      "icon_id": "7834345",
-      "name": "plus",
-      "font_class": "plus",
-      "unicode": "e8fe",
-      "unicode_decimal": 59646
+      "icon_id": "43073200",
+      "name": "comments",
+      "font_class": "comments",
+      "unicode": "e7cf",
+      "unicode_decimal": 59343
     },
     {
-      "icon_id": "4765957",
-      "name": "edit-square",
-      "font_class": "edit-square",
-      "unicode": "e791",
-      "unicode_decimal": 59281
+      "icon_id": "43073199",
+      "name": "comment-one",
+      "font_class": "comment-one",
+      "unicode": "e7d0",
+      "unicode_decimal": 59344
     },
     {
-      "icon_id": "4766676",
-      "name": "delete-two",
-      "font_class": "delete-two",
-      "unicode": "e7c3",
-      "unicode_decimal": 59331
+      "icon_id": "43073201",
+      "name": "like",
+      "font_class": "like",
+      "unicode": "e7d1",
+      "unicode_decimal": 59345
     },
     {
-      "icon_id": "4765891",
-      "name": "setting",
-      "font_class": "setting",
-      "unicode": "e78e",
-      "unicode_decimal": 59278
+      "icon_id": "43073198",
+      "name": "send",
+      "font_class": "send",
+      "unicode": "e7d2",
+      "unicode_decimal": 59346
     },
     {
-      "icon_id": "4936486",
-      "name": "plus-circle-fill",
-      "font_class": "plus-circle-fill",
-      "unicode": "e845",
-      "unicode_decimal": 59461
+      "icon_id": "43078629",
+      "name": "copy",
+      "font_class": "copy",
+      "unicode": "e7d3",
+      "unicode_decimal": 59347
     },
     {
-      "icon_id": "4936630",
-      "name": "image-fill",
-      "font_class": "image-fill",
-      "unicode": "e860",
-      "unicode_decimal": 59488
+      "icon_id": "43078628",
+      "name": "quote",
+      "font_class": "quote",
+      "unicode": "e7d4",
+      "unicode_decimal": 59348
     },
     {
-      "icon_id": "4767096",
-      "name": "close",
-      "font_class": "close",
-      "unicode": "e7fc",
-      "unicode_decimal": 59388
+      "icon_id": "43078637",
+      "name": "delete-three",
+      "font_class": "delete-three",
+      "unicode": "e7d5",
+      "unicode_decimal": 59349
     },
     {
-      "icon_id": "6598339",
-      "name": "caret-down",
-      "font_class": "caret-down",
-      "unicode": "e8ec",
-      "unicode_decimal": 59628
+      "icon_id": "43103287",
+      "name": "edit-1",
+      "font_class": "edit-1",
+      "unicode": "e7d7",
+      "unicode_decimal": 59351
     },
     {
-      "icon_id": "4936659",
-      "name": "location-fill",
-      "font_class": "location-fill",
-      "unicode": "e868",
-      "unicode_decimal": 59496
+      "icon_id": "43103286",
+      "name": "logout",
+      "font_class": "logout",
+      "unicode": "e7d8",
+      "unicode_decimal": 59352
     },
     {
-      "icon_id": "4936652",
-      "name": "fire-fill",
-      "font_class": "fire-fill",
-      "unicode": "e866",
-      "unicode_decimal": 59494
+      "icon_id": "43103284",
+      "name": "chat-message",
+      "font_class": "chat-message",
+      "unicode": "e7d9",
+      "unicode_decimal": 59353
     },
     {
-      "icon_id": "4936668",
-      "name": "eye-fill",
-      "font_class": "eye-fill",
-      "unicode": "e869",
-      "unicode_decimal": 59497
+      "icon_id": "43103285",
+      "name": "chevron-down",
+      "font_class": "chevron-down",
+      "unicode": "e7da",
+      "unicode_decimal": 59354
     },
     {
-      "icon_id": "4936669",
-      "name": "like-fill",
-      "font_class": "like-fill",
-      "unicode": "e86a",
-      "unicode_decimal": 59498
+      "icon_id": "43103282",
+      "name": "caret-down-small",
+      "font_class": "caret-down-small",
+      "unicode": "e7db",
+      "unicode_decimal": 59355
     },
     {
-      "icon_id": "14678715",
-      "name": "arrow_right",
-      "font_class": "arrow_right",
-      "unicode": "e60d",
-      "unicode_decimal": 58893
+      "icon_id": "43103283",
+      "name": "cart",
+      "font_class": "cart",
+      "unicode": "e7dc",
+      "unicode_decimal": 59356
     },
     {
-      "icon_id": "11813183",
-      "name": "profile",
-      "font_class": "profile",
-      "unicode": "e60f",
-      "unicode_decimal": 58895
+      "icon_id": "43209895",
+      "name": "lock",
+      "font_class": "lock",
+      "unicode": "e7dd",
+      "unicode_decimal": 59357
+    },
+    {
+      "icon_id": "43209870",
+      "name": "unlock",
+      "font_class": "unlock",
+      "unicode": "e7e0",
+      "unicode_decimal": 59360
+    },
+    {
+      "icon_id": "43209869",
+      "name": "more",
+      "font_class": "more",
+      "unicode": "e7e1",
+      "unicode_decimal": 59361
+    },
+    {
+      "icon_id": "43209868",
+      "name": "location",
+      "font_class": "location",
+      "unicode": "e7e2",
+      "unicode_decimal": 59362
+    },
+    {
+      "icon_id": "43210372",
+      "name": "chatgroup",
+      "font_class": "chatgroup",
+      "unicode": "e7de",
+      "unicode_decimal": 59358
+    },
+    {
+      "icon_id": "43223178",
+      "name": "share",
+      "font_class": "share",
+      "unicode": "e7d6",
+      "unicode_decimal": 59350
+    },
+    {
+      "icon_id": "43223177",
+      "name": "Thumbs-up",
+      "font_class": "Thumbs-up",
+      "unicode": "e7e3",
+      "unicode_decimal": 59363
+    },
+    {
+      "icon_id": "4765896",
+      "name": "eye",
+      "font_class": "eye",
+      "unicode": "e78f",
+      "unicode_decimal": 59279
     }
   ]
 }

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 12 - 13
src/assets/iconfont/iconfont.svg


BIN
src/assets/iconfont/iconfont.ttf


BIN
src/assets/iconfont/iconfont.woff


BIN
src/assets/iconfont/iconfont.woff2


+ 5 - 0
src/assets/img/note-create/check.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="check">
+<path id="union" d="M6.43348 9.92188L12.6561 3.69922L13.5754 4.61846L6.43348 11.7604L1.97412 7.301L2.89336 6.38176L6.43348 9.92188Z" fill="#FF9300"/>
+</g>
+</svg>

+ 6 - 0
src/assets/img/note-create/expand-text-input.svg

@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Expand-text-input (&#229;&#177;&#149;&#229;&#188;&#128;&#230;&#150;&#135;&#230;&#156;&#172;&#229;&#159;&#159;)">
+<path id="Vector" d="M3.99967 9.33358L3.99967 4.00024L9.33301 4.00024" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_2" d="M12 6.66675L12 12.0001L6.66667 12.0001" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 8 - 0
src/assets/img/note-create/location.svg

@@ -0,0 +1,8 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="location">
+<g id="union">
+<path d="M10.5001 6.00042C10.5001 7.38113 9.3808 8.50042 8.00009 8.50042C6.61938 8.50042 5.50009 7.38113 5.50009 6.00042C5.50009 4.6197 6.61938 3.50042 8.00009 3.50042C9.3808 3.50042 10.5001 4.6197 10.5001 6.00042ZM9.50009 6.00042C9.50009 5.17199 8.82852 4.50042 8.00009 4.50042C7.17166 4.50042 6.50009 5.17199 6.50009 6.00042C6.50009 6.82884 7.17166 7.50042 8.00009 7.50042C8.82852 7.50042 9.50009 6.82884 9.50009 6.00042Z" fill="#333333"/>
+<path d="M8.36196 14.4688C8.18821 14.7241 7.81196 14.7241 7.63822 14.4688L3.85557 8.91217C2.50041 6.92146 2.75204 4.24847 4.45488 2.54562C6.41284 0.587658 9.58733 0.587657 11.5453 2.54562C13.2481 4.24847 13.4998 6.92146 12.1446 8.91217L8.36196 14.4688ZM11.318 8.34944C12.4028 6.75579 12.2014 4.61593 10.8382 3.25273C9.27075 1.68529 6.72943 1.68529 5.16199 3.25273C3.79878 4.61593 3.59735 6.75579 4.68221 8.34944L8.00009 13.2234L11.318 8.34944Z" fill="#333333"/>
+</g>
+</g>
+</svg>

+ 6 - 0
src/assets/img/note-create/orange-expand-text-input.svg

@@ -0,0 +1,6 @@
+<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Expand-text-input (&#229;&#177;&#149;&#229;&#188;&#128;&#230;&#150;&#135;&#230;&#156;&#172;&#229;&#159;&#159;)">
+<path id="Vector" d="M7.33333 1.41729L7.33333 7.19507L2 7.19507" stroke="#FF9300" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_2" d="M8.66699 15.5L8.66699 9.72222L14.0003 9.72222" stroke="#FF9300" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 9 - 0
src/assets/img/profile-others/Female.svg

@@ -0,0 +1,9 @@
+<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Female (&#229;&#165;&#179;&#230;&#128;&#167;)">
+<g id="Female (&#229;&#165;&#179;&#230;&#128;&#167;)_2">
+<path id="Vector" d="M11.1933 2.87323C9.59872 1.27859 7.01326 1.27859 5.41864 2.87323C4.62131 3.67055 4.22266 4.71556 4.22266 5.76057C4.22266 6.80559 4.62131 7.8506 5.41864 8.64793C7.01326 10.2426 9.59872 10.2426 11.1933 8.64793C12.788 7.0533 12.788 4.46788 11.1933 2.87323Z" stroke="#FF0FE3" stroke-linejoin="round"/>
+<path id="Vector_2" d="M5.38515 8.6145L1.67285 12.3268" stroke="#FF0FE3" stroke-linecap="round" stroke-linejoin="round"/>
+<path id="Vector_3" d="M5.59122 12.1205L1.87891 8.4082" stroke="#FF0FE3" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</g>
+</svg>

+ 5 - 0
src/assets/img/profile-others/Like.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Like (&#229;&#150;&#156;&#230;&#172;&#162;)">
+<path id="Vector" d="M4.99967 3.16675C2.97463 3.16675 1.33301 4.80838 1.33301 6.83341C1.33301 10.5001 5.66634 13.8334 7.99967 14.6088C10.333 13.8334 14.6663 10.5001 14.6663 6.83341C14.6663 4.80838 13.0247 3.16675 10.9997 3.16675C9.75957 3.16675 8.66324 3.78238 7.99967 4.72468C7.33611 3.78238 6.23977 3.16675 4.99967 3.16675Z" stroke="#999999" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+</svg>

+ 5 - 0
src/assets/img/profile-others/Like2.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Like (&#229;&#150;&#156;&#230;&#172;&#162;)">
+<path id="Vector" d="M4.99967 2.6665C2.97463 2.6665 1.33301 4.30814 1.33301 6.33317C1.33301 9.99984 5.66634 13.3332 7.99967 14.1086C10.333 13.3332 14.6663 9.99984 14.6663 6.33317C14.6663 4.30814 13.0247 2.6665 10.9997 2.6665C9.75957 2.6665 8.66324 3.28214 7.99967 4.22444C7.33611 3.28214 6.23977 2.6665 4.99967 2.6665Z" fill="#FF476A"/>
+</g>
+</svg>

BIN
src/assets/img/topic/topic.png


BIN
src/assets/img/topic/yj.png


+ 299 - 142
src/components/CreateNote/Form.vue

@@ -1,86 +1,15 @@
 <template>
   <div class="box-border">
-    <div class="flex items-center pl-16 w-full h-44 pt-12">
-      <div class="w-2 h-14 bg-[#FF9300] mr-8"></div>
-      <h1 class="text-sm font-bold">填写游记信息</h1>
-    </div>
-    <div class="flex items-center justify-center">
-      <van-field
-        v-model="departureTime"
-        :label-width="labelWidth"
-        name="calendar"
-        clearable
-        autocomplete="off"
-        placeholder="请选择出发时间"
-        @click="showCalendar = true"
-      >
-        <!--  :rules="[{ required: true, message: '请选择出发时间' }]" -->
-        <template #label>
-          <div
-            class="w-full box-border flex items-center text-16 h-full font-400 text-[#000]/[0.9]"
-          >
-            出发时间
-          </div>
-        </template>
-        <template #right-icon>
-          <div class="w-24 h-24">
-            <van-image width="100%" height="100%" :src="calendar" />
-          </div>
-        </template>
-      </van-field>
-      <van-calendar
-        color="#FE8E2C"
-        :min-date="minDate"
-        :max-date="maxDate"
-        title="请选择出发时间"
-        type="single"
-        v-model:show="showCalendar"
-        @confirm="onConfirm"
-      />
-    </div>
-
-    <van-field
-      :label-width="labelWidth"
-      v-model="countTimes"
-      name="countTimes"
-      autocomplete="off"
-      clearable
-      placeholder="请输入您的天数 例:4天"
-    >
-      <!-- :rules="[{ required: true, message: '请输入您的天数' }]" -->
-      <template #label>
-        <span class="text-16 font-400 text-[#000]/[0.9]">出发天数</span>
+    <van-cell @click="showPicker = true" size="large" center is-link>
+      <template #icon>
+        <img class="w-16 h-16" src="~/assets/img/note-create/location.svg" alt="" />
       </template>
-    </van-field>
-    <van-field
-      :label-width="labelWidth"
-      v-model="role"
-      label="人物关系"
-      clearable
-      autocomplete="off"
-      placeholder="例:情侣"
-    ></van-field>
-
-    <van-field
-      is-link
-      v-model="endPlace"
-      :label-width="labelWidth"
-      clearable
-      readonly
-      autocomplete="off"
-      placeholder="目的地"
-      @click="showPicker = true"
-      :rules="[{ required: true }]"
-    >
-      <template #label>
-        <span class="text-16 font-400 text-[#000]/[0.9]">
-          目的地
-
-          <span class="text-16 text-[#D54941]">*</span>
-        </span>
+      <template #title>
+        <span class="text-16 text-[#D54941]">*</span>
+        {{ endPlace ? endPlace : '地区选择' }}
       </template>
-    </van-field>
-    <van-popup v-model:show="showPicker" position="bottom">
+    </van-cell>
+    <van-popup round v-model:show="showPicker" position="bottom">
       <van-picker
         :columns="placeOptions"
         :columns-field-names="placeOptionProps"
@@ -88,75 +17,258 @@
         @cancel="showPicker = false"
       />
     </van-popup>
-    <!-- <van-cascader
-        v-model="endPlace"
-        title="请选择所在地区"
-        :options="placeOptions"
-        :field-names="placeOptionProps"
-        @confirm="onConfirmAddr"
-        @cancel="showPicker = false"
-      /> -->
-
-    <!--  @finish="onConfirmAddr"  -->
-    <!--  field-names=""  :options="placeOptions" -->
-
-    <van-field name="rate" :label-width="labelWidth" label="推荐指数">
-      <template #input>
-        <van-rate
-          color="#ffd21e"
-          :icon="rate"
-          void-icon="star"
-          void-color="#eee"
-          v-model="recommendationRate"
-          clearable
-        />
+
+    <van-cell @click="showPublic = true" size="large" center is-link>
+      <template v-if="visibleRange == 1" #icon>
+        <span class="iconfont icon-lock text-[#FF9300] mr-12" style="font-size: 16px"></span>
       </template>
-    </van-field>
-
-    <van-field
-      :label-width="labelWidth"
-      v-model="averageCost"
-      name="averageCost"
-      autocomplete="off"
-      clearable
-      maxlength="10"
-      label="平均费用"
-      placeholder="请输入平均费用"
-    ></van-field>
-
-    <van-field
-      :label-width="labelWidth"
-      is-link
-      v-model="travelMode"
-      clearable
-      readonly
-      autocomplete="off"
-      label="出行方式"
-      placeholder="请选择出行方式"
-      @click="showtravelMode = true"
-    ></van-field>
-    <van-popup v-model:show="showtravelMode" destroy-on-close position="bottom">
-      <van-picker
-        :columns="travelModeOptions"
-        :columns-field-names="travelModeOptionsProps"
-        @confirm="onConfirmTravelMode"
-        @cancel="showtravelMode = false"
-      />
+      <template v-else #icon>
+        <span class="iconfont icon-unlock text-black-3 mr-12" style="font-size: 16px"></span>
+      </template>
+      <template v-if="visibleRange == 1" #title>
+        <span class="text-[#FF9300]">仅自己可见</span>
+      </template>
+      <template v-else #title>
+        <span>公开可见</span>
+      </template>
+    </van-cell>
+    <van-popup
+      style="--van-popup-background: #eeeeee"
+      class="py-16"
+      round
+      v-model:show="showPublic"
+      destroy-on-close
+      position="bottom"
+    >
+      <van-cell-group inset>
+        <van-cell @click="(visibleRange = 0), (showPublic = false)" title="公开可见" center>
+          <template #icon>
+            <span class="iconfont icon-unlock text-black-3 mr-12" style="font-size: 16px"></span>
+          </template>
+          <template v-if="visibleRange == 0" #right-icon>
+            <!-- <van-icon color="#FF9300" name="arrow-down" :size="16" /> -->
+            <img class="w-16 h-16" :src="check" alt="" />
+          </template>
+        </van-cell>
+        <van-cell @click="(visibleRange = 1), (showPublic = false)" title="仅自己可见" center>
+          <template #icon>
+            <span class="iconfont icon-lock text-black-3 mr-12" style="font-size: 16px"></span>
+          </template>
+          <template v-if="visibleRange == 1" #right-icon>
+            <!-- <van-icon color="#FF9300" name="arrow-down" :size="16" /> -->
+            <img class="w-16 h-16" :src="check" alt="" />
+          </template>
+        </van-cell>
+      </van-cell-group>
     </van-popup>
 
-    <van-field
-      :label-width="labelWidth"
-      v-model="travelNumber"
-      label="游玩人数"
-      clearable
-      autocomplete="off"
-      placeholder="请输入游玩人数"
-    ></van-field>
+    <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>
+      <template #value>
+        <p class="line-clamp-1 border border-transparent text-[#FF9300]">{{ chatGroupName }}</p>
+      </template>
+    </van-cell>
+    <van-popup
+      round
+      v-model:show="showChatGroup"
+      safe-area-inset-top
+      destroy-on-close
+      position="bottom"
+    >
+      <div class="h-390 w-full box-border py-16">
+        <div
+          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
+                tourImGroupId = checked
+              }
+            "
+          >
+            确认
+          </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">
+                  <MultiHeader
+                    v-if="item?.memberHeadImg"
+                    :size="44"
+                    :imgUrls="item?.memberHeadImg"
+                  />
+                </div>
+              </template>
+              <template #right-icon>
+                <van-radio checked-color="#FF9300" :name="item?.id" />
+              </template>
+            </van-cell>
+          </van-radio-group>
+        </van-list>
+      </div>
+    </van-popup>
+
+    <van-cell
+      @click="showFrom = !showFrom"
+      icon="shop-o"
+      size="large"
+      center
+      is-link
+      arrow-direction="down"
+    >
+      <template #icon>
+        <span class="iconfont icon-more text-black-3 mr-12" style="font-size: 16px"></span>
+      </template>
+      <template #title>
+        <span class="font-medium text-lg">更多参数</span>
+      </template>
+      <template #value>
+        <span v-if="!showFrom" class="text-black-3 text-base">展开</span>
+        <span v-else class="text-[#FF9300] text-base">收起</span>
+      </template>
+      <template #right-icon>
+        <van-icon v-if="!showFrom" name="arrow-down" :size="16" />
+        <span
+          v-else
+          class="iconfont icon-chevron-down text-[#FF9300]"
+          style="font-size: 16px"
+        ></span>
+      </template>
+    </van-cell>
+
+    <template v-if="showFrom">
+      <div class="flex items-center justify-center">
+        <van-field
+          v-model="departureTime"
+          :label-width="labelWidth"
+          name="calendar"
+          clearable
+          readonly
+          size="large"
+          label="出发时间"
+          autocomplete="off"
+          is-link
+          placeholder="请选择出发时间"
+          @click="showCalendar = true"
+        >
+          <!-- <template #right-icon>
+            <div class="w-24 h-24">
+              <van-image width="100%" height="100%" :src="calendar" />
+            </div>
+          </template> -->
+        </van-field>
+        <van-calendar
+          color="#FE8E2C"
+          :min-date="minDate"
+          :max-date="maxDate"
+          title="请选择出发时间"
+          type="single"
+          v-model:show="showCalendar"
+          @confirm="onConfirm"
+        />
+      </div>
+      <van-field
+        :label-width="labelWidth"
+        is-link
+        v-model="travelMode"
+        clearable
+        readonly
+        size="large"
+        autocomplete="off"
+        label="出行方式"
+        placeholder="请选择出行方式"
+        @click="showtravelMode = true"
+      ></van-field>
+      <van-popup round v-model:show="showtravelMode" destroy-on-close position="bottom">
+        <van-picker
+          :columns="travelModeOptions"
+          :columns-field-names="travelModeOptionsProps"
+          @confirm="onConfirmTravelMode"
+          @cancel="showtravelMode = false"
+        />
+      </van-popup>
+
+      <van-field
+        :label-width="labelWidth"
+        v-model="countTimes"
+        name="countTimes"
+        autocomplete="off"
+        size="large"
+        label="出发天数"
+        clearable
+        placeholder="请输入您的天数 例:4天"
+      ></van-field>
+
+      <van-field
+        :label-width="labelWidth"
+        v-model="travelNumber"
+        size="large"
+        label="游玩人数"
+        clearable
+        autocomplete="off"
+        placeholder="请输入游玩人数"
+      ></van-field>
+      <van-field
+        :label-width="labelWidth"
+        v-model="role"
+        label="人物关系"
+        clearable
+        size="large"
+        autocomplete="off"
+        placeholder="例:情侣"
+      ></van-field>
+      <van-field
+        :label-width="labelWidth"
+        v-model="averageCost"
+        name="averageCost"
+        autocomplete="off"
+        clearable
+        size="large"
+        maxlength="10"
+        label="平均费用"
+        placeholder="请输入平均费用"
+      ></van-field>
+      <van-field name="rate" size="large" :label-width="labelWidth" label="推荐指数">
+        <template #input>
+          <van-rate
+            color="#ffd21e"
+            :icon="rate"
+            void-icon="star"
+            void-color="#eee"
+            v-model="recommendationRate"
+            clearable
+          />
+        </template>
+      </van-field>
+    </template>
+    <template v-else></template>
   </div>
 </template>
 
 <script setup>
-import calendar from '~/assets//img/note-create/calendar.png'
+// import calendar from '~/assets//img/note-create/calendar.png'
+import check from '~/assets//img/note-create/check.svg'
 import rate from '~/assets//img/note-create/rate.svg'
 
 const departureTime = defineModel('departureTime')
@@ -168,18 +280,28 @@ const averageCost = defineModel('averageCost')
 const recommendationRate = defineModel('recommendationRate')
 const travelModeId = defineModel('travelMode')
 const travelNumber = defineModel('travelNumber')
+const chau = defineModel('chau')
+const chauId = defineModel('chauId')
+const visibleRange = defineModel('visibleRange') //是否公开
+const tourImGroupId = defineModel('tourImGroupId') //是否公开
 
 onMounted(() => {
   getPlaceOptions()
   getTravelModeOptions()
+  getChatGroupList()
 })
 
-const labelWidth = '68px'
+const labelWidth = '81px'
 // 出发时间
 const minDate = new Date(2010, 0, 1)
 const maxDate = new Date()
 
 const showCalendar = ref(false)
+const showFrom = ref(false) //是否显示整个表单
+const showPublic = ref(false) //是否显示公开
+
+const showChatGroup = ref(false) //是否显示群聊
+const checked = ref('') //是否显示群聊
 
 // 展示时间的格式
 const onConfirm = (date) => {
@@ -216,8 +338,13 @@ const showPickerTest = ref('')
 const showPicker = ref(false)
 const onConfirmAddr = ({ selectedValues, selectedOptions }) => {
   showPicker.value = false
+
   endPlace.value = selectedOptions[selectedValues.length - 1].menuName
   endPlaceId.value = selectedOptions[selectedValues.length - 1].id
+  chau.value = selectedOptions[0].menuName
+  chauId.value = selectedOptions[0].id
+
+  // endPlaceId.value = selectedOptions[selectedValues.length - 1].menuName
 }
 
 // 出行方式
@@ -240,6 +367,36 @@ async function getTravelModeOptions() {
   const { data } = await request('/admin/app/extra/listDict?dictCode=TourTravelMode')
   travelModeOptions.value = data
 }
+
+// 获取自己的群聊
+const chatGroupList = ref([])
+async function getChatGroupList() {
+  try {
+    // 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>

+ 148 - 0
src/components/CreateNote/HeaderImage.vue

@@ -0,0 +1,148 @@
+<template>
+  <div
+    style="overflow: hidden; overflow-x: scroll"
+    class="w-full imgUrls box-border px-12 pr-12 pt-8"
+  >
+    <div :class="`${show ? 'h-40 ' : 'h-74 '} flex justify-start items-center box-border pr-12`">
+      <div
+        v-for="(item, index) in imgUrls"
+        :key="index"
+        :class="`${show ? 'w-40 ' : 'w-74 '} h-full shrink-0 box-border rounded-lg overflow-hidden mr-8 relative`"
+        @click="lookImage(index)"
+      >
+        <img class="w-full h-full object-cover" :src="item" alt="" />
+        <div
+          class="absolute top-0 right-0 z-1 w-14 h-14 bg-black/[0.5] rounded-bl-lg text-white flex justify-center items-cneter text-[10px]"
+        >
+          {{ index + 1 }}
+        </div>
+      </div>
+
+      <div
+        :class="`${show ? 'w-40' : 'w-74 '} h-full shrink-0 bg-[#F3F3F3] box-border rounded-lg flex justify-center items-center`"
+        @click.stop="handleSelectImage"
+      >
+        <span class="iconfont icon-plus text-black/[0.4] font-[800]" style="font-size: 28px"></span>
+      </div>
+    </div>
+
+    <van-image-preview
+      v-model:show="showPreview"
+      :startPosition="imageIndex"
+      :images="imgUrls"
+      @change="onChangeNewIndex"
+    >
+      <template v-slot:index>{{ imageIndex + 1 }}/{{ imgUrls.length }}</template>
+      <template v-slot:cover>
+        <div class="fixed bottom-32 right-12 flex justify-start items-center text-sm text-white">
+          <div
+            class="h-24 shrink-0 rounded-full bg-white/[0.3] px-8 py-4 mr-8"
+            @click.stop="setHeadImage"
+          >
+            <span class="border border-white px-5 py-2 rounded-[2px] text-[10px] mr-4">1</span>
+            设为首图
+          </div>
+          <div
+            @click.stop="deleteImage"
+            class="h-24 shrink-0 rounded-full bg-white/[0.3] px-8 py-2 flex items-center"
+          >
+            <span class="iconfont icon-delete-one text-white mr-4" style="font-size: 16px"></span>
+            <span>删除</span>
+          </div>
+        </div>
+      </template>
+    </van-image-preview>
+  </div>
+</template>
+
+<script setup>
+const imgUrls = defineModel('imgUrls')
+const show = defineModel('show')
+
+const { open, onChange } = useFileDialog({
+  accept: '.png,.png,.jpeg,.JPG,Png '
+})
+
+const showPreview = ref(false)
+const imageIndex = ref(0)
+
+function handleSelectImage() {
+  open()
+}
+
+onChange((files) => {
+  if (!files.length) return
+  handleCropperOk(files[0])
+})
+
+async function handleCropperOk(data) {
+  try {
+    // 此处需上传图片,保存URL
+    const formData = new FormData()
+    formData.append('uploadFile', data)
+    formData.append('asImage', true)
+    formData.append('fieldName', 'travelNotesBanner')
+    showLoadingToast({
+      message: '图片上传中...',
+      duration: 1000000
+    })
+
+    const res = await request('/admin/app/tourismProjectTravelNotesWrite/upload', {
+      method: 'post',
+      body: formData
+    })
+
+    imgUrls.value.push(res.data.fileUrl)
+
+    closeToast()
+  } catch (error) {
+    closeToast()
+    showToast('图片上传失败')
+    console.log(error)
+  } finally {
+  }
+}
+
+//切换图片
+const onChangeNewIndex = (newIndex) => {
+  imageIndex.value = newIndex
+}
+
+// 查看图片
+function lookImage(imgIndex) {
+  showPreview.value = true
+  imageIndex.value = imgIndex
+}
+
+//设置头图
+function setHeadImage() {
+  let url = imgUrls.value[imageIndex.value]
+  imgUrls.value.splice(imageIndex.value, 1)
+  imgUrls.value.unshift(url)
+  imageIndex.value = 0
+
+  showPreview.value = false
+}
+
+// 删除图片
+function deleteImage() {
+  showDialog({
+    width: 260,
+    title: '系统提示',
+    message: '确认删除这张照片吗?',
+    confirmButtonColor: '#FF9400',
+    showCancelButton: true
+  })
+    .then(() => {
+      imgUrls.value.splice(imageIndex.value, 1)
+      showPreview.value = false
+    })
+    .catch(() => {})
+}
+</script>
+
+<style lang="scss" scoped>
+.imgUrls::-webkit-scrollbar {
+  width: 0; /* 竖向滚动条的宽度 */
+}
+</style>

+ 122 - 0
src/components/CreateNote/Mention.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="demo">
+    <Mentionable
+      :keys="['#', '@']"
+      :items="items"
+      offset="6"
+      filtering-disabled
+      @open="loadIssues()"
+      @search="loadIssues($event)"
+    >
+      <textarea
+        v-model="text"
+        rows="6"
+        class="input"
+        placeholder="Enter text and then type # to trigger the mention"
+      />
+
+      <template #no-result>
+        <div class="dim">
+          {{ loading ? 'Loading...' : 'No result' }}
+        </div>
+      </template>
+
+      <template #item-#="{ item }">
+        <div class="issue">
+          <span class="number">#{{ item.value }}</span>
+          <span class="dim">
+            {{ item.label }}
+          </span>
+        </div>
+      </template>
+    </Mentionable>
+
+    <div class="preview">{{ text }}</div>
+  </div>
+</template>
+
+<script setup>
+import { Mentionable } from 'vue-mention'
+const text = ref('')
+const items = ref()
+const loading = ref(false)
+
+const issues = [
+  {
+    value: 123,
+    label: 'Error with foo bar'
+  },
+  {
+    value: 42,
+    label: 'Cannot read line'
+  },
+  {
+    value: 77,
+    label: 'I have a feature suggestion'
+  }
+]
+
+async loadIssues (searchText = null) {
+      loading.value = true
+     items.value = await fetchIssues(searchText)
+     loading.value = true
+}
+
+function fetchIssues (searchText = null) {
+  return new Promise(resolve => {
+    setTimeout(() => {
+      if (!searchText) {
+        resolve(issues)
+      } else {
+        const reg = new RegExp(searchText, 'i')
+        resolve(issues.filter(issue => reg.test(issue.label)))
+      }
+    }, 1000)
+  })
+}
+</script>
+
+<style lang="scss" scoped>
+.demo {
+  margin: 24px 0;
+}
+
+.input {
+  width: 100%;
+  border: #ccc 1px solid;
+  border-radius: 6px;
+  resize: vertical;
+  min-height: 42px;
+  padding: 12px;
+  box-sizing: border-box;
+  line-height: 1.2em;
+  font-size: inherit;
+}
+
+.issue {
+  padding: 4px 6px;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.mention-selected .issue {
+  background: rgb(139, 212, 255);
+}
+
+.issue .number {
+  font-family: monospace;
+}
+
+.dim {
+  color: #666;
+}
+
+.preview {
+  font-family: monospace;
+  white-space: pre-wrap;
+  margin-top: 12px;
+  padding: 12px;
+  background: #f8f8f8;
+  border-radius: 6px;
+}
+</style>

+ 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>

+ 7 - 10
src/components/Home/TravelNotes/Item.vue

@@ -13,19 +13,16 @@
         v-if="itemData.isOriginal === 1"
         class="absolute top-0 right-0 h-28 w-60 bg-[#ffffff80] rounded-bl-xl flex items-center justify-center"
       >
-        <img
-          src="~/assets/img/home/original_label.png"
-          class="inline-block h-20 object-cover"
-        />
+        <img src="~/assets/img/home/original_label.png" class="inline-block h-20 object-cover" />
       </div>
     </van-image>
-    <div class="px-10">
+    <div class="box-border h-52 px-10">
       <div class="truncate w-full mt-8 font-semibold text-black text-base">
         {{ itemData.projectTitle }}
       </div>
-      <div class="truncate w-full mt-8 text-black-3 text-sm">
+      <!-- <div class="truncate w-full mt-8 text-black-3 text-sm">
         {{ itemData.remarks }}
-      </div>
+      </div> -->
     </div>
   </NuxtLink>
 </template>
@@ -34,9 +31,9 @@
 defineProps({
   itemData: {
     type: Object,
-    default: () => ({}),
-  },
-});
+    default: () => ({})
+  }
+})
 </script>
 
 <style lang="scss" scoped></style>

+ 11 - 18
src/components/Home/TravelNotes/index.client.vue

@@ -1,10 +1,6 @@
 <template>
   <div class="px-20 relative">
-    <HomeSectionHeader
-      title="旅行游记"
-      subTitle="Hot items"
-      more-to-url="/travel-notes"
-    />
+    <HomeSectionHeader title="旅行游记" subTitle="Hot items" more-to-url="/travel-notes" />
     <swiper-container ref="containerRef" class="swiper">
       <swiper-slide v-for="(item, index) in travelNotesList" :key="item.id">
         <HomeTravelNotesItem :itemData="item" />
@@ -14,10 +10,7 @@
           to="/travel-notes"
           class="border aspect-[267/230] border-[#DFE0E4] rounded-xl bg-[#FAFAFA] flex flex-col items-center justify-center text-xl text-black-3"
         >
-          <span
-            class="iconfont icon-arrow_right"
-            style="font-size: 24px"
-          ></span>
+          <span class="iconfont icon-arrow_right" style="font-size: 24px"></span>
           <span>了解更多</span>
         </NuxtLink>
       </swiper-slide>
@@ -61,28 +54,28 @@
 <script setup>
 const { data } = await useMyFetch(
   `website/tourism/projectTravelNotes/homeList?pageNum=1&pageSize=10`
-);
-const travelNotesList = computed(() => data.value?.dataList ?? []);
+)
+const travelNotesList = computed(() => data.value?.dataList ?? [])
 
-const containerRef = ref(null);
+const containerRef = ref(null)
 const swiper = useSwiper(containerRef, {
   autoplay: {
-    delay: 2000,
+    delay: 2000
   },
   freeMode: {
-    enabled: true,
+    enabled: true
   },
   // freeMode: true,
   slidesPerView: 1.2,
-  spaceBetween: 17,
-});
+  spaceBetween: 17
+})
 
 function handleLeftClick() {
-  swiper.prev();
+  swiper.prev()
 }
 
 function handleRightClick() {
-  swiper.next();
+  swiper.next()
 }
 </script>
 

+ 1 - 1
src/components/NavigationBar/LeftMenu.vue

@@ -151,7 +151,7 @@ const profileMenu = [
   },
   {
     title: '我的收藏',
-    to: '/profile/collection'
+    to: '/profile/collection?tab=travelNotes'
   },
 
   {

+ 56 - 0
src/components/Profile/Collection/Comment.vue

@@ -0,0 +1,56 @@
+<template>
+  <!-- 评论 -->
+  <NuxtLink
+    :to="`/yj/${itemData.travelNoteId}`"
+    class="bg-white p-10 box-border flex flex-wrap space-x-10 rounded-xl"
+  >
+    <div class="flex-1 w-0">
+      <div class="flex">
+        <div @click.prevent="" class="w-32 h-32 shrink-0 border rounded-full mr-8 overflow-hidden">
+          <img
+            v-if="itemData?.headImage"
+            :src="itemData?.headImage"
+            class="w-full h-full object-cover"
+            alt=""
+          />
+          <img v-else :src="defaultAvatar" class="w-full h-full object-cover" alt="" />
+        </div>
+        <div>
+          <p class="text-black-6 text-sm mb-4 line-clamp-1">{{ itemData?.createName }}</p>
+          <p class="line-clamp-1 text-black-3 text-xl">{{ itemData?.commentContent }}</p>
+        </div>
+      </div>
+    </div>
+    <van-image
+      :src="formatImgSrc(itemData?.notice?.tourismUrlsAfterConvert) || noteDraftCoverBg"
+      width="71px"
+      height="47px"
+      radius="4px"
+      class="shrink-0"
+    ></van-image>
+    <div class="w-full flex justify-end">
+      <div
+        @click.prevent="$emit('onCancel')"
+        class="flex mt-20 font-semibold items-center justify-center h-25 border-current text-[#FF9300] text-sm border w-88 rounded-full mt-10"
+      >
+        取消收藏
+      </div>
+    </div>
+  </NuxtLink>
+</template>
+
+<script setup>
+import defaultAvatar from '~/assets/img/default_avatar.png'
+import noteDraftCoverBg from '~/assets/img/note-create/note_draft_cover_bg.jpg'
+
+defineProps({
+  itemData: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const emit = defineEmits(['onCancel'])
+</script>
+
+<style lang="scss" scoped></style>

+ 47 - 0
src/components/Profile/Collection/Topic.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 话题 -->
+  <NuxtLink
+    :to="`/topic?topicName=${itemData.name}`"
+    class="bg-white p-10 box-border flex space-x-10 rounded-xl"
+  >
+    <van-image
+      :src="topic"
+      width="100px"
+      height="100px"
+      radius="8px"
+      class="shrink-0 mr-4"
+    ></van-image>
+
+    <div class="flex-1 w-0 relative">
+      <div class="line-clamp-2 text-black-3 text-base font-semibold mb-4">
+        {{ itemData.name }}
+      </div>
+      <div class="mt-5 text-sm text-black-6">
+        <span class="iconfont icon-eye text-black-9 mr-5" style="font-size: 12px"></span>
+
+        {{ transferCount(itemData.viewCount) }}
+      </div>
+
+      <div
+        @click.prevent="$emit('onCancel')"
+        class="absolute bottom-0 right-0 flex mt-20 font-semibold items-center justify-center h-25 border-current text-[#FF9300] text-sm border w-88 rounded-full mt-10"
+      >
+        取消收藏
+      </div>
+    </div>
+  </NuxtLink>
+</template>
+
+<script setup>
+import topic from '~/assets/img/topic/topic.png'
+defineProps({
+  itemData: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const emit = defineEmits(['onCancel'])
+</script>
+
+<style lang="scss" scoped></style>

+ 19 - 21
src/components/Profile/Collection/TravelNoteCell.vue

@@ -1,41 +1,39 @@
 <template>
-  <NuxtLink
-    :to="`/yj/${itemData.id}`"
-    class="bg-white p-10 box-border flex space-x-10 rounded-xl"
-  >
+  <!-- 游记 -->
+  <NuxtLink :to="`/yj/${itemData.id}`" class="bg-white p-10 box-border flex space-x-10 rounded-xl">
     <van-image
-      :src="formatImgSrc(itemData.tourismUrlsAfterConvert)"
-      width="155px"
-      height="115px"
-      radius="10px"
+      :src="formatImgSrc(itemData.tourismUrlsAfterConvert) || noteDraftCoverBg"
+      width="120px"
+      height="90px"
+      radius="8px"
       class="shrink-0"
     ></van-image>
     <div class="flex-1 w-0">
-      <div class="truncate text-black-3 text-xl">
+      <div class="line-clamp-2 text-black-3 text-base font-semibold">
         {{ itemData.projectTitle }}
       </div>
-      <div class="line-clamp-3 mt-5 text-sm text-black-6">
-        {{ itemData.remarks }}
-      </div>
-      <div
-        @click.prevent="$emit('onCancel')"
-        class="flex items-center justify-center h-25 border-current text-[#FF4242] text-sm border w-64 rounded-md mt-10"
-      >
-        取消收藏
+      <div class="flex justify-end">
+        <div
+          @click.prevent="$emit('onCancel')"
+          class="flex mt-20 font-semibold items-center justify-center h-25 border-current text-[#FF9300] text-sm border w-88 rounded-full mt-10"
+        >
+          取消收藏
+        </div>
       </div>
     </div>
   </NuxtLink>
 </template>
 
 <script setup>
+import noteDraftCoverBg from '~/assets/img/note-create/note_draft_cover_bg.jpg'
 defineProps({
   itemData: {
     type: Object,
-    default: () => {},
-  },
-});
+    default: () => {}
+  }
+})
 
-const emit = defineEmits(["onCancel"]);
+const emit = defineEmits(['onCancel'])
 </script>
 
 <style lang="scss" scoped></style>

+ 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/components/Profile/Notes/Auditing/Item.vue

@@ -1,7 +1,7 @@
 <template>
   <van-swipe-cell>
     <div class="relative flex mb-10 border-[#fff] space-x-10 p-10 rounded-xl bg-[#FFF]">
-      <div class="w-147 h-109 border-box">
+      <div class="w-94 h-70 overflow-hidden rounded-lg border-box">
         <img
           :src="formatImgSrc(data?.tourismUrlsAfterConvert) || noteDraftCoverBg"
           class="w-full h-full shrink-0 object-cover"

+ 2 - 2
src/components/Profile/Notes/Draft/Item.vue

@@ -1,9 +1,9 @@
 <template>
   <van-swipe-cell>
     <div class="relative flex space-x-10 p-10 mb-10 bg-[#fff] rounded-xl">
-      <div class="w-147 h-109 border-box">
+      <div class="w-94 h-70 overflow-hidden rounded-lg border-box">
         <img
-          :src="formatImgSrc(data?.tourismUrlsAfterConvert) || noteDraftCoverBg"
+          :src="formatImgSrc(data?.imageUrl) || noteDraftCoverBg"
           class="w-full h-full shrink-0 object-cover"
         />
       </div>

+ 4 - 2
src/components/Profile/Notes/Draft/index.vue

@@ -47,11 +47,13 @@ async function getNotesList() {
   setLoading(true)
 
   try {
-    let { data } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+    // let { data } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+    let { data } = await request('/website/tourism/travelNotesTopic/getTravelNotesByState', {
       query: {
         pageNum: pageNum.value,
         pageSize: 10,
-        type: 0
+        // type: 0
+        state: 0
       }
     })
 

+ 32 - 15
src/components/Profile/Notes/Published/Item.vue

@@ -1,37 +1,36 @@
 <template>
   <van-swipe-cell>
-    <div class="relative group flex border-box p-10 mb-10 bg-[#fff] rounded-xl">
-      <div class="w-147 h-109 border-box">
+    <div class="relative group flex border-box p-12 mb-10 bg-[#fff] rounded-lg">
+      <div class="w-94 h-70 overflow-hidden border-box rounded-lg relative">
         <img
-          :src="formatImgSrc(data.tourismUrlsAfterConvert) || noteDraftCoverBg"
+          :src="formatImgSrc(data.imageUrl) || noteDraftCoverBg"
           class="w-full h-full shrink-0 object-cover"
         />
+        <div
+          v-if="data.isTop == 1"
+          class="absolute top-8 left-8 px-8 py-2 rounded-full text-white text-sm bg-[#F99406]/[0.6]"
+        >
+          置顶
+        </div>
       </div>
       <div class="w-152 ml-15">
-        <div class="min-h-70 w-full">
+        <div class="min-h-44 w-full">
           <NuxtLink
             :title="data?.projectTitle"
             :to="`/yj/${data?.id}`"
-            class="line-clamp-1 break-all text-base font-bold text-black-3 text-bold"
+            class="line-clamp-2 break-all text-base font-bold text-black-3 text-bold"
           >
             {{ data?.projectTitle }}
           </NuxtLink>
-          <div class="line-clamp-3 text-sm leading-[17px] break-all text-black-6">
-            {{ data?.remarks }}
-          </div>
         </div>
         <div class="flex space-x-4 text-sm text-[#FD9A00]">
           <div class="flex items-center space-x-2">
             <span class="iconfont icon-eye-fill text-[#FD9A00]" style="font-size: 15px"></span>
-            <div>{{ data?.pageViewCount ?? 0 }}</div>
+            <div>{{ transferCount(data?.pageViewCount) ?? 0 }}</div>
           </div>
           <div class="pl-20 flex items-center space-x-2">
             <van-icon @click="$emit('onShare')" name="share-o" color="#FD9A00" />
           </div>
-          <!-- <div v-if="data?.endPlaceDictMap" class="flex items-center space-x-2">
-            <span class="iconfont icon-location-fill text-black-9" style="font-size: 15px"></span>
-            <div>{{ data?.endPlaceDictMap?.name }}</div>
-          </div> -->
         </div>
       </div>
 
@@ -46,6 +45,15 @@
           text="下架"
           @click="$emit('onNoteDown')"
           type="danger"
+          color="#E37318"
+          class="delete-button"
+        />
+        <van-button
+          square
+          :text="showText(data.isTop)"
+          @click="$emit('onPinned', data)"
+          type="danger"
+          color="#D54941"
           class="delete-button"
         />
       </div>
@@ -63,8 +71,17 @@ const props = defineProps({
   }
 })
 
-defineEmits(['onNoteDown', 'onShare'])
-//
+defineEmits(['onNoteDown', 'onShare', 'onPinned'])
+
+// 展示置顶 是的文案
+// showText
+function showText(state) {
+  if (state == 1) {
+    return '取消置顶'
+  } else {
+    return '置顶'
+  }
+}
 </script>
 
 <style lang="scss" scoped>

+ 41 - 12
src/components/Profile/Notes/Published/index.vue

@@ -1,7 +1,6 @@
 <template>
   <div class="w-full box-border pb-10 px-1">
-    <!-- style="height: calc(100vh - 105px);" -->
-    <!-- 发布中 -->
+    <!-- 已发布 -->
     <ProfileNotesEmpty v-if="!noteList.length" />
     <div v-else-if="noteList.length">
       <van-list
@@ -16,10 +15,11 @@
       >
         <ProfileNotesPublishedItem
           v-for="item in noteList"
-          :key="item.id"
+          :key="item?.id"
           :data="item"
           @on-note-down="handleNoteDown(item)"
           @on-share="changeShowShare(item)"
+          @on-pinned="onPinned"
         />
       </van-list>
     </div>
@@ -29,7 +29,6 @@
 </template>
 
 <script setup>
-// import wx from 'weixin-js-sdk'
 const showShare = ref(false)
 
 const options = [
@@ -128,22 +127,33 @@ const getloadList = () => {
 async function getList() {
   setLoading(true)
   try {
-    let { data } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+    // let { data } = await request('/website/tourism/publishTravelNotes/getDraftList', {
+    let { data } = await request('/website/tourism/travelNotesTopic/getTravelNotesByState', {
       query: {
         pageNum: pageNum.value,
         pageSize: 10,
-        type: 3
+        // type: 3
+        state: 3
       }
     })
 
-    if (data.dataList.length == 0) noteList.value = []
+    // if (data.dataList.length == 0) noteList.value = []
 
-    // 去重处理
-    if (noteList.value.length > data.totalCount)
-      noteList.value = Array.from(new Set([...noteList.value, ...data.dataList]))
-    // 去重处理合并处理
-    if (noteList.value.length < data.totalCount)
+    // // 去重处理
+    // if (noteList.value.length > data.totalCount)
+    //   noteList.value = Array.from(new Set([...noteList.value, ...data.dataList]))
+    // // 去重处理合并处理
+    // if (noteList.value.length < data.totalCount)
+    //   noteList.value = noteList.value.concat(data.dataList)
+
+    if (Array.isArray(data?.dataList) && data.dataList.length) {
       noteList.value = noteList.value.concat(data.dataList)
+      nextTick(() => {
+        noteList.value = [...new Map(noteList.value.map((item) => [item?.id, item])).values()]
+      })
+    } else {
+      noteList.value = []
+    }
 
     loading.value = false
     if (noteList.value.length >= data.totalCount) {
@@ -182,6 +192,25 @@ async function handleNoteDown(item) {
     })
 }
 
+// 是否置顶
+async function onPinned(item) {
+  let body = {}
+  body.id = item.id
+  if (item.isTop == 1) {
+    body.isTop = 0
+  } else {
+    body.isTop = 1
+  }
+  const res = await request('/website/tourism/travelNotesTopic/toTop', {
+    method: 'post',
+    body
+  })
+
+  if (res && res.success) {
+    getList()
+  }
+}
+
 onMounted(() => {
   getList()
 })

+ 1 - 1
src/components/Profile/Notes/Rejected/Item.vue

@@ -1,7 +1,7 @@
 <template>
   <van-swipe-cell>
     <div class="relative group flex space-x-10 p-10 mb-10 bg-[#fff] rounded-xl">
-      <div class="w-147 h-109 border-box">
+      <div class="w-94 h-70 overflow-hidden rounded-lg border-box">
         <img
           :src="formatImgSrc(data?.tourismUrlsAfterConvert) || noteDraftCoverBg"
           class="w-full h-full shrink-0 object-cover"

+ 13 - 16
src/components/Profile/Notes/Tabs.vue

@@ -1,19 +1,13 @@
 <template>
-  <div>
-    <div class="flex items-center space-x-7 bg-[#F8F8F8] py-16">
-      <div
-        v-for="tab in tabs"
-        :key="tab.lable"
-        @click="handleClick(tab)"
-        class="flex w-78 h-34 text-14 cursor-pointer items-center justify-center rounded-full text-base transition-all"
-        :class="[
-          currentTab == tab.name ? 'bg-primary text-white font-bold' : 'bg-yellow text-black-3'
-        ]"
-      >
-        {{ tab.lable }}
-      </div>
-    </div>
-  </div>
+  <van-tabs
+    title-active-color="#FF9300"
+    title-inactive-color="#333333"
+    :active="active"
+    @click-tab="handleClick"
+    style="--van-tabs-bottom-bar-color: #ff9300; --van-tabs-bottom-bar-width: 30px; width: 100%"
+  >
+    <van-tab v-for="tab in tabs" :key="tab?.name" :title="tab?.lable"></van-tab>
+  </van-tabs>
 </template>
 
 <script setup>
@@ -25,8 +19,11 @@ const props = defineProps({
 })
 
 const currentTab = useRouteQuery('tab')
+// 下标
+const active = computed(() => props.tabs?.findIndex((item) => item?.name == currentTab.value))
 
-function handleClick(tab) {
+function handleClick({ title }) {
+  let tab = props.tabs?.find((item) => item?.lable == title)
   navigateTo({
     query: {
       tab: tab.name

+ 0 - 2
src/pages/chat/group-chat.vue

@@ -379,7 +379,6 @@ async function getAnnouncement() {
     if (Array.isArray(data.memberList) && data?.memberList?.length) {
       data.memberList.map((el) => {
         if (el.userId == userInfo.value.userId) {
-          console.log(el, 'el  前')
           // 头部的名称已自己的备注名优先
           if (el?.groupRemark) {
             el.groupName = el.groupRemark
@@ -387,7 +386,6 @@ async function getAnnouncement() {
             el.groupName = data?.groupName
           }
 
-          console.log(el, 'el  后')
           groupMemberInfo.value = el
         }
       })

+ 0 - 2
src/pages/chat/single-chat.vue

@@ -247,8 +247,6 @@ const sendImageMessage = async (file) => {
 }
 
 const handleSendMessage = async ({ type, messageContent }) => {
-  console.log(131)
-
   try {
     switch (type) {
       case 'text':

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 389 - 468
src/pages/note-create/index.client.vue


+ 318 - 0
src/pages/profile-others/[id].vue

@@ -0,0 +1,318 @@
+<template>
+  <div>
+    <div class="h-48 flex justify-between items-center bg-white px-12">
+      <span
+        @click="goToBack"
+        class="iconfont icon-left text-black-3 font-[600]"
+        style="font-size: 24px"
+      ></span>
+
+      <span></span>
+    </div>
+
+    <div
+      class="relative w-full h-176 box-border pt-20 pl-16 pb-16 pr-12 bg-[url('~/assets/img/profile/profile_banner.png')] bg-no-repeat bg-cover"
+    >
+      <div class="absolute top-0 left-0 w-full h-full bg-white/[0.6] pt-20 pl-16 pb-16 pr-12">
+        <div class="flex justify-start mb-12">
+          <div class="w-64 h-64 shrink-0 rounded-full relative">
+            <img
+              v-if="othersUserInfo?.headImageUrl"
+              class="w-full h-full object-cover rounded-full"
+              :src="othersUserInfo?.headImageUrl"
+              alt=""
+            />
+            <div
+              v-if="othersUserInfo?.sex"
+              class="absolute -bottom-10 left-1/2 -translate-x-1/2 z-2 w-20 h-20 rounded-full bg-white flex justify-center items-cneter"
+            >
+              <span
+                v-if="othersUserInfo?.sex == 2"
+                class="iconfont icon-Female text-[#FF0FE3]"
+                style="font-size: 14px"
+              ></span>
+              <span
+                v-if="othersUserInfo?.sex == 1"
+                class="iconfont icon-Male text-[#0F8FFF]"
+                style="font-size: 14px"
+              ></span>
+            </div>
+          </div>
+
+          <div class="ml-8">
+            <h1 class="text-black-3 font-medium text-xl mb-8">{{ othersUserInfo?.showName }}</h1>
+            <p class="text-sm line-clamp-2 text-black-3">
+              {{
+                othersUserInfo?.personalSign
+              }}asdjvaghsdavgshdsdahsd2asbdjhasd卢卡斯百度哈桑广大萨达撒看见是大家说的噶话说的说的话京噶手机号大噶十九大
+            </p>
+          </div>
+        </div>
+
+        <div class="w-full flex justify-between text-[13px]">
+          <div>
+            <span class="text-black-9 mr-4">关注</span>
+            <span class="text-black-3 font-medium">
+              {{ transferCount(othersUserInfo?.numberOfConcern) }}
+            </span>
+          </div>
+          <div>
+            <span class="text-black-9 mr-4">粉丝</span>
+            <span class="text-black-3 font-medium">
+              {{ transferCount(othersUserInfo?.numberOfFollowers) }}
+            </span>
+          </div>
+          <div>
+            <span class="text-black-9 mr-4">获赞</span>
+            <span class="text-black-3 font-medium">
+              {{ transferCount(othersUserInfo?.praiseNum) }}
+            </span>
+          </div>
+        </div>
+
+        <div class="mt-10 flex justify-between">
+          <button
+            @click="
+              navigateTo({
+                path: `/view-group-chat/${id}`
+              })
+            "
+            class="border-[#FD9A00] border rounded-full text-sm text-[#FD9A00] py-6 px-12 bg-transparent"
+          >
+            查看群聊
+          </button>
+          <div class="flex items-center">
+            <van-button
+              v-if="othersUserInfo?.state == 0 || othersUserInfo?.state == 4"
+              style="width: 72px; height: 28px"
+              size="small"
+              type="primary"
+              round
+              color="#FD9A00"
+              @click="handleFollow(othersUserInfo)"
+            >
+              {{ followState(othersUserInfo?.state).text }}
+            </van-button>
+
+            <button
+              v-if="othersUserInfo?.state == 1 || othersUserInfo?.state == 2"
+              class="border-black-9 border rounded-full text-sm text-black-9 py-6 px-12 bg-transparent"
+              @click="handleFollow(othersUserInfo)"
+            >
+              {{ followState(othersUserInfo?.state).text }}
+            </button>
+            <van-button
+              style="width: 72px; height: 28px; margin-left: 12px"
+              size="small"
+              type="primary"
+              round
+              color="#999"
+              @click="
+                handlePersonalLetter({
+                  getUserId: othersUserInfo?.userId,
+                  noticeType: 1
+                })
+              "
+            >
+              私信
+            </van-button>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <van-list
+      v-if="notesList?.length"
+      v-model:loading="loading"
+      :immediate-check="false"
+      :finished="finished"
+      loading-text="加载中..."
+      error-text="获取失败"
+      @load="loadMore"
+    >
+      <div class="w-full box-border py-16 px-12 flex justify-between flex-wrap">
+        <NuxtLink
+          v-for="(i, index) in notesList"
+          :key="i?.id"
+          class="w-[49%] box-border mb-12"
+          :to="`/yj/${i.id}`"
+        >
+          <div class="relative w-172 h-172 rounded-2xl overflow-hidden mb-8">
+            <img class="w-full h-full object-cover" :src="i?.tourismUrl" alt="" />
+
+            <div
+              v-if="i.isTop == 1"
+              class="absolute top-12 left-12 text-white bg-[#F99406]/[0.6] text-sm box-border px-8 py-2 rounded-full"
+            >
+              置顶
+            </div>
+          </div>
+
+          <div class="truncate w-full text-[14px] font-bold mb-8">
+            <img
+              v-if="i?.isOriginal == 1"
+              src="~/assets/img/yuanchuang.png"
+              class="mt-3 w-30 h-16"
+              alt=""
+              style="float: left"
+            />
+            {{ i?.projectTitle }}
+          </div>
+          <div class="flex justify-between items-center box-border mr-8 overflow-hidden">
+            <div class="flex shrink-0 justify-start items-center">
+              <div class="w-18 h-18 shrink-0 rounded-full overflow-hidden">
+                <img class="w-full h-full object-cover" :src="i?.image" alt="" />
+              </div>
+              <span class="w-[70%] ml-4 text-black-9 text-sm">{{ i?.name }}</span>
+            </div>
+
+            <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>
+        </NuxtLink>
+      </div>
+    </van-list>
+    <Empty v-else title="暂无游记" />
+  </div>
+</template>
+<script setup>
+const id = useRouteParam('id')
+const router = useRouter()
+const userInfoStore = useUserInfoStore()
+const { userInfo } = storeToRefs(userInfoStore)
+
+const othersUserInfo = ref(null) //他人信息
+const notesList = ref([]) //下方游记
+const pageNum = ref(1)
+const pageSize = ref(10)
+const loading = ref(false)
+const finished = ref(false)
+// 关注
+const saveLoading = ref(false)
+const handleFollow = async (item) => {
+  try {
+    if (saveLoading.value) return
+    saveLoading.value = true
+    const { data } = await request(`/website/tourism/fans/saveConcern`, {
+      method: 'post',
+      body: {
+        attentionId: item.userId
+      }
+    }).finally(() => {
+      saveLoading.value = false
+    })
+    if (!data) return
+    othersUserInfo.value.state = data.fansStatus
+    showSuccessToast('操作成功')
+  } catch (e) {
+    showToast('操作失败')
+  } finally {
+    saveLoading.value = false
+  }
+}
+
+// 随机生成的唯一id
+function getLocalId() {
+  const random = Math.floor(Math.random() * 10000)
+  return Date.now() + '' + random
+}
+
+// 私信
+const handlePersonalLetter = async (body) => {
+  body.groupId = getLocalId()
+
+  body.sendUserId = userInfo.value.userId
+  const { data } = await request('/website/tourGroup/createMember', {
+    method: 'post',
+    body
+  })
+  if (data) {
+    navigateTo({
+      path: '/profile/my-news',
+      replace: true
+    })
+  }
+}
+
+// 获取他人主页的信息
+async function getHomePageDetailsDto() {
+  const { data } = await request('/website/tourism/travelNotesTopic/homePageDetailsDto', {
+    query: {
+      userId: id.value
+    }
+  })
+
+  if (data) {
+    othersUserInfo.value = data
+  }
+}
+
+function goToBack() {
+  router.back()
+}
+
+function loadMore() {
+  pageNum.value++
+  getTravelNotes()
+}
+
+// 分页查询他人主页的游记
+async function getTravelNotes() {
+  const param = {
+    pageNum: pageNum.value,
+    pageSize: pageSize.value
+  }
+
+  loading.value = true
+  const {
+    data: { dataList, totalCount }
+  } = await request('/website/tourism/travelNotesTopic/getTravelNotes', {
+    query: {
+      ...param,
+      userId: id.value
+    }
+  })
+
+  if (Array.isArray(dataList) && dataList.length) {
+    notesList.value = dataList
+    loading.value = false
+  } else {
+    loading.value = true
+    notesList.value = []
+  }
+
+  if (notesList.value.length >= totalCount) {
+    finished.value = true
+  } else {
+    finished.value = false
+  }
+}
+
+// 关注状态
+function followState(params) {
+  if (params == 0 || params == 4) {
+    return {
+      color: 'text-[#FD9A00] border-[#FD9A00]',
+      text: '关注'
+    }
+  }
+
+  if (params == 1 || params == 2) {
+    return {
+      color: 'text-black-9 border-black-9',
+      text: '已关注'
+    }
+  }
+}
+
+onMounted(() => {
+  getHomePageDetailsDto()
+  getTravelNotes()
+})
+</script>
+<style lang="scss" scoped></style>

+ 177 - 33
src/pages/profile/collection.client.vue

@@ -1,9 +1,13 @@
 <template>
+  <ProfileNotesTabs :tabs="tabs"></ProfileNotesTabs>
   <template v-if="!listData.length && !loading">
-    <van-empty description="暂无收藏得游记" />
+    <van-empty :description="showText(tab)" />
   </template>
   <template v-else-if="listData.length">
-    <div class="bg-[#f8f8f8] px-15 min-h-screen pt-15 flex flex-col space-y-15">
+    <div
+      v-if="tab == 'travelNotes'"
+      class="bg-[#f8f8f8] px-15 min-h-screen pt-15 flex flex-col space-y-15"
+    >
       <ProfileCollectionTravelNoteCell
         v-for="item in listData"
         :key="item.id"
@@ -11,55 +15,195 @@
         @on-cancel="handleCancel(item)"
       />
     </div>
+    <div
+      v-if="tab == 'comment'"
+      class="bg-[#f8f8f8] px-15 min-h-screen pt-15 flex flex-col space-y-15"
+    >
+      <ProfileCollectionComment
+        v-for="item in listData"
+        :key="item.id"
+        :itemData="item"
+        @on-cancel="handleCommentCancel(item)"
+      />
+    </div>
+    <div
+      v-if="tab == 'topic'"
+      class="bg-[#f8f8f8] px-15 min-h-screen pt-15 flex flex-col space-y-15"
+    >
+      <ProfileCollectionTopic
+        v-for="item in listData"
+        :key="item.id"
+        :itemData="item"
+        @on-cancel="handleTopicCancel(item)"
+      />
+    </div>
   </template>
 </template>
 
 <script setup>
-onMounted(() => {
-  getCollectionList();
-});
+const tabs = [
+  {
+    lable: '游记',
+    name: 'travelNotes',
+    to: ''
+  },
+  {
+    lable: '评论',
+    name: 'comment',
+    to: ''
+  },
+  {
+    lable: '话题',
+    name: 'topic',
+    to: ''
+  }
+]
+const route = useRoute()
+const tab = useRouteQuery('tab')
+const listData = ref([])
 
-const listData = ref([]);
+const { loading, setLoading } = useLoading()
 
-const { loading, setLoading } = useLoading();
+function showText() {
+  if (tab.value == 'travelNotes') {
+    return '暂无收藏得游记'
+  }
+  if (tab.value == 'comment') {
+    return '暂无收藏得评论'
+  }
+  if (tab.value == 'topic') {
+    return '暂无收藏得话题'
+  }
+}
 
+// 获取收藏得游记
 async function getCollectionList() {
-  setLoading(true);
-  const { data } = await request(
-    "/website/tourism/projectTravelNotes/userCollectTravelNotesList",
-    {
-      query: {
-        pageSize: 999,
-        pageNum: 1,
-      },
+  setLoading(true)
+  const { data } = await request('/website/tourism/projectTravelNotes/userCollectTravelNotesList', {
+    query: {
+      pageSize: 999,
+      pageNum: 1
     }
-  );
-  setLoading(false);
-  listData.value = data.dataList;
+  })
+  setLoading(false)
+  listData.value = data.dataList
+}
+// 获取收藏得评论
+async function getCollectionListComment() {
+  setLoading(true)
+  const { data } = await request('/website/comment/tourTravelNotesComment/getCollectComments', {
+    query: {
+      pageSize: 999,
+      pageNum: 1
+    }
+  })
+  setLoading(false)
+  listData.value = data.dataList
+}
+// 获取收藏得话题
+async function getCollectionListTopic() {
+  setLoading(true)
+  const { data } = await request('/website/tourism/travelNotesTopic/getSpecialCollection')
+  setLoading(false)
+  listData.value = data
 }
 
+// 取消游记收藏
 function handleCancel(item) {
   showConfirmDialog({
-    title: "提示",
-    message: "确认取消收藏吗",
+    title: '提示',
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
   }).then(() => {
-    request(
-      "/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate",
-      {
-        method: "post",
-        body: {
-          travelNotesId: item.id,
-          type: 0,
-        },
+    request('/website/tourism/projectTravelNotes/userCollectTravelNotesUpdate', {
+      method: 'post',
+      body: {
+        travelNotesId: item.id,
+        type: 0
       }
-    )
+    })
       .then(() => {
-        showToast("取消收藏成功");
-        getCollectionList();
+        showToast('取消收藏成功')
+        getCollectionList()
       })
-      .catch(() => {});
-  });
+      .catch(() => {})
+  })
 }
+// 取消评论收藏
+function handleCommentCancel(item) {
+  showConfirmDialog({
+    title: '提示',
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
+  }).then(() => {
+    request('/website/comment/tourTravelNotesComment/commentCollectCancle', {
+      method: 'post',
+      body: item.id
+    })
+      .then(() => {
+        showToast('取消收藏成功')
+        getCollectionListComment()
+      })
+      .catch(() => {})
+  })
+}
+// 取消话题收藏
+function handleTopicCancel(item) {
+  showConfirmDialog({
+    title: '提示',
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
+  }).then(() => {
+    request('/website/tourism/travelNotesTopic/cancelCollection', {
+      method: 'post',
+      body: {
+        id: item.id
+      }
+    })
+      .then(() => {
+        showToast('取消收藏成功')
+        getCollectionListTopic()
+      })
+      .catch(() => {})
+  })
+}
+
+onMounted(() => {
+  if (tab.value == 'travelNotes') {
+    getCollectionList()
+  }
+  if (tab.value == 'comment') {
+    getCollectionListComment()
+  }
+  if (tab.value == 'topic') {
+    getCollectionListTopic()
+  }
+})
+
+watch(
+  tab,
+  (val) => {
+    if (val == 'travelNotes') {
+      getCollectionList()
+    }
+    if (val == 'comment') {
+      getCollectionListComment()
+    }
+    if (val == 'topic') {
+      getCollectionListTopic()
+    }
+    if (val) return
+
+    navigateTo({
+      path: route.fullPath,
+      query: {
+        tab: tabs[0].name
+      },
+      replace: true
+    })
+  },
+  { immediate: true }
+)
 </script>
 
 <style lang="scss" scoped></style>

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

@@ -133,7 +133,7 @@ const menuData = [
   {
     icon: profile_colection,
     label: '我的收藏',
-    to: '/profile/collection'
+    to: '/profile/collection?tab=travelNotes'
   },
   /*  {
       icon: profile_my_comment,

+ 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

+ 3 - 5
src/pages/profile/notes/index.vue

@@ -1,10 +1,8 @@
 <template>
-  <div ref="container" class="w-full min-h-screen box-border pb-16 px-20 bg-[#F8F8F8]">
-    <van-sticky :offset-top="50" :container="container">
-      <ProfileNotesTabs :tabs="tabs"></ProfileNotesTabs>
-    </van-sticky>
+  <div ref="container" class="w-full min-h-screen box-border pb-16 bg-[#F8F8F8]">
+    <ProfileNotesTabs :tabs="tabs"></ProfileNotesTabs>
 
-    <div class="w-full">
+    <div class="w-full px-20 pt-12">
       <van-pull-refresh style="height: 100%" v-model="loading" @refresh="onRefresh">
         <div v-if="tab === 'published'" class="w-full min-h-screen">
           <ProfileNotesPublished />

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

@@ -36,12 +36,11 @@ const openQrcode = async () => {
           width: 250,
           height: 250
         },
-        aspectRatio: window.visualViewport.height / window.visualViewport.width
+        aspectRatio: window.visualViewport.width / window.visualViewport.height
       }
       if (devices && devices.length) {
         // 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个
         let cameraId = devices[devices.length - 1].id //后置摄像头,一般最后一个是后置摄像头
-        cameraIds.value = cameraId
         scanInstance
           .start({ deviceId: { exact: cameraId } }, config, handleSuccess)
           .catch((errorMessage) => {

+ 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,// 关闭录音权限
-  }
-
-}

+ 328 - 0
src/pages/topic/index.vue

@@ -0,0 +1,328 @@
+<template>
+  <template v-if="showSearch">
+    <div class="text-center">不好意思,找不到这篇话题了~</div>
+    <div @click="goBack" class="text-center underline mt-10 cursor-pointer text-[#4B99EA]">
+      返回
+    </div>
+  </template>
+  <template v-else>
+    <div class="w-full h-48 flex justify-between items-center px-12 mb-12">
+      <van-icon @click="router.back()" name="arrow-left" color="#333333" size="24" />
+
+      <span
+        class="iconfont icon-share text-black-3 ml-12"
+        style="font-size: 24px"
+        @click="copyLink"
+      ></span>
+    </div>
+
+    <div class="px-12 flex justify-between items-start mb-16">
+      <div class="flex justify-start items-start">
+        <div class="w-63 h-63 mr-8">
+          <img class="w-full h-full object-cover" src="~/assets/img/topic/topic.png" alt="" />
+        </div>
+        <div>
+          <h1 v-if="topicData?.name" class="mb-8 text-black-3 font-medium text-3xl">
+            #{{ topicData?.name }}
+          </h1>
+          <p class="text-black-6 text-base font-medium">
+            <span class="mr-5">{{ transferCount(topicData?.viewCount) }} 浏览</span>
+            <span>{{ transferCount(topicData?.commentCount) }} 讨论</span>
+          </p>
+        </div>
+      </div>
+
+      <van-button
+        v-if="topicData?.isCollect"
+        type="primary"
+        style="height: 28px"
+        size="normal"
+        color="#FF9300"
+        round
+        @click="handleTopicCancel"
+      >
+        <span class="iconfont icon-star-fill text-white" style="font-size: 16px"></span>
+        已收藏
+      </van-button>
+      <van-button
+        v-else
+        type="primary"
+        style="height: 28px"
+        size="normal"
+        color="#333333"
+        plain
+        round
+        @click="handleCollection"
+      >
+        <span class="iconfont icon-star text-black-3" style="font-size: 16px"></span>
+        收藏
+      </van-button>
+    </div>
+
+    <div class="flex justify-between px-12 mb-12">
+      <h1 class="text-black-3 text-xl font-medium">
+        帖子 {{ transferCount(topicData?.travelNotesCount) }}
+      </h1>
+      <span class="text-sm text-black-6">
+        <span
+          @click="changeIsHotAndIsNew(0)"
+          :class="`${isHot == 0 ? 'text-black-3 font-semibold' : ' '}`"
+        >
+          最热
+        </span>
+        <span
+          @click="changeIsHotAndIsNew(1)"
+          :class="`${isHot == 1 ? 'text-black-3 font-semibold' : ' '} ml-12 `"
+        >
+          最新
+        </span>
+      </span>
+    </div>
+    <van-list
+      v-if="dataList.length"
+      v-model:loading="loading"
+      :immediate-check="false"
+      :finished="finished"
+      loading-text="加载中..."
+      error-text="获取失败"
+      @load="loadMore"
+    >
+      <!-- @load="loadMore" -->
+      <div class="flex justify-between flex-wrap px-12">
+        <template v-for="itemData in dataList">
+          <NuxtLink
+            class="w-[50%] relative cursor-pointer bg-white pb-10"
+            :to="`/yj/${itemData.id}`"
+          >
+            <div class="aspect-[172/172] h-172 shrink-0 rounded-2xl overflow-hidden bg-[#ddd] mb-8">
+              <img
+                v-if="itemData?.tourismUrl"
+                :src="itemData?.tourismUrl"
+                class="w-full h-full rounded-2xl object-cover"
+                alt=""
+                srcset=""
+              />
+              <img
+                v-else
+                src="~/assets/img/note-create/note_draft_cover_bg.jpg"
+                class="w-full h-full rounded-2xl object-cover"
+                alt=""
+                srcset=""
+              />
+            </div>
+            <div class="px-8 flex flex-col w-full justify-between">
+              <div class="truncate w-full text-base font-semibold text-black-3 mb-8">
+                <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 flex justify-between items-center">
+                <div class="w-[60%] flex justify-start items-center">
+                  <div class="w-18 h-18 rounded-full shrink-0 overflow-hidden">
+                    <img
+                      v-if="itemData?.createdHeadImageUrl"
+                      class="w-full h-full object-cover"
+                      :src="itemData?.createdHeadImageUrl"
+                      alt=""
+                    />
+                    <img
+                      v-else
+                      class="w-full h-full object-cover"
+                      src="~/assets/img/default_avatar.png"
+                      alt=""
+                    />
+                  </div>
+                  <span class="truncate ml-4 text-black-9 text-sm">
+                    {{ itemData?.createdShowName }}
+                  </span>
+                </div>
+
+                <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>
+          </NuxtLink>
+        </template>
+      </div>
+    </van-list>
+    <div v-else class="flex items-center justify-center h-[140px] mt-10">
+      <div>
+        <div>
+          <img class="w-84" src="../../assets/img/topic/yj.png" alt="" />
+        </div>
+        <div class="text-center text-[#999]">暂无游记</div>
+      </div>
+    </div>
+  </template>
+</template>
+<script setup>
+const route = useRoute()
+const router = useRouter()
+// 是否最新 和最热
+const isHot = ref(0)
+const showSearch = ref(false)
+
+const pageNum = ref(1)
+const pageSize = ref(10)
+const topicData = ref(null)
+const dataList = ref([])
+const loading = ref(true)
+const finished = ref(false)
+
+const topicName = computed(() => route.query.topicName)
+
+// 搜索页面的请求
+const recordList = ref([])
+async function getSearchRecordList() {
+  const {
+    data: { dataList, totalCount }
+  } = await request('/website/tourism/projectSearchRecords/searchRecordList', {
+    pageNum: 1,
+    pageSize: 20
+  })
+
+  if (Array.isArray(dataList) && dataList.length) {
+    recordList.value = dataList
+  }
+}
+
+function goBack() {
+  router.back()
+}
+
+// 获取话题相关得游记
+async function getTravelNotesTopicList() {
+  showLoadingToast({
+    message: '加载中...',
+    forbidClick: true,
+    duration: 0
+  })
+  const param = {
+    pageNum: pageNum.value,
+    pageSize: pageSize.value
+  }
+
+  param.orderBy = isHot.value
+  param.topicName = topicName.value
+
+  const { data } = await request('/website/tourism/travelNotesTopic/list', {
+    query: param
+  }).finally(() => closeToast())
+
+  if (data) {
+    topicData.value = data
+    dataList.value = dataList.value.concat(data.tourTravelNotesTopicNotesSearchVoList)
+    // 去重相同的游记
+    nextTick(() => {
+      dataList.value = [...new Map(dataList.value.map((item) => [item?.id, item])).values()]
+    })
+    showSearch.value = false
+  } else {
+    topicData.value = {}
+    dataList.value = []
+    showSearch.value = true
+  }
+
+  loading.value = false
+  if (dataList.value.length >= data.travelNotesCount) {
+    finished.value = true
+  } else {
+    finished.value = false
+  }
+}
+// 切换最新和最热
+function changeIsHotAndIsNew(index) {
+  isHot.value = index
+  dataList.value = []
+  getTravelNotesTopicList()
+}
+
+// 是否收藏话题
+async function handleCollection() {
+  const res = await request('/website/tourism/travelNotesTopic/Collection', {
+    method: 'post',
+    body: {
+      id: topicData.value.id
+    }
+  }).finally(() => {})
+
+  if (res && res.success) {
+    showToast('收藏成功')
+    getTravelNotesTopicList()
+  }
+}
+
+// 取消话题收藏
+function handleTopicCancel() {
+  showConfirmDialog({
+    title: '提示',
+    message: '确认取消收藏吗',
+    confirmButtonColor: '#FF9300'
+  }).then(() => {
+    request('/website/tourism/travelNotesTopic/cancelCollection', {
+      method: 'post',
+      body: {
+        id: topicData.value.id
+      }
+    })
+      .then(() => {
+        showToast('取消收藏成功')
+        getTravelNotesTopicList()
+      })
+      .catch(() => {})
+  })
+}
+
+function loadMore() {
+  pageNum.value++
+  getTravelNotesTopicList()
+}
+
+// 分享
+const copyLink = () => {
+  let url = location.href
+
+  navigator.clipboard.writeText(url).then(
+    () => {
+      showNotify({ type: 'success', message: '链接已复制' })
+    },
+    () => {
+      showNotify({ message: '链接复制失败' })
+    }
+  )
+}
+
+// 游记得喜欢
+// const canDoStar = ref(true)
+// async function doStar(params) {
+//   if (!canDoStar.value) return
+//   canDoStar.value = false
+//   request(`/website/tourism/projectTravelNotes/userLikeTravelNotesUpdate`, {
+//     method: 'post',
+//     body: { travelNotesId: params.id }
+//   })
+//     .then(() => {
+//       getTravelNotesTopicList()
+//       nextTick(async () => {
+//         let objData = await dataList.value.find((item) => item.id == params.id)
+//         objData.isLike = true
+//       })
+//     })
+//     .finally(() => (canDoStar.value = true))
+// }
+
+onMounted(() => {
+  getTravelNotesTopicList()
+})
+</script>
+<style lang="scss" scoped></style>

+ 365 - 128
src/pages/travel-notes/index.vue

@@ -1,95 +1,218 @@
 <template>
   <div>
-    <div v-if="filterList.length" class="sticky top-50 z-50 bg-white w-full">
-      <van-dropdown-menu active-color="#FF9300" ref="dropDownMenuRef">
-        <van-dropdown-item @closed="onAreaFilterClose" :title="areaFilterTitle" ref="itemRef">
-          <van-tree-select
-            @click-nav="handleAreaClick"
-            @click-item="handleFilterClick"
-            v-model:active-id="activeId"
-            v-model:main-active-index="areaIndex"
-            :items="filterList"
-          />
-        </van-dropdown-item>
-        <van-dropdown-item
-          :title="writeTypeText"
-          v-model="travelWriteType"
-          :options="writeTypeList"
-        ></van-dropdown-item>
-      </van-dropdown-menu>
-    </div>
-    <div  class="px-10 pt-20">
-      <div v-if="recomendList.length" class="scrollbar w-full" style="overflow-x: auto">
-        <div class="flex ">
-          <NuxtLink :to="'/t/'+item.id" v-for="(item,index) in recomendList" :key="index" class="w-[110px] border rounded overflow-hidden shrink-0 mr-[12px]">
-            <div class="w-full h-[76px] bg-[#dedede]">
-              <img v-if="Array.isArray(item?.tourismUrlsAfterConvert)" :src="item?.tourismUrlsAfterConvert[0]" class="w-full h-full object-cover" alt="">
-            </div>
-            <div class="text-clip overflow-hidden text-[13px] text-[13px] px-5 h-[40px] w-full mt-5 overflow-ellipsis"
-              style="line-height:18px;height:36px">
-              {{ item.projectTitle }}
-            </div>
-            <div class="flex justify-end text-[#FF476A] text-[14px] font-semibold pr-10">
-              {{ item.priceUnit }}{{ item.price }}
-            </div>
-          </NuxtLink>
+    <template v-if="showSearch">
+      <div class="w-full h-48 px-12 mt-8">
+        <van-search
+          v-model="value"
+          show-action
+          shape="round"
+          placeholder="搜索游记"
+          clearable
+          @search="onSearch"
+        >
+          <template #action>
+            <div class="text-[#FF9300]" @click="onSearch">搜索</div>
+          </template>
+        </van-search>
+      </div>
+
+      <div class="px-12">
+        <div class="flex justify-between items-center mb-12">
+          <h1 class="font-semibold text-xl">历史搜索</h1>
+          <div class="text-sm">
+            <template v-if="showCancel">
+              <span class="text-black-9">
+                <span class="mr-12" @click="handleClearSearchRecord">全部删除</span>
+                |
+                <span @click="showCancel = false" class="ml-12 text-black-3">完成</span>
+              </span>
+            </template>
+            <template v-else>
+              <div class="flex items-center text-base">
+                全部删除
+                <span
+                  v-if="recordList.length"
+                  @click="handleClearSearchRecord"
+                  class="iconfont icon-delete-one text-black-9 ml-4"
+                  style="font-size: 20px"
+                ></span>
+              </div>
+            </template>
+          </div>
+        </div>
+        <div class="flex justify-start flex-wrap">
+          <div
+            v-for="(item, index) in recordList"
+            :key="item.id"
+            @click="(value = item?.searchKeyword), (showCancel = true)"
+            class="h-38 bg-[#F7F7F7] box-border px-10 py-8 rounded-[4px] mr-8 mb-12"
+          >
+            {{ item?.searchKeyword }}
+            <span
+              v-if="showCancel"
+              @click.prevent="handleDeleteSearchRecordById(item?.id)"
+              class="iconfont icon-close text-black-6 ml-6"
+              style="font-size: 10px"
+            ></span>
+          </div>
         </div>
       </div>
-      <van-list v-if="dataList.length" v-model:loading="loading" :immediate-check="false" :finished="finished"
-        loading-text="加载中..." error-text="获取失败" @load="loadMore">
-        <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>
+    </template>
+    <template v-else>
+      <div v-if="filterList.length" class="sticky top-50 z-50 bg-white w-full">
+        <div class="w-full h-48 flex justify-between items-center px-12">
+          <van-icon @click="router.back()" name="arrow-left" color="#333333" size="24" />
+
+          <div
+            @click="changeBar(0)"
+            :class="`relative h-full  flex justify-center items-center  w-[38.4%]  text-center ${barIndex == 0 ? 'font-semibold text-xl text-[#FF9300]' : 'text-black-3 text-base'} `"
+          >
+            发现
             <div
-              class="h-80 pl-[8px] flex flex-col text-[#FD9A00] justify-between w-[calc(100%-120px)]"
+              v-if="barIndex == 0"
+              class="barIndex absolute bottom-0 left-1/2 -translate-x-1/2"
+            ></div>
+          </div>
+          <div
+            @click="changeBar(1)"
+            :class="`relative h-full  flex justify-center items-center w-[38.4%] text-center ${barIndex == 1 ? 'font-semibold text-xl text-[#FF9300]' : 'text-black-3 text-base'} 
+           `"
+          >
+            关注
+            <div
+              v-if="barIndex == 1"
+              class="barIndex absolute bottom-0 left-1/2 -translate-x-1/2"
+            ></div>
+          </div>
+          <div class="w-24 h-24 shrink-0">
+            <img
+              class="w-full h-full object-cover"
+              src="~/assets/img/visa/search.svg"
+              alt=""
+              @click="isShowSearch"
+            />
+          </div>
+        </div>
+        <van-dropdown-menu active-color="#FF9300" ref="dropDownMenuRef">
+          <van-dropdown-item @closed="onAreaFilterClose" :title="areaFilterTitle" ref="itemRef">
+            <van-tree-select
+              @click-nav="handleAreaClick"
+              @click-item="handleFilterClick"
+              v-model:active-id="activeId"
+              v-model:main-active-index="areaIndex"
+              :items="filterList"
+            />
+          </van-dropdown-item>
+
+          <van-dropdown-item
+            :title="writeTypeText"
+            v-model="travelWriteType"
+            :options="writeTypeList"
+          ></van-dropdown-item>
+        </van-dropdown-menu>
+      </div>
+      <div class="px-10 pt-20">
+        <div v-if="recomendList.length" class="scrollbar w-full mb-12" style="overflow-x: auto">
+          <div class="flex">
+            <NuxtLink
+              :to="'/t/' + item.id"
+              v-for="(item, index) in recomendList"
+              :key="index"
+              class="w-[110px] border rounded overflow-hidden shrink-0 mr-[12px]"
             >
-              <div class="truncate w-full text-[14px] font-bold">
+              <div class="w-full h-[76px] bg-[#dedede]">
                 <img
-                  v-if="itemData.isOriginal == 1"
-                  src="~/assets/img/yuanchuang.png"
-                  class="mt-3 w-[30px] h-[16px]"
+                  v-if="Array.isArray(item?.tourismUrlsAfterConvert)"
+                  :src="item?.tourismUrlsAfterConvert[0]"
+                  class="w-full h-full object-cover"
                   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
+                class="text-clip overflow-hidden text-[13px] text-[13px] px-5 h-[40px] w-full mt-5 overflow-ellipsis"
+                style="line-height: 18px; height: 36px"
+              >
+                {{ item.projectTitle }}
               </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 class="flex justify-end text-[#FF476A] text-[14px] font-semibold pr-10">
+                {{ item.priceUnit }}{{ item.price }}
+              </div>
+            </NuxtLink>
+          </div>
+        </div>
+        <van-list
+          v-if="dataList.length"
+          v-model:loading="loading"
+          :immediate-check="false"
+          :finished="finished"
+          loading-text="加载中..."
+          error-text="获取失败"
+          @load="loadMore"
+        >
+          <div class="w-full box-border flex justify-between flex-wrap">
+            <template v-for="itemData in dataList">
+              <NuxtLink
+                class="w-[50%] relative cursor-pointer bg-white pb-10"
+                :to="`/yj/${itemData.id}`"
+              >
+                <div
+                  class="aspect-[172/172] h-172 shrink-0 rounded-2xl overflow-hidden bg-[#ddd] mb-8"
+                >
+                  <img
+                    v-if="Array.isArray(itemData?.tourismUrlsAfterConvert)"
+                    :src="itemData?.tourismUrlsAfterConvert[0]"
+                    class="w-full h-full rounded-2xl object-cover"
+                    alt=""
+                    srcset=""
+                  />
                 </div>
-                <div class="flex items-center mr-10">
-                  <van-icon name="good-job-o" class="mr-5" />
-                  {{ transferCount(itemData.likeCount) }}
+                <div class="px-8 flex flex-col w-full justify-between">
+                  <div class="truncate w-full text-base font-semibold text-black-3 mb-8">
+                    <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="flex justify-between items-center">
+                    <div class="flex justify-start items-center">
+                      <div class="w-18 h-18 rounded-full overflow-hidden">
+                        <img
+                          v-if="itemData?.createImage"
+                          class="w-full h-full object-cover"
+                          :src="itemData?.createImage"
+                          alt=""
+                        />
+                        <img
+                          v-else
+                          class="w-full h-full object-cover"
+                          src="~/assets/img/default_avatar.png"
+                          alt=""
+                        />
+                      </div>
+                      <span class="ml-4 text-black-9 text-sm">{{ itemData?.createName }}</span>
+                    </div>
+
+                    <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>
-              </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>
-        </template>
-      </van-list>
-      <Empty v-if="!dataList.length && !loading" />
-    </div>
+              </NuxtLink>
+            </template>
+          </div>
+        </van-list>
+        <Empty v-if="!dataList.length && !loading" />
+      </div>
+    </template>
   </div>
 </template>
 
@@ -97,14 +220,25 @@
 const route = useRoute()
 const router = useRouter()
 
+// 最顶部导航的下标
+const barIndex = ref(0)
+
+// 是否显示搜索页面的
+const showSearch = ref(false)
+
+// 是否显示搜索历史记录的
+const showCancel = ref(false)
+// 搜索的内容
+const value = ref('')
+
+// 搜索的历史记录
+const searchHistoricalList = ref('')
+
 // 推荐项目
-const { data } = await useMyFetch(
-  `website/tourism/project/list?isHotspot=1&pageNum=1&pageSize=10`
-)
+const { data } = await useMyFetch(`website/tourism/project/list?isHotspot=1&pageNum=1&pageSize=10`)
 
 const recomendList = ref([])
 
-
 const AREA_TEXT = '地域'
 
 const areaId = useRouteParam('area')
@@ -124,15 +258,19 @@ const activeIndex = ref('')
 const dropDownMenuRef = ref(null)
 // 获取筛选列表
 async function getFilters() {
-  const { data } = await request(`/website/tourism/projectTravelNotes/travelNotesDirectoryList`).finally(() => { closeToast() })
+  const { data } = await request(
+    `/website/tourism/projectTravelNotes/travelNotesDirectoryList`
+  ).finally(() => {
+    closeToast()
+  })
 
   if (!Array.isArray(data)) return getList()
-  let country = null;
+  let country = null
   data.map((item, index) => {
     data[index].id = item.areaId
     data[index].text = item.areaName
     if (Array.isArray(item.children)) {
-      data[index].children.unshift({ countryName: '全部', countryId: item.areaId+',all' })
+      data[index].children.unshift({ countryName: '全部', countryId: item.areaId + ',all' })
       item.children.map((item2, index2) => {
         data[index].children[index2].id = item2.countryId
         data[index].children[index2].text = item2.countryName
@@ -140,35 +278,35 @@ async function getFilters() {
         data[index].children[index2].areaName = item.areaName
       })
     }
-    
-    if(route.query.area && item.areaId == route.query.area){
+
+    if (route.query.area && item.areaId == route.query.area) {
       curFilter.value.areaId = route.query.area
       document.title = item.areaName
       areaIndex.value = index + 1
       areaFilterTitle.value = item.areaName
     }
 
-    if(route.query.country){
-      const con = item.children.filter(c=>c.countryId == route.query.country)[0]
-      if(con){
+    if (route.query.country) {
+      const con = item.children.filter((c) => c.countryId == route.query.country)[0]
+      if (con) {
         country = con
       }
     }
   })
-  if(country){
+  if (country) {
     curFilter.value.countryId = route.query.country
     curFilter.value.id = route.query.country
-    areaFilterTitle.value = country.areaName +'-'+country.countryName
-  }else{
-    if(curFilter.value.areaId){
+    areaFilterTitle.value = country.areaName + '-' + country.countryName
+  } else {
+    if (curFilter.value.areaId) {
       curFilter.value.countryId = curFilter.value.areaId + ',all'
       curFilter.value.id = curFilter.value.areaId + ',all'
     }
   }
-  if(route.query.country && !route.query.area){
-    data.map((item,index)=>{
-      item.children.map(subItem=>{
-        if(subItem.id == route.query.country){
+  if (route.query.country && !route.query.area) {
+    data.map((item, index) => {
+      item.children.map((subItem) => {
+        if (subItem.id == route.query.country) {
           areaIndex.value = index + 1
         }
       })
@@ -193,11 +331,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 = []
@@ -226,8 +363,13 @@ async function getList() {
   if (travelWriteType.value) {
     param.travelWriteType = travelWriteType.value
   }
+  if (barIndex.value == 1) {
+    param.isFollow = 1
+  }
   loading.value = true
-  const { data } = await request(`/website/tourism/projectTravelNotes/travelNotesPageList`, { query: param }).finally(() => closeToast())
+  const { data } = await request(`/website/tourism/projectTravelNotes/travelNotesPageList`, {
+    query: param
+  }).finally(() => closeToast())
 
   dataList.value = dataList.value.concat(data.dataList)
   loading.value = false
@@ -237,6 +379,14 @@ async function getList() {
     finished.value = false
   }
 }
+
+// 改变头部下标
+function changeBar(index) {
+  barIndex.value = index
+  dataList.value = []
+  getList()
+}
+
 // 选择洲
 function handleAreaClick(index) {
   areaIndex.value = index
@@ -259,28 +409,18 @@ function handleFilterClick(item) {
   // getRecommend()
   // dropDownMenuRef.value && dropDownMenuRef.value.close()
   // document.title = `${item.id ? '游记-' + item.areaName + '-' + item.text : '旅游笔记'}`
-  
-  let search =''
-  if(item.areaId) search+='area='+item.areaId
-  if(item.id) {
+
+  let search = ''
+  if (item.areaId) search += 'area=' + item.areaId
+  if (item.id) {
     const i = item.countryId.split(',')
-    if(!i[1]){
-      search+=`${item.areaId?'&':''}country=${item.id}`
+    if (!i[1]) {
+      search += `${item.areaId ? '&' : ''}country=${item.id}`
     }
-    
   }
-  location.search=`${search}`
-  
+  location.search = `${search}`
 }
 
-function transferCount(num = 0) {
-  if (isNaN(num)) return 0
-  if (num > 10000) {
-    return (num / 10000).toFixed(1) + 'w'
-  } else {
-    return num
-  }
-}
 function loadMore() {
   pageNum.value++
   getList()
@@ -290,11 +430,11 @@ function convertTag(str = '') {
   return str.split('&')
 }
 
-async function getRecommend(){
-  const param={
-    isHotspot:1,
-    pageNum:1,
-    pageSize:10
+async function getRecommend() {
+  const param = {
+    isHotspot: 1,
+    pageNum: 1,
+    pageSize: 10
   }
   if (curFilter.value.areaId) param.areaId = curFilter.value.areaId
 
@@ -302,12 +442,102 @@ async function getRecommend(){
     const countryId = curFilter.value.id.split(',')
     if (!countryId[1]) param.countryId = curFilter.value.id
   }
-  const {data:{dataList}} = await request('website/tourism/project/list',{ query: param })
+  const {
+    data: { dataList }
+  } = await request('website/tourism/project/list', { query: param })
   recomendList.value = dataList || []
 }
+
+// 切换到搜索页面
+function isShowSearch() {
+  showSearch.value = true
+  getSearchRecordList()
+}
+
+// 搜索游记
+async function onSearch() {
+  const { data } = await request(
+    '/website/tourism/projectTravelNotes/travelNotesPageListBySearch',
+    {
+      query: {
+        pageNum: 1,
+        pageSize: 20,
+        searchString: value.value
+      }
+    }
+  ).finally(() => {
+    showSearch.value = false
+    value.value = ''
+  })
+
+  if (Array.isArray(data.dataList) && data?.dataList?.length) {
+    dataList.value = data.dataList
+  } else {
+    dataList.value = []
+  }
+  getSearchRecordList()
+}
+
+// 搜索页面的请求
+const recordList = ref([])
+async function getSearchRecordList() {
+  const {
+    data: { dataList, totalCount }
+  } = await request('/website/tourism/projectSearchRecords/searchRecordList', {
+    pageNum: 1,
+    pageSize: 20
+  })
+
+  if (Array.isArray(dataList) && dataList.length) {
+    recordList.value = dataList
+  }
+}
+
+//根据id 去清除记录
+async function handleDeleteSearchRecordById(id) {
+  showConfirmDialog({
+    width: 260,
+    message: '是否删除这条历史记录?',
+    confirmButtonColor: '#FF9300'
+  })
+    .then(async () => {
+      const res = await request('/website/tourism/projectSearchRecords/deleteSearchRecordById', {
+        method: 'post',
+        body: {
+          id
+        }
+      })
+
+      if (res && res.success) {
+        getSearchRecordList()
+      }
+    })
+    .catch(() => {})
+}
+// 清空历史记录
+function handleClearSearchRecord() {
+  showConfirmDialog({
+    width: 260,
+    message: '是否全部删除历史记录?',
+    confirmButtonColor: '#FF9300'
+  })
+    .then(async () => {
+      const res = await request('/website/tourism/projectSearchRecords/clearSearchRecord', {
+        method: 'post',
+        body: {
+          // 0游记列表1话题列表
+          searchType: 0
+        }
+      })
+
+      if (res && res.success) {
+        recordList.value = []
+      }
+    })
+    .catch(() => {})
+}
 onMounted(async () => {
   getFilters()
-  
 })
 
 useSeoMeta({
@@ -345,4 +575,11 @@ useSeoMeta({
   overflow: hidden;
   -webkit-box-orient: vertical;
 }
+
+.barIndex {
+  width: 40px;
+  height: 2px;
+  background-color: #ff9300;
+  border-radius: 50%;
+}
 </style>

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

@@ -0,0 +1,184 @@
+<template>
+  <div class="h-[100vh] bg-[#F7F8FA]">
+    <div class="h-48 flex justify-between items-center bg-white px-12 mb-12">
+      <span
+        @click="goToBack"
+        class="iconfont icon-left text-black-3 font-[600]"
+        style="font-size: 24px"
+      ></span>
+
+      <span class="text-2xl font-semibold">{{ othersUserInfo?.showName }}的群聊</span>
+      <span></span>
+    </div>
+    <van-list
+      v-if="groupList?.length"
+      v-model:loading="loading"
+      :immediate-check="false"
+      :finished="finished"
+      loading-text="加载中..."
+      error-text="获取失败"
+      @load="loadMore"
+    >
+      <van-cell-group
+        v-for="(item, index) in groupList"
+        :key="item.id"
+        inset
+        style="margin-bottom: 13px"
+      >
+        <van-cell :title="item?.groupName" center :label="`${item?.count}人`">
+          <template #icon>
+            <div class="w-48 h-48 rounded-full mr-12">
+              <MultiHeader v-if="item?.memberHeadImg" :size="48" :img-urls="item?.memberHeadImg" />
+            </div>
+          </template>
+          <template #value>
+            <van-button
+              size="small"
+              class="follow-item__button"
+              :disabled="false"
+              :color="FANS_STATUS[item.status]?.bg"
+              type="primary"
+              @click.stop="handleJoinGroup(item)"
+              round
+            >
+              {{ FANS_STATUS[item.status]?.text }}
+            </van-button>
+          </template>
+        </van-cell>
+        <van-cell v-if="item.description">
+          <template #icon>
+            <h1 class="w-48 mr-12 text-base font-semibold">群介绍</h1>
+          </template>
+          <template #title>
+            <p class="line-clamp-2 text-base text-black/[0.6]">
+              {{ item.description }}
+            </p>
+          </template>
+        </van-cell>
+      </van-cell-group>
+    </van-list>
+    <Empty v-else title="暂无群聊" />
+  </div>
+</template>
+<script setup>
+const id = useRouteParam('id')
+const router = useRouter()
+const userInfoStore = useUserInfoStore()
+const { userInfo } = storeToRefs(userInfoStore)
+const FANS_STATUS = {
+  0: { status: 0, text: '申请加入 ', describe: '未关注', bg: '#FD9A00' },
+  1: { status: 1, text: '立即聊天', describe: '已关注', bg: '#FD9A00' },
+  2: { status: 2, text: '已申请', describe: '相互关注', bg: '#999' }
+}
+const loading = ref(true)
+const finished = ref(false)
+const pageNum = ref(1)
+const pageSize = ref(10)
+
+const othersUserInfo = ref(null) //他人信息
+const groupList = ref([]) //下方游记
+
+// 加入群聊
+const handleJoinGroup = (item) => {
+  if (item.status == 0) {
+    getGroupAdd(item.id)
+  }
+  if (item.status == 1) {
+    navigateTo({
+      path: '/chat/group-chat',
+      query: { groupId: item.id },
+      replace: true
+    })
+  }
+  if (item.status == 2) {
+    showToast('已申请,请等待群主同意')
+  }
+}
+
+// 加群聊
+const getGroupAdd = async (groupId) => {
+  let res = await request('/website/tourMember/invite', {
+    method: 'post',
+    body: {
+      groupId,
+      ids: [userInfo.value.userId]
+    }
+  })
+  if (res && res.data) {
+    getUserGroup()
+  }
+}
+
+function goToBack() {
+  router.back()
+}
+
+// 获取他人主页的信息
+async function getHomePageDetailsDto() {
+  const { data } = await request('/website/tourism/travelNotesTopic/homePageDetailsDto', {
+    query: {
+      userId: id.value
+    }
+  })
+
+  if (data) {
+    othersUserInfo.value = data
+  }
+}
+
+function loadMore() {
+  pageNum.value++
+  getUserGroup()
+}
+// 获取他人公开的群聊
+async function getUserGroup() {
+  try {
+    const param = {
+      pageNum: pageNum.value,
+      pageSize: pageSize.value
+    }
+
+    loading.value = true
+    const {
+      data: { dataList, totalCount }
+    } = await request('/website/tourGroup/getUserGroup', {
+      query: {
+        ...param,
+        userId: id.value
+      }
+    })
+
+    if (Array.isArray(dataList) && dataList.length) {
+      groupList.value = groupList.value.concat(dataList)
+      nextTick(() => {
+        groupList.value = [...new Map(groupList.value.map((item) => [item?.id, item])).values()]
+      })
+    } else {
+      groupList.value = []
+    }
+
+    loading.value = false
+    if (groupList.value.length >= totalCount) {
+      finished.value = true
+    } else {
+      finished.value = false
+    }
+  } catch (error) {}
+}
+
+onMounted(() => {
+  getHomePageDetailsDto()
+  getUserGroup()
+})
+</script>
+<style lang="scss" scoped>
+.follow-item {
+  .follow-item__button {
+    min-width: 60px;
+    padding: 0 16px;
+    border-radius: 100px;
+    text-align: center;
+    font-size: 14px;
+  }
+}
+</style>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 637 - 211
src/pages/yj/[id].vue


+ 96 - 54
src/utils/index.js

@@ -1,84 +1,126 @@
-import accounting from "accounting";
+import accounting from 'accounting'
 
-const setIntervalImmediately = (fn, duration) =>
-  setInterval((() => (fn(), fn))(), duration);
+const setIntervalImmediately = (fn, duration) => setInterval((() => (fn(), fn))(), duration)
 
 function formatImgSrc(srcArr) {
   if (Array.isArray(srcArr) && srcArr.length > 0) {
-    return srcArr[0] ?? "";
+    return srcArr[0] ?? ''
   }
-  return "";
+  return ''
 }
 
 const isEmptyValue = (value) => {
-    if (value == null) return true
+  if (value == null) return true
 
-    if (Array.isArray(value) && value.length === 0) return true
+  if (Array.isArray(value) && value.length === 0) return true
 
-    if (typeof value === 'object' && Object.keys(value).length === 0) return true
+  if (typeof value === 'object' && Object.keys(value).length === 0) return true
 
-    return false
+  return false
 }
 
 const formatNumber = (n) => {
-    let num = Number(n ?? '')
+  let num = Number(n ?? '')
 
-    // 如果数字大于或等于10,000万,则显示为9999w+
-    if (num >= 10000 * 10000) {
-        return '9999万+'
-    }
-    // 如果数字大于或等于1万,则转换为以“万”为单位,不四舍五入,最多保留两位小数
-    else if (num >= 10000) {
-        let w = Math.floor(num / 10000) // 取整,避免四舍五入
-        let remainder = num % 10000
-
-        // 计算小数部分并限制为最多两位
-        let decimalPart = ''
-        if (remainder > 0) {
-            // 将余数转换为两位小数,但不进行四舍五入
-            decimalPart = ('.' + Math.floor(remainder / 100)).slice(0, 2)
-            // 移除结尾的0,如果有的话
-            decimalPart = decimalPart.replace(/\.?0+$/, '')
-        }
-
-        return `${w}${decimalPart}万`
+  // 如果数字大于或等于10,000万,则显示为9999w+
+  if (num >= 10000 * 10000) {
+    return '9999万+'
+  }
+  // 如果数字大于或等于1万,则转换为以“万”为单位,不四舍五入,最多保留两位小数
+  else if (num >= 10000) {
+    let w = Math.floor(num / 10000) // 取整,避免四舍五入
+    let remainder = num % 10000
+
+    // 计算小数部分并限制为最多两位
+    let decimalPart = ''
+    if (remainder > 0) {
+      // 将余数转换为两位小数,但不进行四舍五入
+      decimalPart = ('.' + Math.floor(remainder / 100)).slice(0, 2)
+      // 移除结尾的0,如果有的话
+      decimalPart = decimalPart.replace(/\.?0+$/, '')
     }
 
-    // 对于小于1万的数字直接输出
-    else {
-        return accounting.formatNumber(num)
-    }
+    return `${w}${decimalPart}万`
+  }
+
+  // 对于小于1万的数字直接输出
+  else {
+    return accounting.formatNumber(num)
+  }
 }
 
+// 字母
+const formatNumberLetter = (n) => {
+  let num = Number(n ?? '')
 
-const isValidJson = (jsonString) => {
-    try {
-        JSON.parse(jsonString);
-        return true;
-    } catch (e) {
-        return false;
+  // 如果数字大于或等于10,000万,则显示为9999w+
+  if (num >= 10000 * 10000) {
+    return '9999w+'
+  }
+  // 如果数字大于或等于1万,则转换为以“万”为单位,不四舍五入,最多保留两位小数
+  else if (num >= 10000) {
+    let w = Math.floor(num / 10000) // 取整,避免四舍五入
+    let remainder = num % 10000
+
+    // 计算小数部分并限制为最多两位
+    let decimalPart = ''
+    if (remainder > 0) {
+      // 将余数转换为两位小数,但不进行四舍五入
+      decimalPart = ('.' + Math.floor(remainder / 100)).slice(0, 2)
+      // 移除结尾的0,如果有的话
+      decimalPart = decimalPart.replace(/\.?0+$/, '')
     }
+
+    return `${w}${decimalPart}w`
+  }
+
+  // 对于小于1万的数字直接输出
+  else {
+    return accounting.formatNumber(num)
+  }
+}
+const transferCount = (num = 0) => {
+  if (isNaN(num)) return 0
+  if (num > 10000) {
+    return (num / 10000).toFixed(1) + 'w'
+  } else {
+    return num
+  }
 }
 
+const isValidJson = (jsonString) => {
+  try {
+    JSON.parse(jsonString)
+    return true
+  } catch (e) {
+    return false
+  }
+}
 
 const uuid = function () {
-    function S4() {
-        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
-    }
-    return (S4() + S4() + "" + S4() + "" + S4() + "" + S4() + "" + S4() + S4() + S4());
-};
+  function S4() {
+    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
+  }
+  return S4() + S4() + '' + S4() + '' + S4() + '' + S4() + '' + S4() + S4() + S4()
+}
 
 function priceToArray(price) {
-  if (!price) return ["0", "00"];
-  const priceStr = price.toString();
-  if (!priceStr.includes(".")) {
-    return [priceStr, "00"];
+  if (!price) return ['0', '00']
+  const priceStr = price.toString()
+  if (!priceStr.includes('.')) {
+    return [priceStr, '00']
   }
-  return [priceStr.split(".")[0], priceStr.split(".")[1]];
+  return [priceStr.split('.')[0], priceStr.split('.')[1]]
 }
 
-
-export { setIntervalImmediately, formatImgSrc, formatNumber, isEmptyValue, isValidJson, uuid ,priceToArray};
-
-
-
+export {
+  setIntervalImmediately,
+  formatImgSrc,
+  formatNumber,
+  isEmptyValue,
+  isValidJson,
+  uuid,
+  priceToArray,
+  formatNumberLetter,
+  transferCount
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott