Commit cdd10067 by lijiabin

Merge branch 'master' into feature/21170-YAYA文化岛官方账号ip显示问题

parents ce93495a 7f921885
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue'
import emojis from '@/utils/emoji/face.json' import emojis from '@/utils/emoji/face.json'
import yayas from '@/utils/emoji/yaya.json'
import type { IEmoji } from '@/utils/emoji/type' import type { IEmoji } from '@/utils/emoji/type'
const emit = defineEmits<{ const emit = defineEmits<{
selectEmoji: [emoji: IEmoji] selectEmoji: [emoji: IEmoji]
}>() }>()
type EmojiTab = 'face' | 'yaya'
const activeTab = ref<EmojiTab>('face')
const transitionName = ref('emoji-slide-left')
const emojiTabs: Array<{
key: EmojiTab
label: string
list: Array<Pick<IEmoji, 'name' | 'url' | 'group'>>
}> = [
{
key: 'face',
label: '默认表情',
list: emojis,
},
{
key: 'yaya',
label: 'YAYA表情',
list: yayas,
},
]
const currentEmojiList = computed(() => {
return emojiTabs.find((tab) => tab.key === activeTab.value)?.list ?? []
})
const switchTab = (nextTab: EmojiTab) => {
if (nextTab === activeTab.value) return
const currentIndex = emojiTabs.findIndex((tab) => tab.key === activeTab.value)
const nextIndex = emojiTabs.findIndex((tab) => tab.key === nextTab)
transitionName.value = nextIndex > currentIndex ? 'emoji-slide-left' : 'emoji-slide-right'
activeTab.value = nextTab
}
</script> </script>
<template> <template>
<div <div
class="w-8 h-8 text-gray-500 hover:bg-gray-100 hover:text-gray-700 rounded-lg flex items-center justify-center" class="flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 transition-all hover:bg-orange-50 hover:text-orange-500"
> >
<el-popover placement="bottom" trigger="click" width="384"> <el-popover placement="bottom" trigger="click" :width="384" popper-class="emoji-popover">
<template #reference> <template #reference>
<el-icon size="20" @mousedown.prevent> <el-icon size="20" @mousedown.prevent>
<svg-icon name="icon_face" class="cursor-pointer" <svg-icon name="icon_face" class="cursor-pointer" />
/></el-icon> </el-icon>
</template> </template>
<!-- 表情面板 -->
<el-scrollbar class="h-50"> <div class="emoji-panel">
<div class="flex flex-wrap"> <div class="emoji-tabs">
<span <button
v-for="item in emojis" v-for="tab in emojiTabs"
:key="item.name" :key="tab.key"
class="cursor-pointer hover:bg-gray-100 rounded p-1 flex items-center justify-center" type="button"
@click="emit('selectEmoji', item)" class="emoji-tab"
:class="{ 'emoji-tab--active': activeTab === tab.key }"
@click="switchTab(tab.key)"
> >
<img :src="item.url" alt="" class="w-6 h-6" /> {{ tab.label }}
</span> </button>
</div> </div>
</el-scrollbar>
<el-scrollbar class="emoji-scrollbar">
<transition :name="transitionName" mode="out-in">
<div :key="activeTab" class="emoji-grid">
<div v-for="item in currentEmojiList" :key="item.name">
<el-popover
v-if="item.group === 'yaya'"
placement="top"
trigger="hover"
:offset="10"
:show-arrow="false"
:popper-style="{
height: '150px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}"
>
<el-image :src="item.url" :alt="item.name" class="h-full w-full object-contain" />
<template #reference>
<button
type="button"
class="emoji-item"
:title="item.name"
@click="emit('selectEmoji', item as IEmoji)"
>
<img
:src="item.url"
:alt="item.name"
class="h-6 w-6 object-contain"
:class="{ 'h-8 w-8': item.group === 'yaya' }"
/>
</button>
</template>
</el-popover>
<button
v-else
type="button"
class="emoji-item"
:title="item.name"
@click="emit('selectEmoji', item as IEmoji)"
>
<img
:src="item.url"
:alt="item.name"
class="h-6 w-6 object-contain"
:class="{ 'h-8 w-8': item.group === 'yaya' }"
/>
</button>
</div>
</div>
</transition>
</el-scrollbar>
</div>
</el-popover> </el-popover>
</div> </div>
</template> </template>
<style scoped></style> <style scoped>
.emoji-tabs {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 8px;
padding: 0 6px 8px;
border-bottom: 1px solid #f5f5f5;
}
.emoji-tab {
position: relative;
border: 0;
background: transparent;
color: #9ca3af;
border-radius: 0;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition:
color 0.18s ease,
transform 0.18s ease;
}
.emoji-tab:hover {
color: #f97316;
}
.emoji-tab--active {
color: #ea580c;
transform: none;
}
.emoji-tab--active::after {
content: '';
position: absolute;
left: 0;
bottom: -9px;
width: 100%;
height: 2px;
border-radius: 999px;
background: linear-gradient(90deg, #fb923c 0%, #f97316 100%);
}
.emoji-scrollbar {
height: 188px;
}
.emoji-grid {
display: grid;
grid-template-columns: repeat(8, minmax(0, 1fr));
gap: 6px;
padding: 2px 4px 10px;
}
.emoji-slide-left-enter-active,
.emoji-slide-left-leave-active,
.emoji-slide-right-enter-active,
.emoji-slide-right-leave-active {
transition:
opacity 0.22s ease,
transform 0.22s ease;
}
.emoji-slide-left-enter-from,
.emoji-slide-right-leave-to {
opacity: 0;
transform: translateX(18px);
}
.emoji-slide-left-leave-to,
.emoji-slide-right-enter-from {
opacity: 0;
transform: translateX(-18px);
}
.emoji-slide-left-enter-to,
.emoji-slide-left-leave-from,
.emoji-slide-right-enter-to,
.emoji-slide-right-leave-from {
opacity: 1;
transform: translateX(0);
}
.emoji-item {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 34px;
border: 0;
border-radius: 10px;
background: #fff;
cursor: pointer;
transition:
transform 0.18s ease,
background-color 0.18s ease,
box-shadow 0.18s ease;
}
.emoji-item:hover {
background: linear-gradient(180deg, #fff7ed 0%, #ffedd5 100%);
box-shadow: 0 6px 14px rgb(251 146 60 / 16%);
transform: translateY(-1px);
}
</style>
import emojis from './face.json' import emojis from './face.json'
import yayas from './yaya.json'
type EmojiAsset = {
name: string
url: string
group: string
}
const emojiList: EmojiAsset[] = [...emojis, ...yayas]
function escapeHTML(str: string) { function escapeHTML(str: string) {
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
...@@ -9,18 +18,19 @@ export const parseEmoji = (content: string) => { ...@@ -9,18 +18,19 @@ export const parseEmoji = (content: string) => {
let html = escapeHTML(content) let html = escapeHTML(content)
emojis.forEach((item) => { emojiList.forEach((item) => {
const escapedName = item.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') const escapedName = item.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
const reg = new RegExp(escapedName, 'g') const reg = new RegExp(escapedName, 'g')
console.log(item.group)
html = html.replace( html = html.replace(
reg, reg,
`<img `<img
src="${item.url}" src="${item.url}"
alt="${item.name}" alt="${item.name}"
class="${item.className || 'emoji_small'} inline-block align-text-bottom w-6 h-6" class="${item.group === 'yaya' ? 'w-8 h-8' : 'w-6 h-6'}"
/>`, />`,
) )
}) })
......
[
{
"name": "[YAYA_OK]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842153149.png",
"group": "yaya"
},
{
"name": "[YAYA_OK1]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842183051.png",
"group": "yaya"
},
{
"name": "[YAYA_OKK]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842204358.png",
"group": "yaya"
},
{
"name": "[YAYA_拜托]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842337245.png",
"group": "yaya"
},
{
"name": "[YAYA_点赞]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842370496.png",
"group": "yaya"
},
{
"name": "[YAYA_非常感谢]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842403468.png",
"group": "yaya"
},
{
"name": "[YAYA_恭喜]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842433720.png",
"group": "yaya"
},
{
"name": "[YAYA_恭喜1]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842456906.png",
"group": "yaya"
},
{
"name": "[YAYA_好滴]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842482423.png",
"group": "yaya"
},
{
"name": "[YAYA_加油]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842512339.png",
"group": "yaya"
},
{
"name": "[YAYA_焦急]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842540763.png",
"group": "yaya"
},
{
"name": "[YAYA_开心]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842564724.png",
"group": "yaya"
},
{
"name": "[YAYA_哭泣]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842593525.png",
"group": "yaya"
},
{
"name": "[YAYA_努力]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842629597.png",
"group": "yaya"
},
{
"name": "[YAYA_谢谢]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842649971.png",
"group": "yaya"
},
{
"name": "[YAYA_亚声人]",
"url": "https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/png/2026/03/30/Common/1774842693166.png",
"group": "yaya"
}
]
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
:ref="(e) => (contentRefList[index] = e as HTMLElement)" :ref="(e) => (contentRefList[index] = e as HTMLElement)"
class="text-gray-600 text-sm sm:text-base leading-relaxed transition-all duration-300" class="text-gray-600 text-sm sm:text-base leading-relaxed transition-all duration-300"
:class="{ 'line-clamp-3': !item.isExpand }" :class="{ 'line-clamp-3': !item.isExpand }"
@click="openNewPage(`/questionDetail/${item.id}`)"
> >
<template <template
v-if=" v-if="
......
...@@ -394,7 +394,7 @@ import type { ...@@ -394,7 +394,7 @@ import type {
DailyLotteryInfo, DailyLotteryInfo,
} from '@/api' } from '@/api'
import { TABS_REF_KEY, levelListOptions } from '@/constants' import { TABS_REF_KEY, levelListOptions } from '@/constants'
import { useScrollTop } from '@/hooks' import { useScrollTop, useMessageBox } from '@/hooks'
import { useQuestionStore, useActivityStore, useYaBiStore } from '@/stores' import { useQuestionStore, useActivityStore, useYaBiStore } from '@/stores'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { push } from 'notivue' import { push } from 'notivue'
...@@ -404,6 +404,7 @@ import { RewardButtonEnum } from '@/constants' ...@@ -404,6 +404,7 @@ import { RewardButtonEnum } from '@/constants'
import RewardButton from '@/components/common/RewardButton/index.vue' import RewardButton from '@/components/common/RewardButton/index.vue'
import { useTourStore } from '@/stores' import { useTourStore } from '@/stores'
const { confirm } = useMessageBox()
const tourStore = useTourStore() const tourStore = useTourStore()
const { shouldShowAskTabTour } = storeToRefs(tourStore) const { shouldShowAskTabTour } = storeToRefs(tourStore)
const breakpoints = useBreakpoints(breakpointsTailwind) const breakpoints = useBreakpoints(breakpointsTailwind)
...@@ -526,6 +527,13 @@ const getLotteryPrizesDetail = async () => { ...@@ -526,6 +527,13 @@ const getLotteryPrizesDetail = async () => {
const handleLottery = async () => { const handleLottery = async () => {
if (!lotteryPrizesDetail.value?.inRegistrationTime) if (!lotteryPrizesDetail.value?.inRegistrationTime)
return push.error(`抽奖通道将于${lotteryPrizesDetail.value?.registrationTimeDesc}开启`) return push.error(`抽奖通道将于${lotteryPrizesDetail.value?.registrationTimeDesc}开启`)
// 二次确认
await confirm({
title: '提示',
message: '确定参与每日抽奖吗?',
type: 'primary',
})
await userJoinLottery() await userJoinLottery()
getLotteryPrizesDetail() getLotteryPrizesDetail()
refreshUserAccountData() refreshUserAccountData()
......
...@@ -451,20 +451,17 @@ const questionContentRef = useTemplateRef<HTMLElement>('questionContentRef') ...@@ -451,20 +451,17 @@ const questionContentRef = useTemplateRef<HTMLElement>('questionContentRef')
const isExpand = ref(false) const isExpand = ref(false)
// 检测当前是否超过三行 要用到具体的dom // 检测当前是否超过三行 要用到具体的dom
const isOverThreeLine = ref(false) const isOverThreeLine = computed(() => {
const checkIsOverThreeLine = () => {
if (!questionContentRef.value || !questionDetail.value.content) return false if (!questionContentRef.value || !questionDetail.value.content) return false
const lineHeight = parseFloat(getComputedStyle(questionContentRef.value).lineHeight) const lineHeight = parseFloat(getComputedStyle(questionContentRef.value).lineHeight)
const height = questionContentRef.value!.scrollHeight const height = questionContentRef.value!.scrollHeight
const maxHeight = lineHeight * 3 const maxHeight = lineHeight * 3
return height > maxHeight return height > maxHeight
} })
const getQuestionDetail = async () => { const getQuestionDetail = async () => {
const { data } = await getArticleDetail(questionId) const { data } = await getArticleDetail(questionId)
questionDetail.value = data questionDetail.value = data
await nextTick()
isOverThreeLine.value = checkIsOverThreeLine()
} }
const { list, total, searchParams, goToPage, refresh } = usePageSearch(getCommentList, { const { list, total, searchParams, goToPage, refresh } = usePageSearch(getCommentList, {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment