Commit a25a5702 by lijiabin

【需求 17679】 perf: 优化实践列表展示、在线时长等内容

parent bfb3f0bd
...@@ -22,8 +22,9 @@ export interface AddOrUpdatePracticeDto { ...@@ -22,8 +22,9 @@ export interface AddOrUpdatePracticeDto {
* 搜索文章的参数 * 搜索文章的参数
*/ */
export interface PracticeSearchParams extends PageSearchParams { export interface PracticeSearchParams extends PageSearchParams {
sortLogic?: number sortLogic: number
tagIdList?: number[] tagIdList: number[]
deptIdList: string[]
} }
/** /**
......
...@@ -28,7 +28,7 @@ export interface SelfPublishDetailDto { ...@@ -28,7 +28,7 @@ export interface SelfPublishDetailDto {
replyCount: number replyCount: number
tagNameList: string[] tagNameList: string[]
title: string title: string
type: string type: ArticleTypeEnum
videoUrl: string videoUrl: string
viewCount: number viewCount: number
} }
...@@ -52,7 +52,7 @@ export interface SelfCollectDetailDto { ...@@ -52,7 +52,7 @@ export interface SelfCollectDetailDto {
replyCount: number replyCount: number
tagNameList: string[] tagNameList: string[]
title: string title: string
type: string type: ArticleTypeEnum
viewCount: number viewCount: number
} }
...@@ -129,7 +129,7 @@ export interface AuditListItemDto { ...@@ -129,7 +129,7 @@ export interface AuditListItemDto {
showName: string showName: string
tagNameList: string[] tagNameList: string[]
title: string title: string
type: string type: ArticleTypeEnum
viewCount: number viewCount: number
} }
...@@ -252,7 +252,7 @@ export interface SelfCommentItemDto { ...@@ -252,7 +252,7 @@ export interface SelfCommentItemDto {
replyName: string replyName: string
replyUser: string replyUser: string
title: string title: string
type: string type: ArticleTypeEnum
userId: number userId: number
viewCount: number viewCount: number
} }
...@@ -298,7 +298,7 @@ export interface ComplaintListItemDto { ...@@ -298,7 +298,7 @@ export interface ComplaintListItemDto {
showName: string showName: string
status: number status: number
title: string title: string
type: string type: ArticleTypeEnum
} }
/** /**
......
...@@ -15,11 +15,10 @@ ...@@ -15,11 +15,10 @@
class="custom-upload" class="custom-upload"
> >
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</el-upload>
<el-dialog :append-to-body="true" v-model="dialogVisible"> <el-dialog :append-to-body="true" v-model="dialogVisible">
<img class="w-full" :src="dialogImageUrl" alt="Preview Image" /> <img class="w-full" :src="dialogImageUrl" alt="Preview Image" />
</el-dialog> </el-dialog>
</el-upload>
</template> </template>
<script lang="ts" setup generic="T extends string | string[]"> <script lang="ts" setup generic="T extends string | string[]">
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
storage-type="session" storage-type="session"
class="fixed" class="fixed"
> >
<div class="cursor-pointer online-time flex flex-col items-center z-50"> <div class="cursor-pointer online-time flex flex-col items-center z-1050">
<!-- 图片容器 --> <!-- 图片容器 -->
<div <div
class="mb-4 w-24 h-24 bg-white rounded-full shadow-xl flex items-center justify-center hover:scale-110 transition-transform cursor-pointer" class="mb-4 w-24 h-24 bg-white rounded-full shadow-xl flex items-center justify-center hover:scale-110 transition-transform cursor-pointer"
...@@ -96,7 +96,11 @@ const widthRate = computed(() => { ...@@ -96,7 +96,11 @@ const widthRate = computed(() => {
// 在线时长格式化 将秒级 格式化为 00:00 // 在线时长格式化 将秒级 格式化为 00:00
const formatSeconds = computed(() => { const formatSeconds = computed(() => {
if (currentSeconds.value >= maxSeconds) {
return dayjs.utc(currentSeconds.value * 1000).format('hh:mm:ss')
} else {
return dayjs.utc(currentSeconds.value * 1000).format('mm:ss') return dayjs.utc(currentSeconds.value * 1000).format('mm:ss')
}
}) })
onMounted(async () => { onMounted(async () => {
......
...@@ -93,10 +93,10 @@ video { ...@@ -93,10 +93,10 @@ video {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
vertical-align: baseline; /* vertical-align: baseline;
background: transparent; background: transparent;
font: inherit; font: inherit;
color: inherit; color: inherit; */
} }
/* 3. 基础 html / body */ /* 3. 基础 html / body */
......
...@@ -31,12 +31,13 @@ ...@@ -31,12 +31,13 @@
{{ item.title }} {{ item.title }}
</h2> </h2>
<div class="flex gap-4 mb-2"> <div class="flex gap-4 mb-2">
<el-image <!-- 问吧暂时先不展示图片 -->
v-if="item.faceUrl" <!-- <el-image
v-if="item.faceUrl && !item.cultureCommentListVo?.hiddenName"
:src="item.faceUrl" :src="item.faceUrl"
fit="cover" fit="cover"
class="w-50 h-25 rounded-l" class="w-50 h-25 rounded-lg"
/> /> -->
<!-- 问题内容 --> <!-- 问题内容 -->
<div> <div>
<p <p
......
...@@ -187,9 +187,9 @@ ...@@ -187,9 +187,9 @@
<div class="w-full"> <div class="w-full">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="w-1 h-4 bg-gradient-to-b from-pink-500 to-rose-500 rounded-full"></div> <div class="w-1 h-4 bg-gradient-to-b from-pink-500 to-rose-500 rounded-full"></div>
<h1 class="text-sm sm:text-base font-bold">任务中心</h1> <h1 class="text-sm sm:text-base">任务中心</h1>
</div> </div>
<h2 <div
class="w-full text-xs sm:text-sm mt-1 text-gray-600 flex items-center justify-between" class="w-full text-xs sm:text-sm mt-1 text-gray-600 flex items-center justify-between"
> >
<div> <div>
...@@ -205,7 +205,7 @@ ...@@ -205,7 +205,7 @@
<span class="text-#999 cursor-pointer" @click="router.push(`/userPage/selfTask`)"> <span class="text-#999 cursor-pointer" @click="router.push(`/userPage/selfTask`)">
查看更多 查看更多
</span> </span>
</h2> </div>
</div> </div>
</div> </div>
......
...@@ -2,35 +2,103 @@ ...@@ -2,35 +2,103 @@
<div> <div>
<!-- 发布区域 --> <!-- 发布区域 -->
<PublishPractice :type="ArticleTypeEnum.PRACTICE" :isReal="1" :maxLength="2000" /> <PublishPractice :type="ArticleTypeEnum.PRACTICE" :isReal="1" :maxLength="2000" />
<!-- 筛选面板 -->
<!-- 标签导航 --> <div class="bg-white rounded-xl shadow-sm border border-gray-100/50 overflow-hidden mb-6">
<div class="bg-white p-4 mb-6 rounded-lg shadow-sm"> <div class="p-6">
<div class="flex flex-wrap gap-2 mb-2"> <!-- 排序选项 (单选) -->
<el-tag <div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-4 bg-gradient-to-b from-blue-500 to-blue-600 rounded-full"></div>
<span class="text-sm font-semibold text-gray-700">排序方式</span>
</div>
<div class="flex flex-wrap gap-2">
<button
v-for="tag in filterOptions" v-for="tag in filterOptions"
:key="tag.id" :key="tag.id"
:type="tag.id === searchParams.sortLogic ? 'primary' : 'info'"
:effect="tag.id === searchParams.sortLogic ? 'dark' : 'plain'"
class="cursor-pointer"
@click="toggleFilter(tag.id)" @click="toggleFilter(tag.id)"
:class="[
'px-4 py-2 rounded-lg text-sm font-medium cursor-pointer transition-all duration-200',
tag.id === searchParams.sortLogic
? 'bg-blue-50 text-blue-600 border-2 border-blue-400 shadow-sm'
: 'bg-gray-50 text-gray-600 border-2 border-transparent hover:border-gray-200 hover:bg-gray-100',
]"
> >
{{ tag.title }} {{ tag.title }}
</el-tag> </button>
</div>
</div>
<!-- 标签筛选 (多选) -->
<div class="mb-6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-4 bg-gradient-to-b from-blue-400 to-blue-500 rounded-full"></div>
<span class="text-sm font-semibold text-gray-700">文化标签</span>
<span v-if="searchParams.tagIdList.length" class="text-xs text-gray-400">
(已选 {{ searchParams.tagIdList.length }} 个)
</span>
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<el-tag <label
v-for="tag in tagList" v-for="tag in tagList"
:key="tag.id" :key="tag.id"
:type="searchParams.tagIdList?.includes(tag.id) ? 'primary' : 'info'" :class="[
:effect="searchParams.tagIdList?.includes(tag.id) ? 'dark' : 'plain'" 'px-4 py-2 rounded-lg text-sm font-medium cursor-pointer transition-all duration-200',
class="cursor-pointer" searchParams.tagIdList.includes(tag.id)
@click="toggleTag(tag.id)" ? 'bg-blue-50 text-blue-600 border-2 border-blue-400 shadow-sm'
: 'bg-gray-50 text-gray-600 border-2 border-transparent hover:border-gray-200 hover:bg-gray-100',
]"
> >
<input
type="checkbox"
:value="tag.id"
v-model="searchParams.tagIdList"
@change="refresh"
class="hidden"
/>
<span class="flex items-center gap-1.5">
<span v-if="searchParams.tagIdList.includes(tag.id)" class="text-xs"></span>
{{ tag.title }} {{ tag.title }}
</el-tag> </span>
</label>
</div> </div>
</div> </div>
<!-- 部门筛选 (多选) -->
<div>
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-4 bg-gradient-to-b from-blue-400 to-blue-500 rounded-full"></div>
<span class="text-sm font-semibold text-gray-700">所属部门</span>
<span v-if="searchParams.deptIdList.length" class="text-xs text-gray-400">
(已选 {{ searchParams.deptIdList.length }} 个)
</span>
</div>
<div class="flex flex-wrap gap-2">
<label
v-for="item in firstDepList"
:key="item.id"
:class="[
'px-4 py-2 rounded-lg text-sm font-medium cursor-pointer transition-all duration-200',
searchParams.deptIdList.includes(item.id)
? 'bg-blue-50 text-blue-600 border-2 border-blue-400 shadow-sm'
: 'bg-gray-50 text-gray-600 border-2 border-transparent hover:border-gray-200 hover:bg-gray-100',
]"
>
<input
type="checkbox"
:value="item.id"
v-model="searchParams.deptIdList"
@change="refresh"
class="hidden"
/>
<span class="flex items-center gap-1.5">
<span v-if="searchParams.deptIdList.includes(item.id)" class="text-xs"></span>
{{ item.name }}
</span>
</label>
</div>
</div>
</div>
</div>
<!-- 内容区域 --> <!-- 内容区域 -->
<div class="bg-white rounded-lg shadow-sm"> <div class="bg-white rounded-lg shadow-sm">
<!-- 最新标题 --> <!-- 最新标题 -->
...@@ -78,7 +146,7 @@ ...@@ -78,7 +146,7 @@
class="w-40 h-25 object-cover rounded-lg flex-shrink-0" class="w-40 h-25 object-cover rounded-lg flex-shrink-0"
/> />
<div class="flex-1 mr-4"> <div class="flex-1 mr-4">
<div class="text-gray-600 text-base leading-relaxed line-clamp-4"> <div class="text-gray-600 text-base leading-relaxed line-clamp-3">
{{ item.content }} {{ item.content }}
</div> </div>
</div> </div>
...@@ -177,27 +245,42 @@ const tabsRef = inject(TABS_REF_KEY) ...@@ -177,27 +245,42 @@ const tabsRef = inject(TABS_REF_KEY)
const filterOptions = ref([ const filterOptions = ref([
{ title: '最热', id: 0 }, { title: '最热', id: 0 },
{ title: '最新', id: 1 }, { title: '最新', id: 1 },
{ title: '最多观看', id: 2 }, // { title: '最多观看', id: 2 },
])
const firstDepList = ref([
{ id: '1825', name: 'Amazon产品开发部' },
{ id: '76', name: 'Amazon销售部' },
{ id: '139', name: 'Amazon运营部' },
{ id: '5114', name: 'Temu销售部' },
{ id: '4491', name: 'Tiktok项目部' },
{ id: '39', name: '视觉设计部' },
{ id: '23', name: '知识产权部' },
{ id: '499', name: '供应链管理部' },
{ id: '20', name: 'IT技术部' },
{ id: '5', name: '财务部' },
{ id: '2357', name: '人力发展中心' },
{ id: '683', name: '副总经理' },
{ id: '6', name: '总经理' },
{ id: '3', name: '董事长' },
]) ])
const { handleBackTop, ScrollTopComp } = useScrollTop(tabsRef!) const { handleBackTop, ScrollTopComp } = useScrollTop(tabsRef!)
const { list, total, searchParams, goToPage, changePageSize, refresh } = usePageSearch( const { list, total, searchParams, goToPage, changePageSize, refresh } = usePageSearch(
getPracticeList, getPracticeList,
{ {
defaultParams: { sortLogic: filterOptions.value[0]?.id, tagIdList: [] }, defaultParams: { sortLogic: filterOptions.value[0]?.id, tagIdList: [], deptIdList: [] },
defaultCurrent: 1, defaultCurrent: 1,
defaultSize: 8, defaultSize: 8,
immediate: false, immediate: false,
}, },
) )
const filterText = computed(() => { const filterText = computed(() => {
return ( return filterOptions.value.find((item) => item.id === searchParams.value.sortLogic)?.title
filterOptions.value.find((item) => item.id === searchParams.value.sortLogic)?.title + // +
(searchParams.value.tagIdList?.length ? '——' : '') + // (searchParams.value.tagIdList?.length ? '——' : '')
(searchParams.value.tagIdList?.length // +
? tagList.value.find((item) => searchParams.value.tagIdList?.includes(item.id))?.title // (searchParams.value.tagIdList?.length
: '') // ? tagList.value.find((item) => searchParams.value.tagIdList?.includes(item.id))?.title
) // : '')
}) })
const toggleFilter = (id: number) => { const toggleFilter = (id: number) => {
...@@ -206,12 +289,6 @@ const toggleFilter = (id: number) => { ...@@ -206,12 +289,6 @@ const toggleFilter = (id: number) => {
handleBackTop() handleBackTop()
} }
const toggleTag = (id: number) => {
searchParams.value.tagIdList = [id]
refresh()
handleBackTop()
}
defineExpose({ defineExpose({
refresh: () => { refresh: () => {
refresh() refresh()
......
...@@ -289,7 +289,7 @@ ...@@ -289,7 +289,7 @@
import UploadVideo from '@/components/common/UploadVideo/index.vue' import UploadVideo from '@/components/common/UploadVideo/index.vue'
import { useResetData } from '@/hooks' import { useResetData } from '@/hooks'
import { ArticleTypeEnum, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants' import { ArticleTypeEnum, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants'
import { addOrUpdateArticle, uploadFile } from '@/api' import { addOrUpdateArticle, uploadFile, getArticleDetail } from '@/api'
import SelectTags from '@/components/common/SelectTags/index.vue' import SelectTags from '@/components/common/SelectTags/index.vue'
import type { TagItemDto, AddOrUpdateVideoDto } from '@/api' import type { TagItemDto, AddOrUpdateVideoDto } from '@/api'
import { Camera, Picture } from '@element-plus/icons-vue' import { Camera, Picture } from '@element-plus/icons-vue'
...@@ -306,7 +306,7 @@ const showSpecialInput = computed( ...@@ -306,7 +306,7 @@ const showSpecialInput = computed(
) )
const router = useRouter() const router = useRouter()
const route = useRoute()
const formRef = useTemplateRef('formRef') const formRef = useTemplateRef('formRef')
const coverInputRef = useTemplateRef('coverInputRef') const coverInputRef = useTemplateRef('coverInputRef')
...@@ -478,6 +478,22 @@ const handleFileChange = async (e: Event) => { ...@@ -478,6 +478,22 @@ const handleFileChange = async (e: Event) => {
const { data } = await uploadFile(file) const { data } = await uploadFile(file)
form.value.faceUrl = data.data[0].filePath form.value.faceUrl = data.data[0].filePath
} }
// const isEdit = computed(() => {
// return !!route.query.id
// })
// onActivated(async () => {
// resetPageData()
// if (isEdit.value) {
// const { data } = await getArticleDetail(route.query.id as string)
// form.value = {
// ...form.value,
// ...data,
// mainTagId:String( data.tagIdList?.[0]) || '',
// tagList: data.tagIdList?.slice(1) || [],
// }
// }
// })
</script> </script>
<style scoped> <style scoped>
......
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