Commit 22115883 by lijiabin

【需求 17679】 feat: 继续完善页面,个人中心、积分商城、首页信息经验等

parent d142cb25
import { BooleanFlag } from '@/constants'
/**
* 轮播图的item
*/
export interface CarouselItemDto {
articleId: number
assetUrl: string
isRelease: BooleanFlag
sort: number
type: BooleanFlag
url: string
}
...@@ -4,6 +4,17 @@ import type { AddOrUpdateCaseDto } from './types' ...@@ -4,6 +4,17 @@ import type { AddOrUpdateCaseDto } from './types'
// 案例库相关的接口 // 案例库相关的接口
/** /**
* 获取最新的案例编号
*/
export const getMaxCaseNumber = () => {
return service.request<string>({
url: '/api/cultureCase/getMaxCaseNumber',
method: 'POST',
data: {},
})
}
/**
* 新增案例库 * 新增案例库
*/ */
export const addOrUpdateCase = (data: AddOrUpdateCaseDto) => { export const addOrUpdateCase = (data: AddOrUpdateCaseDto) => {
......
/** /**
* 添加或更新案例库DTO * 添加或更新案例库DTO
*/ */
import { TagTypeEnum, TagLevelEnum } from '@/constants'
export type TagItemDto = {
tagId: number
type: TagTypeEnum
keywordType: TagLevelEnum
}
export interface AddOrUpdateCaseDto { export interface AddOrUpdateCaseDto {
content: string content: string
title: string title: string
tagList: number[] tagRelationDtoList: TagItemDto[]
number: string
} }
import service from '@/utils/request/index' import service from '@/utils/request/index'
import type { CarouselItemDto } from './types' import type { CarouselItemDto, UserAccountDataDto, UserRecordDataDto } from './types'
import { BooleanFlag } from '@/constants' import { BooleanFlag } from '@/constants'
/** /**
* 获取轮播图列表 * 获取首页轮播图列表
*/ */
export const getCarouselList = () => { export const getCarouselList = () => {
return service.request<CarouselItemDto[]>({ return service.request<CarouselItemDto[]>({
...@@ -13,3 +13,26 @@ export const getCarouselList = () => { ...@@ -13,3 +13,26 @@ export const getCarouselList = () => {
}, },
}) })
} }
/**
* 获取首页用户相关数据 亚币 等级等
*/
export const getUserAccountData = () => {
return service.request<UserAccountDataDto>({
url: '/api/personalCenter/selfAccountData',
method: 'POST',
data: {},
})
}
/**
* 获取首页信息 是否已经签到
*/
export const getRecordData = () => {
return service.request<UserRecordDataDto>({
url: '/api/culture/action/record/baseData',
method: 'POST',
data: {},
})
}
import { BooleanFlag } from '@/constants'
/**
* 轮播图的item
*/
export interface CarouselItemDto {
articleId: number
assetUrl: string
isRelease: BooleanFlag
sort: number
type: BooleanFlag
url: string
}
/**
* 用户相关数据
*/
export interface UserAccountDataDto {
ayabiAvailable: number
ayabiTotal: number
createTime: number
expTotal: number
id: number
isDelete: number
level: number
remark: string
updateTime: number
userId: string
}
/**
* 用户信息记录
*/
export interface UserRecordDataDto {
actionType: null
actionTypeText: null
createdAt: null
createdTimeText: null
currentValue: null
id: null
incrText: null
isDelete: null
isIncr: null
isSign: BooleanFlag
relationId: null
remark: null
scoreAyabi: null
scoreExp: null
subType: null
userId: null
}
...@@ -3,21 +3,23 @@ export * from './task' ...@@ -3,21 +3,23 @@ export * from './task'
export * from './sign' export * from './sign'
export * from './article' export * from './article'
export * from './shop' export * from './shop'
export * from './carousel'
export * from './column' export * from './column'
export * from './interview' export * from './interview'
export * from './tag' export * from './tag'
export * from './common'
export * from './article' export * from './article'
export * from './user' export * from './user'
export * from './case'
export * from './home'
export * from './common'
// 导出类型 // 导出类型
export * from './task/types' export * from './task/types'
export * from './shop/types' export * from './shop/types'
export * from './article/types' export * from './article/types'
export * from './carousel/types'
export * from './column/types' export * from './column/types'
export * from './interview/types' export * from './interview/types'
export * from './tag/types' export * from './tag/types'
export * from './article/types' export * from './article/types'
export * from './user/types' export * from './user/types'
export * from './case/types'
export * from './home/types'
export * from './common/types' export * from './common/types'
import service from '@/utils/request/index' import service from '@/utils/request/index'
import type { UpdateUserInfoDto } from './types' import type { UpdateUserInfoDto, SelfPublishDetailDto } from './types'
import type { import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
BackendServicePageResult,
BackendServiceResult,
PageSearchParams,
} from '@/utils/request/types'
/** /**
* 更新用户信息 * 更新用户信息
...@@ -29,6 +25,28 @@ export const hasOfficialAccount = () => { ...@@ -29,6 +25,28 @@ export const hasOfficialAccount = () => {
} }
/** /**
* 获取我的发布列表
*/
export const getSelfPublishList = (data: PageSearchParams) => {
return service.request<BackendServicePageResult<SelfPublishDetailDto>>({
url: '/api/personalCenter/selfPublish',
method: 'POST',
data,
})
}
/**
* 获取我的草稿列表
*/
export const getSelfDraftList = (data: PageSearchParams) => {
return service.request<BackendServicePageResult<SelfPublishDetailDto>>({
url: '/api/personalCenter/selfDraft',
method: 'POST',
data,
})
}
/**
* 获取我的收藏列表 * 获取我的收藏列表
*/ */
export const getSelfCollectList = (data: PageSearchParams) => { export const getSelfCollectList = (data: PageSearchParams) => {
...@@ -65,3 +83,33 @@ export const getSelfPraiseList = (data: PageSearchParams) => { ...@@ -65,3 +83,33 @@ export const getSelfPraiseList = (data: PageSearchParams) => {
data, data,
}) })
} }
/**
* 获取我的案例库列表
*/
export const getSelfCaseList = (data: PageSearchParams) => {
return service.request<
BackendServicePageResult<{
id: number
title: string
content: string
createTime: string
updateTime: string
}>
>({
url: '/api/personalCenter/selfCase',
method: 'POST',
data,
})
}
/**
* 获取我的任务列表
*/
export const getSelfTaskList = (data: PageSearchParams) => {
return service.request<BackendServicePageResult<SelfPublishDetailDto>>({
url: '/api/personalCenter/selfTaskConfig',
method: 'POST',
data,
})
}
// 我的发布 详情
export interface SelfPublishDetailDto {
collectionCount: number
content: string
createTime: number
createUserId: number
description: string
faceUrl: string
hasPraised: boolean
id: number
isRecommend: boolean
isRelateColleague: boolean
praiseCount: number
releaseStatus: number
replyCount: number
tagNameList: string[]
title: string
type: string
videoUrl: string
viewCount: number
}
// 我的草稿 详情
export interface SelfDraftDetailDto {
id: number
title: string
content: string
createTime: string
updateTime: string
}
export interface UpdateUserInfoDto { export interface UpdateUserInfoDto {
hiddenAvatar: string hiddenAvatar: string
hiddenName: string hiddenName: string
......
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1763374682921" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5607" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M747.008 257.536h-18.432c-12.288-35.84-46.08-61.44-86.016-61.44H247.296c-50.176 0-91.136 40.96-91.136 91.136v263.168c0 46.08 37.376 83.456 83.456 83.456 24.064 0 43.52 19.456 43.52 43.52v21.504c0 29.696 35.328 45.056 56.832 25.088l85.504-78.336c8.192-7.168 18.432-11.264 29.184-11.264h187.904c50.176 0 91.136-40.96 91.136-91.136V328.704h13.312c27.136 0 49.152 22.016 49.152 49.152v244.736c0 23.04-18.944 42.496-42.496 42.496-41.984 0-76.288 34.304-76.288 76.288v10.752l-72.704-66.56c-13.824-12.8-32.256-19.968-51.712-19.968H460.288c-19.456 0-35.84 15.872-35.84 35.84 0 19.456 15.872 35.84 35.84 35.84h93.184c1.024 0 2.56 0.512 3.072 1.024l79.36 73.216c12.8 11.264 28.672 17.92 45.056 17.92 9.216 0 18.432-2.048 27.136-5.632 25.088-10.752 40.448-34.304 40.448-61.44V742.4c0-2.56 2.048-4.608 4.608-4.608 62.464 0 113.664-51.2 113.664-113.664V377.856c0.512-66.56-53.248-120.32-119.808-120.32z m-233.984 260.608H311.808c-18.432 0-33.28-14.848-33.28-33.28s14.848-33.28 33.28-33.28h201.216c18.432 0 33.28 14.848 33.28 33.28s-14.848 33.28-33.28 33.28z m67.584-130.048H311.808c-8.704 0-17.408-3.584-23.552-9.728-6.144-6.144-9.728-14.848-9.728-23.552 0-8.704 3.584-17.408 9.728-23.552 6.144-6.144 14.848-9.728 23.552-9.728h268.8c18.432 0 33.28 14.848 33.28 33.28s-14.848 33.28-33.28 33.28z m0 0" fill="#ffffff" p-id="5608"></path><path d="M605.184 685.056c-13.824-12.8-32.256-19.968-51.712-19.968H460.288c-19.456 0-35.84 15.872-35.84 35.84 0 17.92 12.8 32.256 30.208 35.328 52.736-9.216 103.424-26.112 150.528-51.2z m0 0" fill="#ffffff" p-id="5609"></path><path d="M859.136 333.824c-17.408-44.544-61.44-76.288-112.128-76.288h-18.432c-12.288-35.84-46.08-61.44-86.016-61.44H247.296c-50.176 0-91.136 40.96-91.136 91.136v263.168c0 46.08 37.376 83.456 83.456 83.456 24.064 0 43.52 19.456 43.52 43.52v21.504c0 29.696 35.328 45.056 56.832 25.088l85.504-78.336c8.192-7.168 18.432-11.264 29.184-11.264h187.904c50.176 0 91.136-40.96 91.136-91.136V328.704h13.312c27.136 0 49.152 22.016 49.152 49.152v126.464c30.72-51.2 52.736-109.056 62.976-170.496z m-346.112 184.32H311.808c-18.432 0-33.28-14.848-33.28-33.28s14.848-33.28 33.28-33.28h201.216c18.432 0 33.28 14.848 33.28 33.28s-14.848 33.28-33.28 33.28z m67.584-130.048H311.808c-8.704 0-17.408-3.584-23.552-9.728-6.144-6.144-9.728-14.848-9.728-23.552 0-8.704 3.584-17.408 9.728-23.552 6.144-6.144 14.848-9.728 23.552-9.728h268.8c18.432 0 33.28 14.848 33.28 33.28s-14.848 33.28-33.28 33.28z m0 0" fill="#ffffff" p-id="5610"></path><path d="M457.728 518.144H311.808c-18.432 0-33.28-14.848-33.28-33.28s14.848-33.28 33.28-33.28h201.216c11.776 0 22.016 6.144 27.648 14.848 78.336-60.416 138.24-144.384 168.448-241.664-16.384-17.92-40.448-29.696-67.072-29.696H247.296c-50.176 0-91.136 40.96-91.136 91.136v263.168c0 3.584 0.512 7.68 1.024 11.264 27.648 5.12 56.32 7.168 85.504 7.168 76.8 0.512 150.016-17.408 215.04-49.664zM311.808 321.536h268.8c18.432 0 33.28 14.848 33.28 33.28s-14.848 33.28-33.28 33.28H311.808c-8.704 0-17.408-3.584-23.552-9.728-6.144-6.144-9.728-14.848-9.728-23.552 0-8.704 3.584-17.408 9.728-23.552 6.144-6.144 14.336-9.728 23.552-9.728z m0 0" fill="#ffffff" p-id="5611"></path><path d="M280.576 367.616c-1.536-4.096-2.56-8.192-2.56-12.8 0-8.704 3.584-17.408 9.728-23.552 6.144-6.144 14.848-9.728 23.552-9.728h65.536C430.08 288.768 476.16 245.76 513.536 195.584h-266.24c-50.176 0-91.136 40.96-91.136 91.136v107.008c43.52-3.584 84.992-12.288 124.416-26.112z m0 0" fill="#ffffff" p-id="5612"></path></svg>
\ No newline at end of file
...@@ -53,3 +53,21 @@ export enum TaskDateLimitTypeEnum { ...@@ -53,3 +53,21 @@ export enum TaskDateLimitTypeEnum {
// 每月 // 每月
MONTH = 'MONTH', MONTH = 'MONTH',
} }
// 标签类型枚举
export enum TagTypeEnum {
// 文化关键词
CULTURE_TAG = 0,
// 年度关键词
YEAR_TAG = 1,
// 关联场景
SCENE_TAG = 2,
}
// 标签级别
export enum TagLevelEnum {
// 副标签
SUB_TAG = 0,
// 主标签
MAIN_TAG = 1,
}
import { ArticleTypeEnum, TaskTypeEnum } from './enums'
// 地区列表 // 地区列表
export const regionListOptions = [ export const regionListOptions = [
{ {
...@@ -29,3 +31,88 @@ export const regionListOptions = [ ...@@ -29,3 +31,88 @@ export const regionListOptions = [
value: '仓库', value: '仓库',
}, },
] ]
// 文章类型列表
export const articleTypeListOptions = [
{
label: '帖子',
value: ArticleTypeEnum.POST,
},
{
label: '视频',
value: ArticleTypeEnum.VIDEO,
},
{
label: '问题',
value: ArticleTypeEnum.QUESTION,
},
{
label: '专栏',
value: ArticleTypeEnum.COLUMN,
},
{
label: '实践',
value: ArticleTypeEnum.PRACTICE,
},
{
label: '专访',
value: ArticleTypeEnum.INTERVIEW,
},
]
// 任务类型列表
export const taskTypeListOptions = [
{
label: '常规任务',
value: TaskTypeEnum.REGULAR_TASK,
},
{
label: '特殊任务',
value: TaskTypeEnum.SPECIAL_TASK,
},
]
// 等级相关内容
export const levelListOptions: {
label: string
value: number
iconUrl: string
expScope: [number, number]
}[] = [
{
label: 'LV1',
value: 1,
iconUrl:
'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/png/2025/11/17/Common/1763370983822.png',
expScope: [0, 500],
},
{
label: 'LV2',
value: 2,
iconUrl:
'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/png/2025/11/17/Common/1763370990111.png',
expScope: [500, 1500],
},
{
label: 'LV3',
value: 3,
iconUrl:
'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/png/2025/11/17/Common/1763370993043.png',
expScope: [1500, 3000],
},
{
label: 'LV4',
value: 4,
iconUrl:
'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/png/2025/11/17/Common/1763370996142.png',
expScope: [3000, 6000],
},
{
label: 'LV5',
value: 5,
iconUrl:
'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/png/2025/11/17/Common/1763370998414.png',
expScope: [6000, 12000],
},
]
...@@ -7,7 +7,6 @@ import router from './router' ...@@ -7,7 +7,6 @@ import router from './router'
import './style/index.css' import './style/index.css'
import 'virtual:uno.css' import 'virtual:uno.css'
// 注册svg // 注册svg
import 'virtual:svg-icons-register' import 'virtual:svg-icons-register'
import SvgIcon from '@/components/common/SvgIcon/svgIcon.vue' import SvgIcon from '@/components/common/SvgIcon/svgIcon.vue'
......
...@@ -85,6 +85,11 @@ const routes = [ ...@@ -85,6 +85,11 @@ const routes = [
// } // }
], ],
}, },
{
path: '/test',
name: 'Test',
component: () => import('@/test.vue'),
},
] ]
const scrollPositionMap = new Map<string, number>() const scrollPositionMap = new Map<string, number>()
......
<template>
<el-button>111111{{ a }}</el-button>
</template>
<script setup lang="ts">
const a = 33
console.log(a)
</script>
...@@ -228,7 +228,7 @@ ...@@ -228,7 +228,7 @@
</div> </div>
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-pagination bg-gray-50/80 backdrop-blur-8 border-t border-gray-200"> <div class="bottom-pagination backdrop-blur-8 border-t border-gray-200">
<div class="max-w-7xl mx-auto px-8 py-6"> <div class="max-w-7xl mx-auto px-8 py-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<!-- 左侧:回到顶部按钮 --> <!-- 左侧:回到顶部按钮 -->
......
<template> <template>
<div ref="listRef"> <div ref="listRef">
<template v-if="list.length > 0 && !loading"> <div v-loading="loading" v-if="list.length > 0">
<div class="space-y-3 sm:space-y-4"> <div class="space-y-3 sm:space-y-4">
<div <div
v-for="item in list" v-for="item in list"
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
</div> </div>
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-pagination bg-gray-50/80 backdrop-blur-8 border-t border-gray-200"> <div class="bottom-pagination backdrop-blur-8 border-t border-gray-200">
<div class="max-w-7xl mx-auto px-8 py-6"> <div class="max-w-7xl mx-auto px-8 py-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<!-- 左侧:回到顶部按钮 --> <!-- 左侧:回到顶部按钮 -->
...@@ -113,13 +113,13 @@ ...@@ -113,13 +113,13 @@
</div> </div>
</div> </div>
</div> </div>
</template> </div>
<template v-else-if="loading"> <!-- <template v-else-if="loading">
<div class="flex items-center justify-center h-full"> <div class="flex items-center justify-center h-full">
<el-icon class="is-loading mr-2 text-gray-500"><Loading /></el-icon> <el-icon class="is-loading mr-2 text-gray-500"><Loading /></el-icon>
<span class="text-gray-500">加载中...</span> <span class="text-gray-500">加载中...</span>
</div> </div>
</template> </template> -->
<template v-else> <template v-else>
<div class="flex items-center justify-center h-full"> <div class="flex items-center justify-center h-full">
<el-empty description="暂无数据" /> <el-empty description="暂无数据" />
......
...@@ -339,7 +339,7 @@ ...@@ -339,7 +339,7 @@
</template> </template>
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-pagination bg-gray-50/80 backdrop-blur-8 border-t border-gray-200"> <div class="bottom-pagination backdrop-blur-8 border-t border-gray-200">
<div class="max-w-7xl mx-auto px-8 py-6"> <div class="max-w-7xl mx-auto px-8 py-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<!-- 左侧:回到顶部按钮 --> <!-- 左侧:回到顶部按钮 -->
......
...@@ -49,33 +49,50 @@ ...@@ -49,33 +49,50 @@
<div <div
class="level-container common-box flex flex-col justify-center items-center gap-4 rounded-lg bg-#E4F5FE" class="level-container common-box flex flex-col justify-center items-center gap-4 rounded-lg bg-#E4F5FE"
> >
<div class="top flex items-center w-full justify-center"> <div class="top flex items-center justify-center gap-3">
<div class="relative"> <img class="h-20" :src="currentLevelData?.iconUrl" alt="" />
<img class="h-8 sm:h-10" src="@/assets/img/culture/letter.png" alt="" /> <div class="text-base flex-3/4 flex flex-col gap-1">
<!-- 添加小的等级徽章 --> <div class="flex items-center gap-1 justify-start">
<div <div class="font-semibold">等级:{{ currentLevelData?.label }}</div>
class="absolute -top-1 -right-1 bg-blue-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center font-bold" <el-tooltip
> :content="`当前经验:${userAccountData.expTotal}/${currentLevelData.expScope[1]} (${currentLevelData.percentage}%)`"
1 placement="top"
>
<div class="relative w-20 cursor-pointer">
<div
class="relative w-full h-4 bg-#A5E4FF rounded-full border-1 border-#30C4FF border-solid"
>
<div class="absolute left-0 top-0 h-full bg-#30C4FF rounded-full"></div>
<div
class="absolute left-0 top-0 h-full bg-gradient-to-r from-blue-500 via-blue-400 to-cyan-400 rounded-full transition-all duration-500 ease-out"
:style="{ width: `${currentLevelData.percentage}%` }"
>
<div
class="absolute top-0 left-0 w-full h-1/2 bg-gradient-to-b from-white/40 to-transparent rounded-t-full"
></div>
</div>
</div>
</div>
</el-tooltip>
</div>
<div class="text-amber-600 font-medium">
YA币:{{ userAccountData.ayabiAvailable }}
</div> </div>
</div>
<div class="ml-2 sm:ml-4 text-sm sm:text-base">
<div class="font-semibold">等级:LV1</div>
<div class="text-amber-600 font-medium">YA币:8888</div>
</div> </div>
</div> </div>
<div class="flex flex-col sm:flex-row gap-2 w-full"> <div class="flex flex-col sm:flex-row gap-2">
<el-button <el-button
class="bg-[linear-gradient(to_right,#FFD06A_0%,#FFB143_100%)] shadow-[0px_1px_8px_0_rgba(255,173,91,0.25)] border-none hover:-translate-y-1 hover:shadow-[0px_4px_10px_0_rgba(255,173,91,0.4)] hover:scale-105 active:scale-95 active:translate-y-0 transition-all duration-200 flex-1 text-xs sm:text-sm" class="bg-[linear-gradient(to_right,#FFD06A_0%,#FFB143_100%)] shadow-[0px_1px_8px_0_rgba(255,173,91,0.25)] border-none hover:-translate-y-1 hover:shadow-[0px_4px_10px_0_rgba(255,173,91,0.4)] hover:scale-105 active:scale-95 active:translate-y-0 transition-all duration-200 flex-1 text-xs sm:text-sm"
type="primary" type="primary"
@click="onDailySign" @click="onDailySign"
v-if="!userRecordData.isSign"
> >
<svg-icon name="sign_in" size="35" /> <svg-icon name="sign_in" size="35" />
<span class="text-black text-xs sm:text-sm">立即签到</span> <span class="text-black text-xs sm:text-sm">立即签到</span>
</el-button> </el-button>
<el-button <el-button
class="bg-[linear-gradient(to_right,#ABB0FF_0%,#7495FF_100%)] shadow-[0_1px_8px_0_rgba(0,36,237,0.25)] border-none hover:-translate-y-1 transition-all duration-200 flex-1 text-xs sm:text-sm" class="bg-[linear-gradient(to_right,#ABB0FF_0%,#7495FF_100%)] shadow-[0_1px_8px_0_rgba(0,36,237,0.25)] border-none hover:-translate-y-1 transition-all duration-200 flex-1 text-xs sm:text-sm w-116px"
type="primary" type="primary"
@click="router.push('/pointsStore')" @click="router.push('/pointsStore')"
> >
...@@ -96,17 +113,16 @@ ...@@ -96,17 +113,16 @@
</p> </p>
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<el-button <el-button
class="bg-[linear-gradient(to_right,#A3EADC_0%,#7BE0BD_100%)] shadow-[0_1px_4px_0_rgba(168,225,210,1)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm" class="bg-[linear-gradient(to_right,#A3EADC_0%,#7BE0BD_100%)] shadow-[0_1px_4px_0_rgba(168,225,210,1)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm w-116px"
type="primary" type="primary"
@click="router.push('/publishCase')" @click="router.push('/publishCase')"
> >
<svg-icon name="submit" size="30" class="mr-2" /> <svg-icon name="submit" size="20" class="mr-2" />
<span class="text-black text-xs sm:text-sm">去投稿</span> <span class="text-black text-xs sm:text-sm">去投稿</span>
</el-button> </el-button>
</div> </div>
</div> </div>
<!-- 投稿中心-->
<div class="submit-container common-box rounded-lg bg-#EDEAFE"> <div class="submit-container common-box rounded-lg bg-#EDEAFE">
<div class="grid grid-cols-3 gap-2 sm:gap-4 mb-4"> <div class="grid grid-cols-3 gap-2 sm:gap-4 mb-4">
<div <div
...@@ -131,10 +147,11 @@ ...@@ -131,10 +147,11 @@
</div> </div>
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<el-button <el-button
class="bg-[linear-gradient(to_right,#D6C9FF_0%,#C5B1FF_100%)] shadow-[0_1px_4px_0_rgba(95,0,237,0.25)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm" class="bg-[linear-gradient(to_right,#D6C9FF_0%,#C5B1FF_100%)] shadow-[0_1px_4px_0_rgba(95,0,237,0.25)] border-none hover:-translate-y-1 transition-all duration-200 text-xs sm:text-sm w-116px"
type="primary" type="primary"
> >
<span class="text-black text-xs sm:text-sm">投稿中心</span> <svg-icon name="my_answer" size="20" class="mr-2" />
<span class="text-black text-xs sm:text-sm">我的回答</span>
</el-button> </el-button>
</div> </div>
</div> </div>
...@@ -174,7 +191,7 @@ ...@@ -174,7 +191,7 @@
class="flex flex-col items-start justify-center ml-2 sm:ml-3 min-w-0 flex-1" class="flex flex-col items-start justify-center ml-2 sm:ml-3 min-w-0 flex-1"
> >
<div class="text-14px truncate w-full font-medium mb-1"> <div class="text-14px truncate w-full font-medium mb-1">
{{ item.title }} {{ item.title }}({{ item.currentCount }}/{{ item.limitCount }})
</div> </div>
<div class="color-#333 text-xs w-full flex items-center flex-nowrap"> <div class="color-#333 text-xs w-full flex items-center flex-nowrap">
<svg-icon name="small_coin" size="16" class="mr-1" /> <svg-icon name="small_coin" size="16" class="mr-1" />
...@@ -217,14 +234,19 @@ import front from '@/assets/img/culture/front_page.png' ...@@ -217,14 +234,19 @@ import front from '@/assets/img/culture/front_page.png'
import ya from '@/assets/img/culture/ya_culture.png' import ya from '@/assets/img/culture/ya_culture.png'
import ask from '@/assets/img/culture/ask.png' import ask from '@/assets/img/culture/ask.png'
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router' import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
import { getTaskList, dailySign, getCarouselList } from '@/api' import { getTaskList, dailySign, getCarouselList, getUserAccountData, getRecordData } from '@/api'
import { TaskTypeEnum, TaskDateLimitTypeText } from '@/constants' import { TaskTypeEnum, TaskDateLimitTypeText } from '@/constants'
import type { CarouselItemDto, TaskItemDto } from '@/api' import type { CarouselItemDto, TaskItemDto, UserAccountDataDto, UserRecordDataDto } from '@/api'
import { TABS_REF_KEY } from '@/constants' import { TABS_REF_KEY, levelListOptions } from '@/constants'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const getThirdLevelKey = (route: RouteLocationNormalizedLoadedGeneric) => {
// console.log(route, '三级路由')
return route.fullPath
}
const carouselList = ref<CarouselItemDto[]>([]) const carouselList = ref<CarouselItemDto[]>([])
const tabsRef = useTemplateRef('tabsRef') const tabsRef = useTemplateRef('tabsRef')
...@@ -262,10 +284,35 @@ const currentTaskList = computed(() => ...@@ -262,10 +284,35 @@ const currentTaskList = computed(() =>
currentTask.value === TaskTypeEnum.REGULAR_TASK ? regularTaskList.value : specialTaskList.value, currentTask.value === TaskTypeEnum.REGULAR_TASK ? regularTaskList.value : specialTaskList.value,
) )
const getThirdLevelKey = (route: RouteLocationNormalizedLoadedGeneric) => { // 用户账号信息
// console.log(route, '三级路由') const userAccountData = ref<UserAccountDataDto>({} as UserAccountDataDto)
return route.fullPath const currentLevelData = computed<{
} label: string
iconUrl: string
percentage: number
expScope: [number, number]
}>(() => {
const levelData = levelListOptions.find((item) => item.value === userAccountData.value.level)!
if (!levelData) return { label: '', iconUrl: '', percentage: 0, expScope: [0, 0] }
const currExp = userAccountData.value.expTotal
const percentage = Number(
(
((currExp - levelData.expScope[0]) / (levelData.expScope[1] - levelData.expScope[0])) *
100
).toFixed(2),
)
console.log(percentage)
return {
label: levelData.label,
iconUrl: levelData.iconUrl,
percentage,
expScope: levelData.expScope,
}
})
const userRecordData = ref({} as UserRecordDataDto)
const onDailySign = async () => { const onDailySign = async () => {
await dailySign() await dailySign()
...@@ -276,7 +323,12 @@ const openPostCaseDialog = () => { ...@@ -276,7 +323,12 @@ const openPostCaseDialog = () => {
} }
const initPage = () => { const initPage = () => {
Promise.allSettled([getCarouselList(), getTaskList()]).then(([r1, r2]) => { Promise.allSettled([
getCarouselList(),
getTaskList(),
getUserAccountData(),
getRecordData(),
]).then(([r1, r2, r3, r4]) => {
if (r1.status === 'fulfilled') { if (r1.status === 'fulfilled') {
carouselList.value = r1.value.data carouselList.value = r1.value.data
} }
...@@ -288,6 +340,14 @@ const initPage = () => { ...@@ -288,6 +340,14 @@ const initPage = () => {
(item) => item.taskType === TaskTypeEnum.SPECIAL_TASK, (item) => item.taskType === TaskTypeEnum.SPECIAL_TASK,
) )
} }
if (r3.status === 'fulfilled') {
console.log(r3)
userAccountData.value = r3.value.data
}
if (r4.status === 'fulfilled') {
console.log(r4)
userRecordData.value = r4.value.data
}
}) })
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<InterviewList v-if="activeTab === '专访'" /> <InterviewList v-if="activeTab === '专访'" />
<PracticeList v-if="activeTab === '实践'" /> <PracticeList v-if="activeTab === '实践'" />
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-pagination bg-gray-50/80 backdrop-blur-8 border-t border-gray-200"> <div class="bottom-pagination backdrop-blur-8 border-t border-gray-200">
<div class="max-w-7xl mx-auto px-8 py-6"> <div class="max-w-7xl mx-auto px-8 py-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<!-- 左侧:回到顶部按钮 --> <!-- 左侧:回到顶部按钮 -->
......
...@@ -9,10 +9,13 @@ import ask from '@/assets/img/culture/ask.png' ...@@ -9,10 +9,13 @@ import ask from '@/assets/img/culture/ask.png'
type ExchangeContentProps = { type ExchangeContentProps = {
item: ShopItem item: ShopItem
type: ShopGoodsTypeEnum type: ShopGoodsTypeEnum
modelValue: string modelValue: {
region: string
num: number
}
} }
type ExchangeContentEvents = { type ExchangeContentEvents = {
'update:modelValue'(message: string): void 'update:modelValue'(data: { region: string; num: number }): void
} }
export default function ExchangeContent( export default function ExchangeContent(
...@@ -56,8 +59,10 @@ export default function ExchangeContent( ...@@ -56,8 +59,10 @@ export default function ExchangeContent(
<div class="text-center text-gray-700 text-sm font-medium mb-4">选择办公点:</div> <div class="text-center text-gray-700 text-sm font-medium mb-4">选择办公点:</div>
<div class=" w-full"> <div class=" w-full">
<el-select <el-select
modelValue={modelValue} modelValue={modelValue.region}
onUpdate:modelValue={(value: string) => context.emit('update:modelValue', value)} onUpdate:modelValue={(value: string) =>
context.emit('update:modelValue', { ...modelValue, region: value })
}
placeholder="请选择办公点" placeholder="请选择办公点"
> >
{regionListOptions.map((office) => ( {regionListOptions.map((office) => (
...@@ -69,6 +74,14 @@ export default function ExchangeContent( ...@@ -69,6 +74,14 @@ export default function ExchangeContent(
/> />
))} ))}
</el-select> </el-select>
选择数量
<el-input-number
modelValue={modelValue.num}
onUpdate:modelValue={(value: number) =>
context.emit('update:modelValue', { ...modelValue, num: value })
}
placeholder="请选择数量"
/>
</div> </div>
</div> </div>
)} )}
...@@ -82,8 +95,8 @@ ExchangeContent.props = { ...@@ -82,8 +95,8 @@ ExchangeContent.props = {
required: true, required: true,
}, },
modelValue: { modelValue: {
type: String, type: Object as PropType<{ region: string; num: number }>,
required: false, required: true,
}, },
type: { type: {
type: Number, type: Number,
...@@ -92,5 +105,5 @@ ExchangeContent.props = { ...@@ -92,5 +105,5 @@ ExchangeContent.props = {
} }
ExchangeContent.emits = { ExchangeContent.emits = {
'update:modelValue': (value: string) => value, 'update:modelValue': (value: { region: string; num: number }) => value,
} }
...@@ -34,6 +34,18 @@ ...@@ -34,6 +34,18 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 分页 -->
<div class="flex justify-end mt-4">
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-3 w-fit">
<el-pagination
v-model:current-page="virtualGoodsSearchParams.current"
v-model:page-size="virtualGoodsSearchParams.size"
:total="virtualGoodsTotal"
@current-change="virtualGoodsGoToPage"
@size-change="virtualGoodsChangePageSize"
/>
</div>
</div>
</div> </div>
<!-- 实物奖品 --> <!-- 实物奖品 -->
...@@ -68,48 +80,6 @@ ...@@ -68,48 +80,6 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 右侧栏 -->
<!-- <div class="hidden lg:flex flex-col gap-4 basis-1/4 transition-all duration-500">
<div class="bg-[#e0e7ff] rounded-2xl p-5 shadow flex flex-col items-center text-center">
<div
class="w-20 h-20 bg-gradient-to-br from-[#a5b4fc] to-[#818cf8] rounded-full mb-3"
></div>
<div class="text-gray-700 font-semibold">等级:LV1</div>
<div class="text-gray-500 mb-3">YAYA币:8888</div>
<button
class="px-4 py-2 rounded-full bg-gradient-to-r from-[#f59e0b] to-[#f97316] text-white mb-2"
>
立即签到
</button>
<button>大啊啊啊啊啊啊啊啊啊啊啊</button>
<button
class="px-4 py-2 rounded-full bg-gradient-to-r from-[#a78bfa] to-[#6366f1] text-white"
>
积分兑换
</button>
</div>
<div class="bg-[#f3e8ff] rounded-2xl p-5 shadow text-center">
<div class="text-gray-700 font-semibold mb-2">YAYA案例库</div>
<p class="text-sm text-gray-500 mb-3">案例库说明文字,可放两行以内</p>
<button
class="px-4 py-1.5 rounded-full bg-gradient-to-r from-[#8b5cf6] to-[#6366f1] text-white text-sm"
>
去投稿
</button>
</div>
<div class="bg-[#e0f2fe] rounded-2xl p-5 shadow text-center">
<div class="text-gray-700 font-semibold mb-2">任务中心</div>
<p class="text-sm text-gray-500 mb-3">完成任务领取积分奖励</p>
<button
class="px-4 py-1.5 rounded-full bg-gradient-to-r from-[#60a5fa] to-[#3b82f6] text-white text-sm"
>
查看任务
</button>
</div>
</div> -->
</div> </div>
<div class="mt-40 text-center text-sm text-gray-500 mb-4"> <div class="mt-40 text-center text-sm text-gray-500 mb-4">
实物商品兑换后清联系相关负责人领取奖励 —— 实物商品兑换后清联系相关负责人领取奖励 ——
...@@ -137,7 +107,13 @@ const exchangeRecordDialogRef = ...@@ -137,7 +107,13 @@ const exchangeRecordDialogRef =
useTemplateRef<InstanceType<typeof ExchangeRecordDialog>>('exchangeRecordDialogRef') useTemplateRef<InstanceType<typeof ExchangeRecordDialog>>('exchangeRecordDialogRef')
// 虚拟商品 // 虚拟商品
const { list: virtualGoodsList } = usePageSearch(getShopItemList, { const {
list: virtualGoodsList,
goToPage: virtualGoodsGoToPage,
changePageSize: virtualGoodsChangePageSize,
searchParams: virtualGoodsSearchParams,
total: virtualGoodsTotal,
} = usePageSearch(getShopItemList, {
defaultParams: { defaultParams: {
goodsType: ShopGoodsTypeEnum.VIRTUAL_GOODS, goodsType: ShopGoodsTypeEnum.VIRTUAL_GOODS,
}, },
...@@ -147,7 +123,9 @@ const { list: virtualGoodsList } = usePageSearch(getShopItemList, { ...@@ -147,7 +123,9 @@ const { list: virtualGoodsList } = usePageSearch(getShopItemList, {
const { const {
list: realGoodsList, list: realGoodsList,
goToPage: realGoodsGoToPage, goToPage: realGoodsGoToPage,
changePageSize: realGoodsChangePageSize,
searchParams: realGoodsSearchParams, searchParams: realGoodsSearchParams,
total: realGoodsTotal,
} = usePageSearch(getShopItemList, { } = usePageSearch(getShopItemList, {
defaultParams: { defaultParams: {
goodsType: ShopGoodsTypeEnum.REAL_GOODS, goodsType: ShopGoodsTypeEnum.REAL_GOODS,
...@@ -173,18 +151,23 @@ const getYaBiDataFn = async () => { ...@@ -173,18 +151,23 @@ const getYaBiDataFn = async () => {
const onExchangeGoods = async (item: ShopItem, type: ShopGoodsTypeEnum) => { const onExchangeGoods = async (item: ShopItem, type: ShopGoodsTypeEnum) => {
// if (currentYaBi.value < item.price) return ElMessage.error('YA币不足') // if (currentYaBi.value < item.price) return ElMessage.error('YA币不足')
const selectedRegion = ref('广州') const form = ref({
region: '广州',
itemId: item.id,
num: 1,
})
await ElMessageBox({ await ElMessageBox({
title: 'YA币兑换', title: 'YA币兑换',
message: () => ( message: () => (
// @ts-ignore // @ts-ignore
<ExchangeContent item={item} type={type} v-model={selectedRegion.value}></ExchangeContent> <ExchangeContent item={item} type={type} v-model={form.value}></ExchangeContent>
), ),
confirmButtonText: '确认兑换', confirmButtonText: '确认兑换',
cancelButtonText: '取消', cancelButtonText: '取消',
showCancelButton: true, showCancelButton: true,
center: true, center: true,
}) })
console.log(form.value)
} }
onMounted(async () => { onMounted(async () => {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<!-- 案例编号 --> <!-- 案例编号 -->
<div class="mb-6 flex items-center gap-2"> <div class="mb-6 flex items-center gap-2">
<span class="text-gray-700 font-medium">案例编号:</span> <span class="text-gray-700 font-medium">案例编号:</span>
<span class="text-gray-900 font-semibold">000001</span> <span class="text-gray-900 font-semibold">{{ form.number }}</span>
<el-tooltip content="案例编号自动生成" placement="top"> <el-tooltip content="案例编号自动生成" placement="top">
<el-icon class="text-pink-500 cursor-pointer"> <el-icon class="text-pink-500 cursor-pointer">
<QuestionFilled /> <QuestionFilled />
...@@ -41,35 +41,31 @@ ...@@ -41,35 +41,31 @@
<!-- 关键词选择 --> <!-- 关键词选择 -->
<el-form-item label="文化关键词" class="mb-6"> <el-form-item label="文化关键词" class="mb-6">
<div class="flex flex-wrap gap-3"> <div class="flex flex-wrap gap-3">
<SelectTags v-model="form.tagList" /> 主标签
<SelectTags v-model="form.mainTagId" />
</div> </div>
</el-form-item> </el-form-item>
<!-- 上传人 --> <el-form-item class="mb-6">
<el-form-item class="mb-6" label="上传人"> <div class="flex flex-wrap gap-3">
<el-input 副标签
v-model="form.uploadUser" <SelectTags
placeholder="请输入【案例】上传人" v-model="form.subTagIds"
:maxlength="100" :max-selected-tags="3"
show-word-limit :filter-tags-fn="filterTagsFn"
size="large" />
class="text-lg" </div>
/>
</el-form-item>
<!-- 上传时间 -->
<el-form-item class="mb-6" label="上传时间">
<el-input v-model="form.uploadTime" placeholder="请输入【案例】上传时间" />
</el-form-item> </el-form-item>
<!-- 是否同步发布 --> <!-- 是否同步发布 -->
<el-form-item label="*是否同步发布到实践" class="mb-6"> <!-- <el-form-item label="*是否同步发布到实践" class="mb-6">
<el-radio-group v-model="form.publishToPractice"> <el-radio-group v-model="form.publishToPractice">
<el-radio :label="true"></el-radio> <el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="false"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item> -->
<!-- 发布时间 --> <!-- 发布时间 -->
<el-form-item label="*发布时间" class="mb-8"> <!-- <el-form-item label="*发布时间" class="mb-8">
<el-radio-group v-model="form.publishTime"> <el-radio-group v-model="form.publishTime">
<el-radio label="now">立即发布</el-radio> <el-radio label="now">立即发布</el-radio>
<el-radio label="scheduled">定时发布</el-radio> <el-radio label="scheduled">定时发布</el-radio>
...@@ -81,7 +77,7 @@ ...@@ -81,7 +77,7 @@
placeholder="选择发布时间" placeholder="选择发布时间"
class="ml-4" class="ml-4"
/> />
</el-form-item> </el-form-item> -->
<!-- 底部按钮组 --> <!-- 底部按钮组 -->
<div class="flex items-center justify-between gap-4 pt-4"> <div class="flex items-center justify-between gap-4 pt-4">
...@@ -102,17 +98,27 @@ ...@@ -102,17 +98,27 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { QuestionFilled } from '@element-plus/icons-vue' import { QuestionFilled } from '@element-plus/icons-vue'
import { addOrUpdateCase } from '@/api/case' import { addOrUpdateCase, getMaxCaseNumber } from '@/api'
import { useResetData } from '@/hooks' import { useResetData } from '@/hooks'
import type { AddOrUpdateCaseDto } from '@/api/case/types' import type { AddOrUpdateCaseDto } from '@/api'
import SelectTags from '@/components/common/SelectTags/index.vue' import SelectTags from '@/components/common/SelectTags/index.vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import type { TagItemDto } from '@/api'
import { TagTypeEnum, TagLevelEnum } from '@/constants'
const formRef = useTemplateRef<FormInstance>('formRef') const formRef = useTemplateRef<FormInstance>('formRef')
const [form, resetForm] = useResetData<AddOrUpdateCaseDto>({
type FormData = Omit<AddOrUpdateCaseDto, 'tagRelationDtoList'> & {
mainTagId: string
subTagIds: number[]
}
const [form] = useResetData<FormData>({
title: '', title: '',
content: '', content: '',
tagList: [], number: '',
mainTagId: '',
subTagIds: [],
}) })
// 取消 // 取消
...@@ -133,10 +139,31 @@ const handleSaveDraft = () => { ...@@ -133,10 +139,31 @@ const handleSaveDraft = () => {
ElMessage.success('草稿保存成功') ElMessage.success('草稿保存成功')
} }
const transformData = (formData: FormData): AddOrUpdateCaseDto => {
const { mainTagId, subTagIds, ...rest } = formData
const obj: AddOrUpdateCaseDto = {
...rest,
tagRelationDtoList: [],
}
obj.tagRelationDtoList.push({
tagId: Number(mainTagId),
type: TagTypeEnum.CULTURE_TAG,
keywordType: TagLevelEnum.MAIN_TAG,
})
subTagIds.forEach((id) => {
obj.tagRelationDtoList.push({
tagId: id,
type: TagTypeEnum.CULTURE_TAG,
keywordType: TagLevelEnum.SUB_TAG,
})
})
return obj
}
// 提交 // 提交
const handleSubmit = async () => { const handleSubmit = async () => {
await formRef.value?.validate() await formRef.value?.validate()
const res = await addOrUpdateCase(form.value) const res = await addOrUpdateCase(transformData(form.value))
if (res) { if (res) {
ElMessage.success('提交成功') ElMessage.success('提交成功')
} }
...@@ -202,8 +229,18 @@ const showSubmissionGuide = () => { ...@@ -202,8 +229,18 @@ const showSubmissionGuide = () => {
}) })
} }
const filterTagsFn = (allTags: TagItemDto[]) => {
return allTags.filter((tag) => tag.id !== Number(form.value.mainTagId))
}
const fetchMaxCaseNumber = async () => {
const { data } = await getMaxCaseNumber()
form.value.number = data
}
onActivated(() => { onActivated(() => {
showSubmissionGuide() showSubmissionGuide()
fetchMaxCaseNumber()
}) })
</script> </script>
......
<template>
<div class="flex-1 flex flex-col" v-loading="loading">
<!-- List Container -->
<div class="flex-1 p-4 pt-1">
<div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<div v-else class="space-y-4">
<div
v-for="item in list"
:key="item.id"
class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
>
<!-- Content -->
<div class="flex-1 min-w-0">
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<div class="text-gray-500 text-sm mt-1 truncate">
<span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<span class="mr-2">浏览 {{ item.viewCount }}</span>
<span class="mr-2">点赞 {{ item.replyCount }}</span>
<span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div>
</div>
<!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link>编辑</el-button>
<el-button type="danger" link>删除</el-button>
</div>
</div>
</div>
</div>
<div
v-if="list.length"
class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
>
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
@size-change="changePageSize"
@current-change="goToPage"
:page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total"
:total="total"
class="custom-pagination"
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { Document } from '@element-plus/icons-vue'
import { getSelfCaseList } from '@/api'
import { usePageSearch } from '@/hooks'
import { articleTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
const toggleTab = (key: string) => {
searchParams.value.type = key
refresh()
}
// State
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } =
usePageSearch(getSelfCaseList)
// Computed
const paginatedList = computed(() => {
const start = (searchParams.value.current - 1) * searchParams.value.size
const end = start + searchParams.value.size
return list.value.slice(start, end)
})
const getEmptyText = () => {
const emptyTexts: Record<string, string> = {
posts: '还没有发布任何帖子',
videos: '还没有上传任何视频',
questions: '还没有提出任何问题',
articles: '还没有发表任何专栏文章',
practice: '还没有分享任何实践经验',
interviews: '还没有参与任何专访',
}
return emptyTexts[searchParams.type] || '暂无数据'
}
</script>
<template> <template>
<div class="w-full h-full bg-white rounded-lg overflow-hidden"> <div class="flex-1 flex flex-col" v-loading="loading">
<!-- Custom Tabs (保持原样式) --> <!-- List Container -->
<div class="flex border-b border-gray-200"> <div class="flex-1 p-4 pt-1">
<div <el-tabs v-model="searchParams.type" @tab-change="toggleTab">
v-for="tab in tabs" <el-tab-pane
:key="tab.key" v-for="tab in articleTypeListOptions"
class="px-6 py-4 cursor-pointer text-gray-600 hover:text-blue-500 transition-colors relative" :key="tab.value"
:class="[ :label="tab.label"
searchParams.type === tab.key :name="tab.value"
? 'text-blue-500! font-medium' />
: 'text-gray-600 hover:text-blue-400', </el-tabs>
]"
@click="toggleTab(tab.key)"
>
{{ tab.label }}
</div>
</div>
<!-- Content Area -->
<div class="flex-1 flex flex-col">
<!-- List Container -->
<div class="flex-1 p-6">
<!-- Loading State -->
<div v-if="loading" class="flex items-center justify-center h-64">
<el-icon class="is-loading mr-2 text-gray-500"><Loading /></el-icon>
<span class="text-gray-500">加载中...</span>
</div>
<!-- Empty State --> <div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div v-else-if="!list.length" class="flex flex-col items-center justify-center h-64"> <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4"> <el-icon class="text-2xl text-gray-300"><Document /></el-icon>
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div> </div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<!-- List Items --> <div v-else class="space-y-4">
<div v-else class="space-y-4"> <div
<div v-for="item in list"
v-for="item in paginatedList" :key="item.id"
:key="item.id" class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
class="flex items-center p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer" >
> <!-- Content -->
<!-- Avatar --> <div class="flex-1 min-w-0">
<el-avatar class="mr-4 flex-shrink-0" :size="48" style="background-color: #e5f3ff"> <div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<el-icon class="text-blue-500"><User /></el-icon> <div class="text-gray-500 text-sm mt-1 truncate">
</el-avatar> <span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
<!-- Content --> </span>
<div class="flex-1 min-w-0"> <span class="mr-2">浏览 {{ item.viewCount }}</span>
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div> <span class="mr-2">点赞 {{ item.replyCount }}</span>
<div class="text-gray-500 text-sm mt-1 truncate">{{ item.description }}</div> <span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div> </div>
</div>
<!-- Meta Info --> <!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4"> <div class="flex items-center text-gray-400 text-sm ml-4">
<el-icon class="mr-1"><Clock /></el-icon> <el-button type="primary" link>编辑</el-button>
<span>{{ item.time }}</span> <el-button type="danger" link>删除</el-button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- Custom Pagination (保持原样式) --> <div
<div v-if="list.length"
v-if="list.length" class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
class="flex items-center justify-between px-6 py-4 border-t border-gray-200" >
> <div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<div class="right"> <el-pagination
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3"> v-model:current-page="searchParams.current"
<el-pagination v-model:page-size="searchParams.size"
v-model:current-page="searchParams.current" @size-change="changePageSize"
v-model:page-size="searchParams.size" @current-change="goToPage"
:page-sizes="[10, 20, 30, 40]" :page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total" layout="prev, pager, next, jumper, total"
:total="total" :total="total"
class="custom-pagination" class="custom-pagination"
/> />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Loading, User, Clock, Document } from '@element-plus/icons-vue' import { Document } from '@element-plus/icons-vue'
import { getSelfCollectList } from '@/api' import { getSelfCollectList } from '@/api'
import { usePageSearch } from '@/hooks' import { usePageSearch } from '@/hooks'
import { ArticleTypeEnum } from '@/constants' import { articleTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
interface TabItem {
key: string
label: string
}
const toggleTab = (key: string) => { const toggleTab = (key: string) => {
searchParams.value.type = key searchParams.value.type = key
refresh() refresh()
} }
const tabs: TabItem[] = [
{ key: 'posts', label: '帖子' },
{ key: 'videos', label: '视频' },
{ key: 'questions', label: '问题' },
{ key: 'articles', label: '专栏' },
{ key: 'practice', label: '实践' },
{ key: 'interviews', label: '专访' },
]
// State // State
const { list, loading, searchParams, total, refresh } = usePageSearch(getSelfCollectList, { const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
defaultParams: { getSelfCollectList,
type: ArticleTypeEnum.POST, {
defaultParams: {
type: ArticleTypeEnum.POST,
},
}, },
}) )
// Computed // Computed
const paginatedList = computed(() => { const paginatedList = computed(() => {
......
<template>
<div class="flex-1 flex flex-col" v-loading="loading">
<!-- List Container -->
<div class="flex-1 p-4 pt-1">
<el-tabs v-model="searchParams.type" @tab-change="toggleTab">
<el-tab-pane
v-for="tab in articleTypeListOptions"
:key="tab.value"
:label="tab.label"
:name="tab.value"
/>
</el-tabs>
<div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<div v-else class="space-y-4">
<div
v-for="item in list"
:key="item.id"
class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
>
<!-- Content -->
<div class="flex-1 min-w-0">
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<div class="text-gray-500 text-sm mt-1 truncate">
<span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<span class="mr-2">浏览 {{ item.viewCount }}</span>
<span class="mr-2">点赞 {{ item.replyCount }}</span>
<span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div>
</div>
<!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link>编辑</el-button>
<el-button type="danger" link>删除</el-button>
</div>
</div>
</div>
</div>
<div
v-if="list.length"
class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
>
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
@size-change="changePageSize"
@current-change="goToPage"
:page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total"
:total="total"
class="custom-pagination"
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { Document } from '@element-plus/icons-vue'
import { getSelfDraftList } from '@/api'
import { usePageSearch } from '@/hooks'
import { articleTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
const toggleTab = (key: string) => {
searchParams.value.type = key
refresh()
}
// State
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
getSelfDraftList,
{
defaultParams: {
type: ArticleTypeEnum.POST,
},
},
)
// Computed
const paginatedList = computed(() => {
const start = (searchParams.value.current - 1) * searchParams.value.size
const end = start + searchParams.value.size
return list.value.slice(start, end)
})
const getEmptyText = () => {
const emptyTexts: Record<string, string> = {
posts: '还没有发布任何帖子',
videos: '还没有上传任何视频',
questions: '还没有提出任何问题',
articles: '还没有发表任何专栏文章',
practice: '还没有分享任何实践经验',
interviews: '还没有参与任何专访',
}
return emptyTexts[searchParams.type] || '暂无数据'
}
</script>
<template> <template>
<div class="w-full h-full bg-white rounded-lg overflow-hidden"> <div class="flex-1 flex flex-col" v-loading="loading">
<!-- Custom Tabs (保持原样式) --> <!-- List Container -->
<div class="flex border-b border-gray-200"> <div class="flex-1 p-4 pt-1">
<div <el-tabs v-model="searchParams.type" @tab-change="toggleTab">
v-for="tab in tabs" <el-tab-pane
:key="tab.key" v-for="tab in articleTypeListOptions"
class="px-6 py-4 cursor-pointer text-gray-600 hover:text-blue-500 transition-colors relative" :key="tab.value"
:class="[ :label="tab.label"
searchParams.type === tab.key :name="tab.value"
? 'text-blue-500! font-medium' />
: 'text-gray-600 hover:text-blue-400', </el-tabs>
]"
@click="toggleTab(tab.key)"
>
{{ tab.label }}
</div>
</div>
<!-- Content Area -->
<div class="flex-1 flex flex-col">
<!-- List Container -->
<div class="flex-1 p-6">
<!-- Loading State -->
<div v-if="loading" class="flex items-center justify-center h-64">
<el-icon class="is-loading mr-2 text-gray-500"><Loading /></el-icon>
<span class="text-gray-500">加载中...</span>
</div>
<!-- Empty State --> <div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div v-else-if="!list.length" class="flex flex-col items-center justify-center h-64"> <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4"> <el-icon class="text-2xl text-gray-300"><Document /></el-icon>
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div> </div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<!-- List Items --> <div v-else class="space-y-4">
<div v-else class="space-y-4"> <div
<div v-for="item in list"
v-for="item in paginatedList" :key="item.id"
:key="item.id" class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
class="flex items-center p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer" >
> <!-- Content -->
<!-- Avatar --> <div class="flex-1 min-w-0">
<el-avatar class="mr-4 flex-shrink-0" :size="48" style="background-color: #e5f3ff"> <div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<el-icon class="text-blue-500"><User /></el-icon> <div class="text-gray-500 text-sm mt-1 truncate">
</el-avatar> <span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
<!-- Content --> </span>
<div class="flex-1 min-w-0"> <span class="mr-2">浏览 {{ item.viewCount }}</span>
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div> <span class="mr-2">点赞 {{ item.replyCount }}</span>
<div class="text-gray-500 text-sm mt-1 truncate">{{ item.description }}</div> <span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div> </div>
</div>
<!-- Meta Info --> <!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4"> <div class="flex items-center text-gray-400 text-sm ml-4">
<el-icon class="mr-1"><Clock /></el-icon> <el-button type="primary" link>编辑</el-button>
<span>{{ item.time }}</span> <el-button type="danger" link>删除</el-button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- Custom Pagination (保持原样式) --> <div
<div v-if="list.length"
v-if="list.length" class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
class="flex items-center justify-between px-6 py-4 border-t border-gray-200" >
> <div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<div class="right"> <el-pagination
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3"> v-model:current-page="searchParams.current"
<el-pagination v-model:page-size="searchParams.size"
v-model:current-page="searchParams.current" @size-change="changePageSize"
v-model:page-size="searchParams.size" @current-change="goToPage"
:page-sizes="[10, 20, 30, 40]" :page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total" layout="prev, pager, next, jumper, total"
:total="total" :total="total"
class="custom-pagination" class="custom-pagination"
/> />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Loading, User, Clock, Document } from '@element-plus/icons-vue' import { Document } from '@element-plus/icons-vue'
import { getSelfPraiseList } from '@/api' import { getSelfPraiseList } from '@/api'
import { usePageSearch } from '@/hooks' import { usePageSearch } from '@/hooks'
import { ArticleTypeEnum } from '@/constants' import { articleTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
interface TabItem {
key: string
label: string
}
const toggleTab = (key: string) => { const toggleTab = (key: string) => {
searchParams.value.type = key searchParams.value.type = key
refresh() refresh()
} }
const tabs: TabItem[] = [
{ key: 'posts', label: '帖子' },
{ key: 'videos', label: '视频' },
{ key: 'questions', label: '问题' },
{ key: 'articles', label: '专栏' },
{ key: 'practice', label: '实践' },
{ key: 'interviews', label: '专访' },
]
// State // State
const { list, loading, searchParams, total, refresh } = usePageSearch(getSelfPraiseList, { const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
defaultParams: { getSelfPraiseList,
type: ArticleTypeEnum.POST, {
defaultParams: {
type: ArticleTypeEnum.POST,
},
}, },
}) )
// Computed // Computed
const paginatedList = computed(() => { const paginatedList = computed(() => {
......
<template>
<div class="flex-1 flex flex-col" v-loading="loading">
<!-- List Container -->
<div class="flex-1 p-4 pt-1">
<el-tabs v-model="searchParams.type" @tab-change="toggleTab">
<el-tab-pane
v-for="tab in articleTypeListOptions"
:key="tab.value"
:label="tab.label"
:name="tab.value"
/>
</el-tabs>
<div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<div v-else class="space-y-4">
<div
v-for="item in list"
:key="item.id"
class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
>
<!-- Content -->
<div class="flex-1 min-w-0">
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<div class="text-gray-500 text-sm mt-1 truncate">
<span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<span class="mr-2">浏览 {{ item.viewCount }}</span>
<span class="mr-2">点赞 {{ item.replyCount }}</span>
<span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div>
</div>
<!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link>编辑</el-button>
<el-button type="danger" link>删除</el-button>
</div>
</div>
</div>
</div>
<div
v-if="list.length"
class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
>
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
@size-change="changePageSize"
@current-change="goToPage"
:page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total"
:total="total"
class="custom-pagination"
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { Document } from '@element-plus/icons-vue'
import { getSelfPublishList } from '@/api'
import { usePageSearch } from '@/hooks'
import { articleTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
const toggleTab = (key: string) => {
searchParams.value.type = key
refresh()
}
// State
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
getSelfPublishList,
{
defaultParams: {
type: ArticleTypeEnum.POST,
},
},
)
// Computed
const paginatedList = computed(() => {
const start = (searchParams.value.current - 1) * searchParams.value.size
const end = start + searchParams.value.size
return list.value.slice(start, end)
})
const getEmptyText = () => {
const emptyTexts: Record<string, string> = {
posts: '还没有发布任何帖子',
videos: '还没有上传任何视频',
questions: '还没有提出任何问题',
articles: '还没有发表任何专栏文章',
practice: '还没有分享任何实践经验',
interviews: '还没有参与任何专访',
}
return emptyTexts[searchParams.type] || '暂无数据'
}
</script>
<template>
<div class="flex-1 flex flex-col" v-loading="loading">
<!-- List Container -->
<div class="flex-1 p-4 pt-1">
<el-tabs v-model="searchParams.taskType" @tab-change="toggleTab">
<el-tab-pane
v-for="tab in taskTypeListOptions"
:key="tab.value"
:label="tab.label"
:name="tab.value"
/>
</el-tabs>
<div v-if="!list.length" class="flex flex-col items-center justify-center h-64">
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
<el-icon class="text-2xl text-gray-300"><Document /></el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
<div class="text-gray-400 text-sm">{{ getEmptyText() }}</div>
</div>
<div v-else class="space-y-4">
<div
v-for="item in list"
:key="item.id"
class="flex items-center p-2 rounded-lg hover:bg-gray-100 transition-colors cursor-pointer"
>
<!-- Content -->
<div class="flex-1 min-w-0">
<div class="text-gray-900 font-medium truncate">{{ item.title }}</div>
<div class="text-gray-500 text-sm mt-1 truncate">
<span class="mr-2">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<span class="mr-2">浏览 {{ item.viewCount }}</span>
<span class="mr-2">点赞 {{ item.replyCount }}</span>
<span class="mr-2">评论 {{ item.collectionCount }}</span>
<span class="mr-2">收藏 {{ item.praiseCount }}</span>
</div>
</div>
<!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link>编辑</el-button>
<el-button type="danger" link>删除</el-button>
</div>
</div>
</div>
</div>
<div
v-if="list.length"
class="flex items-center justify-end px-6 py-4 border-t border-gray-200"
>
<div class="pagination-wrapper bg-white rounded-xl shadow-sm border border-gray-100 p-3">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
@size-change="changePageSize"
@current-change="goToPage"
:page-sizes="[10, 20, 30, 40]"
layout="prev, pager, next, jumper, total"
:total="total"
class="custom-pagination"
/>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { Document } from '@element-plus/icons-vue'
import { getSelfTaskList } from '@/api'
import { usePageSearch } from '@/hooks'
import { taskTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { TaskTypeEnum } from '@/constants/enums'
const toggleTab = (key: string) => {
searchParams.value.taskType = key
refresh()
}
// State
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
getSelfTaskList,
{
defaultParams: {
taskType: TaskTypeEnum.REGULAR_TASK,
},
},
)
// Computed
const paginatedList = computed(() => {
const start = (searchParams.value.current - 1) * searchParams.value.size
const end = start + searchParams.value.size
return list.value.slice(start, end)
})
const getEmptyText = () => {
const emptyTexts: Record<string, string> = {
posts: '还没有发布任何帖子',
videos: '还没有上传任何视频',
questions: '还没有提出任何问题',
articles: '还没有发表任何专栏文章',
practice: '还没有分享任何实践经验',
interviews: '还没有参与任何专访',
}
return emptyTexts[searchParams.value.taskType] || '暂无数据'
}
</script>
<template> <template>
<div class="min-h-screen bg-gray-50 mt-2 rounded-lg"> <div class="min-h-screen bg-gray-50 rounded-lg">
<!-- 顶部背景区域 --> <!-- 顶部背景区域 -->
<div class="box relative h-200px bg-gradient-to-r from-purple-400 via-pink-300 to-blue-300"> <div class="box relative h-200px bg-gradient-to-r from-purple-400 via-pink-300 to-blue-300">
<!-- 顶部操作按钮 --> <!-- 顶部操作按钮 -->
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
</div> </div>
<!-- 主要内容区域 --> <!-- 主要内容区域 -->
<div class="relative -mt-20 px-6"> <div class="relative -mt-20 p-6">
<div class="flex gap-6"> <div class="flex gap-6">
<!-- 左侧个人信息卡片 --> <!-- 左侧个人信息卡片 -->
<div class="w-300px"> <div class="w-300px">
...@@ -121,7 +121,6 @@ ...@@ -121,7 +121,6 @@
import { import {
Edit, Edit,
User, User,
Calendar,
Trophy, Trophy,
Document, Document,
Star, Star,
...@@ -129,12 +128,19 @@ import { ...@@ -129,12 +128,19 @@ import {
Link, Link,
View, View,
Setting, Setting,
Pointer,
Collection,
Finished,
} from '@element-plus/icons-vue' } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import EditUserInfo from './components/editUserInfo.vue' import EditUserInfo from './components/editUserInfo.vue'
import SelfCollect from './components/selfCollect.vue' import SelfCollect from './components/selfCollect.vue'
import SelfPraise from './components/selfPraise.vue' import SelfPraise from './components/selfPraise.vue'
import SelfPublish from './components/selfPublish.vue'
import SelfDraft from './components/selfDraft.vue'
import SelfCase from './components/selfCase.vue'
import SelfTask from './components/selfTask.vue'
import { hasOfficialAccount } from '@/api' import { hasOfficialAccount } from '@/api'
const editUserInfoRef = useTemplateRef<InstanceType<typeof EditUserInfo>>('editUserInfoRef') const editUserInfoRef = useTemplateRef<InstanceType<typeof EditUserInfo>>('editUserInfoRef')
...@@ -152,12 +158,14 @@ const currentPage = ref(1) ...@@ -152,12 +158,14 @@ const currentPage = ref(1)
// 左侧菜单项 // 左侧菜单项
const menuItems = [ const menuItems = [
{ key: 'posts', label: '我的帖子', icon: User }, { key: 'posts', label: '我的帖子', icon: User, component: SelfPublish, tab: '发布' },
{ key: 'activity', label: '我的活动', icon: Calendar }, { key: 'activity', label: '我的草稿', icon: Document, component: SelfDraft, tab: '草稿' },
{ key: 'favorites', label: '我的收藏', icon: Star, component: SelfCollect, tab: '收藏' },
{ key: 'praise', label: '我的点赞', icon: Pointer, component: SelfPraise, tab: '点赞' },
{ key: 'case', label: '我的案例库', icon: Collection, component: SelfCase, tab: '案例库' },
{ key: 'task', label: '我的任务', icon: Finished, component: SelfTask, tab: '任务' },
{ key: 'votes', label: '我的投票', icon: Trophy }, { key: 'votes', label: '我的投票', icon: Trophy },
{ key: 'articles', label: '我的文章', icon: Document }, { key: 'articles', label: '我的文章', icon: Document },
{ key: 'favorites', label: '我的收藏', icon: Star, component: SelfCollect },
{ key: 'praise', label: '我的点赞', icon: Star, component: SelfPraise },
{ key: 'comments', label: '评论回复', icon: ChatDotRound }, { key: 'comments', label: '评论回复', icon: ChatDotRound },
{ key: 'follows', label: '获赞列表', icon: Trophy }, { key: 'follows', label: '获赞列表', icon: Trophy },
{ key: 'social', label: '关注和粉', icon: Link }, { key: 'social', label: '关注和粉', icon: Link },
......
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