index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <template>
  2. <page-meta :page-font-size="fontValue+'px'" :root-font-size="fontValue+'px'"></page-meta>
  3. <cu-custom bgImage="/static/bg.png" :isBack="true">
  4. <template v-slot:content>
  5. <text class="text-black">收藏夹</text>
  6. </template>
  7. <template v-slot:right>
  8. <text class="cuIcon cuIcon-add text-bold text-black" @click="handleEdit(null)"></text>
  9. </template>
  10. </cu-custom>
  11. <view>
  12. <scroll-view scroll-x class="bg-white nav text-center">
  13. <view class="cu-item" :class="index===checkIndex?'text-zblue text-bold cur':'text-bold text-black'" v-for="(item,index) in menuList" :key="index"
  14. @click="changCollect(index,item.type)" :data-id="index">
  15. {{ item.text }}
  16. </view>
  17. </scroll-view>
  18. <view class="cu-list menu">
  19. <view class="cu-item collect" :class="modalName=='move-box-'+ index?'move-cur':''" v-for="(item,index) in list"
  20. :key="index" :data-target="'move-box-' + index"
  21. @touchstart="ListTouchStart" @touchmove="ListTouchMove" @touchend="ListTouchEnd">
  22. <view class="content">
  23. <view class="text-grey">
  24. <rich-text v-if="!item.messageType||item.messageType===MessageType.text" style="word-break: break-all;"
  25. :nodes="ChatUtils.transform(item.content)"></rich-text>
  26. <image style="max-width: 150upx;" v-if="item.messageType===MessageType.image && item.extend"
  27. :src="item.extend.url"
  28. mode="widthFix"></image>
  29. <view v-if="item.messageType===MessageType.file && item.extend && item.extend.url && item.extend.fileName">
  30. <text class="cuIcon cuIcon-down" style="color: #666666;"></text>
  31. <uni-link color="#666666" class="text-black" :href="item.extend.url"
  32. :text="item.extend.fileName"></uni-link>
  33. </view>
  34. <view v-if="item.messageType===MessageType.voice" class="main">
  35. <view @click="handleAudio(item)">
  36. <text>{{ item.extend?.time }}"</text>
  37. <text class="cuIcon-sound text-xxl padding-right-xl"></text>
  38. </view>
  39. </view>
  40. <view v-if="item.messageType===MessageType.forward" class="main">
  41. <message-multiple-forward :message="item"/>
  42. </view>
  43. <view v-if="item.messageType===MessageType.video && item.extend && item.extend.url" class="main">
  44. <video :src="item.extend.url" controls style="width: 70vw"></video>
  45. <dom-video :src="item.extend.url" :controls='true' objectFit="contain"/>
  46. </view>
  47. </view>
  48. <view class="text-gray text-sm">
  49. <user-name-tag :id="item.fromId"/>
  50. </view>
  51. </view>
  52. <view class="action">
  53. <view class="text-grey text-xs">
  54. <Time :time="item.createTime"></Time>
  55. </view>
  56. </view>
  57. <view class="move">
  58. <view class="bg-orange" v-if="item.messageType === MessageType.text" @click="handleEdit(item.id)">编辑</view>
  59. <view class="bg-red" @click="handleDelete(item.id)">删除</view>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. <view class="cu-modal" :class="showAddCollect?'show':''">
  65. <view class="cu-dialog">
  66. <view class="cu-bar bg-white justify-end">
  67. <view class="content text-bold text-black">收藏</view>
  68. <view class="action" @tap="showAddCollect = false">
  69. <text class="cuIcon-close text-red"></text>
  70. </view>
  71. </view>
  72. <view class="padding-xl bg-gray">
  73. <textarea v-model="collectContent" rows="10"></textarea>
  74. </view>
  75. <view class="cu-bar bg-white">
  76. <view class="action margin-0 flex-sub text-green solid-left text-bold" @tap="showAddCollect = false">取消</view>
  77. <view class="action margin-0 flex-sub solid-left text-bold" @tap="margeCollect">确定</view>
  78. </view>
  79. </view>
  80. </view>
  81. </template>
  82. <script setup lang="ts">
  83. import {onActivated, ref} from "vue";
  84. import Auth from "@/api/Auth";
  85. import CollectApi from "@/api/CollectApi";
  86. import type Collect from "@/mode/Collect";
  87. import MessageType from "@/utils/MessageType";
  88. import UserNameTag from "@/components/UserNameTag.vue";
  89. import {match} from "pinyin-pro";
  90. import CuCustom from "@/colorui/components/cu-custom.vue";
  91. import Time from "@/components/Time.vue";
  92. import ChatUtils from "@/utils/ChatUtils";
  93. import UniLink from "@/uni_modules/uni-link/components/uni-link/uni-link.vue";
  94. import MessageMultipleForward from "@/components/messages/MessageMultipleForward.vue";
  95. import type Message from "@/mode/Message";
  96. import domVideo from "@/components/ls-dom-video/ls-dom-video.vue";
  97. const fontValue=ref(Auth.getfontSize());
  98. const Audio = ref(uni.createInnerAudioContext());
  99. const menuList = ref([
  100. {
  101. icon: "icon-v-quanbu",
  102. text: "全部",
  103. type: "",
  104. active: true,
  105. },
  106. {
  107. icon: "icon-v-24gl-fileText",
  108. text: "文本",
  109. type: MessageType.text,
  110. active: false,
  111. },
  112. {
  113. icon: "icon-v-tupian1",
  114. text: "图片",
  115. type: MessageType.image,
  116. active: false,
  117. },
  118. {
  119. icon: "icon-v-wj-wjj",
  120. text: "文件",
  121. type: MessageType.file,
  122. active: false,
  123. },
  124. {
  125. icon: "icon-v-yuyin",
  126. text: "语音",
  127. type: MessageType.voice,
  128. active: false,
  129. },
  130. ]);
  131. const list = ref(new Array<Collect>());
  132. const checkIndex = ref(0);
  133. const showAddCollect = ref(false);
  134. const collectContent = ref("");
  135. const keyword = ref("");
  136. const collect = ref<Collect>({
  137. id: undefined,
  138. fromId: undefined,
  139. content: "",
  140. messageType: MessageType.text,
  141. extend: undefined,
  142. });
  143. //控制播放还是暂停音频文件
  144. const handleAudio = (item: any) => {
  145. Audio.value.paused ? playAudio(item) : stopAudio();
  146. }
  147. //播放音频
  148. const playAudio = (item: any) => {
  149. Audio.value.src = item.extend.url
  150. Audio.value.play();
  151. }
  152. //停止音频
  153. const stopAudio = () => {
  154. Audio.value.src = '';
  155. Audio.value.stop();
  156. }
  157. const listTouchStart = ref(0);
  158. const listTouchDirection = ref();
  159. const modalName = ref();
  160. // ListTouch触摸开始
  161. const ListTouchStart = (e: any) => {
  162. listTouchStart.value = e.touches[0].pageX
  163. }
  164. // ListTouch计算方向
  165. const ListTouchMove = (e: any) => {
  166. listTouchDirection.value = e.touches[0].pageX - listTouchStart.value > 0 ? 'right' : 'left'
  167. }
  168. // ListTouch计算滚动
  169. const ListTouchEnd = (e: any) => {
  170. if (listTouchDirection.value == 'left') {
  171. modalName.value = e.currentTarget.dataset.target
  172. } else {
  173. modalName.value = null
  174. }
  175. listTouchDirection.value = null
  176. }
  177. const keywordFilter = (items: any[], keyword: string): any[] => {
  178. return items.filter((item) => {
  179. if (keyword.trim() === "" || match(item.content, keyword)) {
  180. return true;
  181. } else if (
  182. item.extend &&
  183. item.extend.fileName &&
  184. match(item.extend.fileName, keyword)
  185. ) {
  186. return true;
  187. } else {
  188. return false;
  189. }
  190. });
  191. };
  192. /**
  193. * 选择收藏类型
  194. * @param index 索引
  195. * @param type 选中项
  196. */
  197. const changCollect = (index: number, type: string) => {
  198. checkIndex.value = index;
  199. loadData(type);
  200. };
  201. /**
  202. * 加载数据
  203. * @param type 收藏类型
  204. */
  205. const loadData = (type: string) => {
  206. CollectApi.list(type).then((res) => {
  207. list.value = res.data.map((item: any) => {
  208. if (item.extend) {
  209. item.extend = JSON.parse(item.extend);
  210. }
  211. return item;
  212. });
  213. });
  214. };
  215. onActivated(() => {
  216. // 初始化加载数据
  217. loadData(menuList.value[checkIndex.value].type);
  218. });
  219. loadData('')
  220. /**
  221. * 编辑收藏
  222. * @param id 收藏id
  223. */
  224. const handleEdit = (id: string | undefined) => {
  225. showAddCollect.value = true;
  226. collectContent.value = "";
  227. if (typeof id === "string") {
  228. CollectApi.get(id).then((res) => {
  229. collect.value = res.data;
  230. collectContent.value = res.data.content;
  231. });
  232. }
  233. };
  234. /**
  235. * 删除收藏
  236. * @param id 收藏id
  237. */
  238. const handleDelete = (id: string | undefined) => {
  239. uni.showModal({
  240. title: '提示',
  241. content: '确定要删除吗?',
  242. cancelText: '取消',
  243. confirmText: '删除',
  244. success: res => {
  245. if (res.confirm && id) {
  246. CollectApi.delete(id).then(() => {
  247. loadData(menuList.value[checkIndex.value].type);
  248. });
  249. }
  250. }
  251. })
  252. }
  253. /**
  254. * 保存或者删除
  255. */
  256. const margeCollect = () => {
  257. collect.value.content = collectContent.value;
  258. const p = collect.value.id
  259. ? CollectApi.update(collect.value)
  260. : CollectApi.save(collect.value);
  261. p.then(() => {
  262. showAddCollect.value = false;
  263. checkIndex.value = 0;
  264. loadData("");
  265. collect.value = {
  266. id: undefined,
  267. fromId: undefined,
  268. content: "",
  269. messageType: MessageType.text,
  270. extend: undefined,
  271. };
  272. });
  273. };
  274. </script>
  275. <style scoped lang="scss">
  276. .collect {
  277. margin-top: 15px;
  278. }
  279. </style>