Commit 21438b37 by lijiabin

【需求 17679】 wip: 继续完善专栏 专访等内容

parent 14475b0a
import service from '@/utils/request/index' import service from '@/utils/request/index'
import type { AddOrUpdateArticleDto, ArticleItemDto, ArticleSearchParams } from './types' import type {
AddOrUpdateArticleDto,
ArticleItemDto,
ArticleSearchParams,
InterviewItemDto,
ColumnItemDto,
} from './types'
import type { BackendServicePageResult } from '@/utils/request/types' import type { BackendServicePageResult } from '@/utils/request/types'
import { ArticleTypeEnum } from '@/constants' import { ArticleTypeEnum } from '@/constants'
// 文章相关的接口(帖子 视频 实践等) // 文章相关的接口(帖子 视频 实践等)
/** /**
* 发布文章 * 发布文章 暂时由 有帖子 专栏 专访
*/ */
export const addOrUpdateArticle = (data: AddOrUpdateArticleDto) => { export const addOrUpdateArticle = (data: AddOrUpdateArticleDto) => {
return service.request<boolean>({ return service.request<boolean>({
...@@ -47,3 +53,23 @@ export const addOrCancelCollect = (data: { articleId: number | string; type: Art ...@@ -47,3 +53,23 @@ export const addOrCancelCollect = (data: { articleId: number | string; type: Art
data, data,
}) })
} }
/**
* 获取专访列表--不分页
*/
export const getInterviewList = () => {
return service.request<InterviewItemDto[]>({
url: '/api/cultureColumn/listNoPage?type=interview',
method: 'POST',
})
}
/**
* 获取专栏列表-- 不分页
*/
export const getColumnList = () => {
return service.request<ColumnItemDto[]>({
url: '/api/cultureColumn/listNoPage?type=column',
method: 'POST',
})
}
import { ArticleTypeEnum, ReleaseStatusTypeEnum, BooleanFlag } from '@/constants' import { ArticleTypeEnum, ReleaseStatusTypeEnum, BooleanFlag, SendTypeEnum } from '@/constants'
import type { PageSearchParams } from '@/utils/request/types' import type { PageSearchParams } from '@/utils/request/types'
/** /**
...@@ -11,45 +11,87 @@ export interface ArticleSearchParams extends PageSearchParams { ...@@ -11,45 +11,87 @@ export interface ArticleSearchParams extends PageSearchParams {
/** /**
* 添加或更新文章DTO(带枚举版本) * 添加或更新文章DTO(带枚举版本)
*/ */
export interface AddOrUpdateArticleDto { export type AddOrUpdateArticleDto =
/** 内容 */ | AddOrUpdatePostDto
content?: string | AddOrUpdateColumnDto
| AddOrUpdateInterviewDto
/** 创建人id */ /**
createUserId?: number * 添加帖子的DTO
*/
/** 描述 */ export interface AddOrUpdatePostDto {
description?: string id?: number
title: string
/** 封面图 */ content: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string faceUrl?: string
imgUrl?: string
sendTime?: string
type: ArticleTypeEnum.POST
}
/** id,编辑时必传 */ interface AddOrUpdateColumnBase {
id?: number id?: number
type: ArticleTypeEnum.COLUMN
title: string
content: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string
imgUrl?: string
// 关联的专栏栏目
relateColumn: number
mainTagId: string
isRelateColleague: BooleanFlag
sendTime?: string
}
/** 是否关联同事 */ /**
isRelateColleague?: number * 添加专栏的原始form类型
*/
/** 主标签id */ export interface AddOrUpdateColumnForm extends AddOrUpdateColumnBase {
mainTagId?: number tagList: number[]
}
/** 发布状态 */
releaseStatus?: ReleaseStatusTypeEnum
/** 标签列表 */ /**
tagList?: { tagId: number; sort: number }[] * 添加专栏的DTO
*/
export interface AddOrUpdateColumnDto extends AddOrUpdateColumnBase {
tagList: { tagId: number; sort: number }[]
}
/** 标题 */ export interface AddOrUpdateInterviewBase {
title?: string id?: number
type: ArticleTypeEnum.INTERVIEW
title: string
content: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string
imgUrl?: string
// 关联的专访栏目
relateColumn: number
mainTagId: string
sendTime?: string
}
/** 文章类型 */ export interface AddOrUpdateInterviewForm extends AddOrUpdateInterviewBase {
type?: ArticleTypeEnum tagList: number[]
}
/** 视频url */ /**
videoUrl?: string * 添加专访的DTO
*/
export interface AddOrUpdateInterviewDto extends AddOrUpdateInterviewBase {
tagList: { tagId: number; sort: number }[]
} }
/** /**
* 添加专访的DTO
*/
/**
* 文章详情 * 文章详情
*/ */
...@@ -74,3 +116,27 @@ export interface ArticleItemDto { ...@@ -74,3 +116,27 @@ export interface ArticleItemDto {
replyCount: number replyCount: number
hasPraised: BooleanFlag hasPraised: BooleanFlag
} }
export interface ColumnItemDto {
color: string
createTime: number
createUserId: number
id: number
isDelete: BooleanFlag
sort: number
status: BooleanFlag
title: string
type: 'column'
}
export interface InterviewItemDto {
color: string
createTime: number
createUserId: number
id: number
isDelete: BooleanFlag
sort: number
status: BooleanFlag
title: string
type: 'column'
}
...@@ -3,8 +3,8 @@ export * from './task' ...@@ -3,8 +3,8 @@ export * from './task'
export * from './sign' export * from './sign'
export * from './article' export * from './article'
export * from './shop' export * from './shop'
export * from './column' // export * from './column'
export * from './interview' // export * from './interview'
export * from './tag' export * from './tag'
export * from './article' export * from './article'
export * from './user' export * from './user'
...@@ -18,8 +18,8 @@ export * from './article' ...@@ -18,8 +18,8 @@ export * from './article'
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 './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'
......
...@@ -4,10 +4,10 @@ import service from '@/utils/request/index' ...@@ -4,10 +4,10 @@ import service from '@/utils/request/index'
*/ */
export const dailySign = () => { export const dailySign = () => {
return service.request({ return service.request({
url: '/api/culture/action/record/operate', url: '/api/culture/action/record/finishTask',
method: 'POST', method: 'POST',
data: { data: {
subType: 'sign_in_normal_ayabi', taskKey: 'SIGN_IN_NORMAL',
}, },
}) })
} }
import service from '@/utils/request/index' import service from '@/utils/request/index'
import type { UpdateUserInfoDto, SelfPublishDetailDto } from './types' import type {
UpdateUserInfoDto,
SelfPublishDetailDto,
AuditListSearchParams,
AuditListItemDto,
AuditArticleDto,
} from './types'
import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types' import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
/** /**
...@@ -124,3 +130,25 @@ export const getSelfCommentList = (data: PageSearchParams) => { ...@@ -124,3 +130,25 @@ export const getSelfCommentList = (data: PageSearchParams) => {
data, data,
}) })
} }
/**
* 待审核列表
*/
export const getAuditList = (data: AuditListSearchParams) => {
return service.request<BackendServicePageResult<AuditListItemDto>>({
url: '/api/personalCenter/getAuditList',
method: 'POST',
data,
})
}
/**
* 审核推文
*/
export const auditArticle = (data: AuditArticleDto) => {
return service.request({
url: '/api/cultureArticle/auditArticle',
method: 'POST',
data,
})
}
import { AuditStatusEnum } from '@/constants'
import type { PageSearchParams } from '@/utils/request/types'
// 我的发布 详情 // 我的发布 详情
export interface SelfPublishDetailDto { export interface SelfPublishDetailDto {
collectionCount: number collectionCount: number
...@@ -34,3 +37,42 @@ export interface UpdateUserInfoDto { ...@@ -34,3 +37,42 @@ export interface UpdateUserInfoDto {
hiddenName: string hiddenName: string
signature: string signature: string
} }
// 审核列表查询参数
export interface AuditListSearchParams extends PageSearchParams {
isAudit: AuditStatusEnum
}
// 待审核列表item
export interface AuditListItemDto {
collectionCount: number
content: string
createTime: number
createUserId: number
description: string
faceUrl: string
hasPraised: boolean
id: number
imgUrl: string
isRecommend: boolean
isRelateColleague: boolean
playCount: number
praiseCount: number
relateColumn: string
releaseStatus: AuditStatusEnum
replyCount: number
showAvatar: string
showName: string
tagNameList: string[]
title: string
type: string
viewCount: number
}
/**
* 审核推文参数
*/
export interface AuditArticleDto {
articleId: number
auditResult: Exclude<AuditStatusEnum, AuditStatusEnum.UNAUDITED>
}
...@@ -156,9 +156,9 @@ const toggleTag = (tagId: number) => { ...@@ -156,9 +156,9 @@ const toggleTag = (tagId: number) => {
} }
} }
onMounted(() => { // onMounted(() => {
if (tagList.value.length === 0) { // if (tagList.value.length === 0) {
tagsStore.fetchTagList() // tagsStore.fetchTagList()
} // }
}) // })
</script> </script>
...@@ -79,3 +79,13 @@ export enum CommentTypeEnum { ...@@ -79,3 +79,13 @@ export enum CommentTypeEnum {
// 别人评论我的 // 别人评论我的
COMMNET_TO_SELF = 2, COMMNET_TO_SELF = 2,
} }
// 审核状态枚举
export enum AuditStatusEnum {
// 未审核
UNAUDITED = 0,
// 通过审核
AGREED = 1,
// 驳回审核
REJECTED = 2,
}
import { ArticleTypeEnum, CommentTypeEnum, TaskTypeEnum } from './enums' import { ArticleTypeEnum, AuditStatusEnum, CommentTypeEnum, TaskTypeEnum } from './enums'
// 地区列表 // 地区列表
export const regionListOptions = [ export const regionListOptions = [
...@@ -60,6 +60,22 @@ export const articleTypeListOptions = [ ...@@ -60,6 +60,22 @@ export const articleTypeListOptions = [
}, },
] ]
// 审核类型列表
export const auditTypeListOptions: { label: string; value: AuditStatusEnum }[] = [
{
label: '待审核',
value: AuditStatusEnum.UNAUDITED,
},
{
label: '同意',
value: AuditStatusEnum.AGREED,
},
{
label: '拒绝',
value: AuditStatusEnum.REJECTED,
},
]
// 任务类型列表 // 任务类型列表
export const taskTypeListOptions = [ export const taskTypeListOptions = [
{ {
......
...@@ -2,7 +2,7 @@ import type { SetupContext, MaybeRef } from 'vue' ...@@ -2,7 +2,7 @@ import type { SetupContext, MaybeRef } from 'vue'
type Events = { type Events = {
handleBackTop(): void handleBackTop(): void
} }
function ScrollTopComp(_: any, { emit }: SetupContext<Events>) { function ScrollTopComp(_: Record<string, never>, { emit }: SetupContext<Events>) {
return ( return (
<button <button
class="back-top-btn group cursor-pointer flex items-center gap-3 px-4 py-2.5 bg-gradient-to-r from-blue-50 to-indigo-50 hover:from-blue-100 hover:to-indigo-100 border border-blue-200/50 rounded-full transition-all duration-300 hover:shadow-lg hover:-translate-y-1 active:scale-95 shadow-sm" class="back-top-btn group cursor-pointer flex items-center gap-3 px-4 py-2.5 bg-gradient-to-r from-blue-50 to-indigo-50 hover:from-blue-100 hover:to-indigo-100 border border-blue-200/50 rounded-full transition-all duration-300 hover:shadow-lg hover:-translate-y-1 active:scale-95 shadow-sm"
......
import { ArticleTypeEnum, BooleanFlag, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants'
import UploadFile from '@/components/common/UploadFile/index.vue'
import { useResetData } from '@/hooks'
import type { TagItemDto } from '@/api/tag/types'
import { useColumnStore } from '@/stores/column'
import { storeToRefs } from 'pinia'
import SelectTags from '@/components/common/SelectTags/index.vue'
import type { AddOrUpdateColumnForm, AddOrUpdateColumnDto } from '@/api/article/types'
export default defineComponent((_, { expose }) => {
const columnStore = useColumnStore()
const { columnList } = storeToRefs(columnStore)
const [form, resetForm] = useResetData<AddOrUpdateColumnForm>({
title: '',
content: '',
faceUrl: '',
imgUrl: '',
releaseStatus: ReleaseStatusTypeEnum.PUBLISH,
mainTagId: '',
tagList: [],
sendType: SendTypeEnum.IMMEDIATE,
sendTime: '',
isRelateColleague: BooleanFlag.NO,
relateColumn: 0,
type: ArticleTypeEnum.COLUMN,
})
const formRef = ref<InstanceType<typeof ElForm>>()
const rules = {
title: [{ required: true, message: '请输入实践标题', trigger: 'blur' }],
content: [{ required: true, message: '请输入实践内容', trigger: 'blur' }],
releaseStatus: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
mainTagId: [{ required: true, message: '请选择主标签', trigger: 'blur' }],
sendType: [{ required: true, message: '请选择发布类型', trigger: 'blur' }],
sendTime: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
relateColumn: [
{ required: true, message: '请选择专栏栏目', trigger: 'blur', type: 'number', min: 1 },
],
}
const transformForm = (releaseStatus: ReleaseStatusTypeEnum): AddOrUpdateColumnDto => {
return {
...form.value,
releaseStatus,
faceUrl: form.value.imgUrl?.split(',').filter(Boolean)[0] || '',
tagList: [form.value.mainTagId, ...form.value.tagList].map((tag, index) => {
return {
sort: index,
tagId: Number(tag),
}
}),
}
}
// 检验并且获取表单数据
const getValidatedFormData = async (releaseStatus: ReleaseStatusTypeEnum) => {
try {
await formRef.value?.validate()
return transformForm(releaseStatus)
} catch (error) {
console.log(error)
ElMessage.warning('请检查输入内容')
return null
}
}
const filterTagsFn = (allTags: TagItemDto[]) => {
// 引用了form.value.mainTagId
return allTags.filter((tag) => tag.id !== Number(form.value.mainTagId))
}
const resetFields = () => {
formRef.value?.resetFields()
resetForm()
}
expose({
getValidatedFormData,
resetFields,
})
return () => (
<div>
<el-form
ref={formRef}
model={form.value}
label-width="auto"
label-position="right"
rules={rules}
>
<el-form-item label="标题" prop="title">
<el-input
v-model={form.value.title}
placeholder="请输入实践标题"
maxlength={200}
show-word-limit
/>
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input
v-model={form.value.content}
type="textarea"
placeholder="分享你的企业文化实践实例"
rows={6}
maxlength={1000}
show-word-limit
class="content-input"
/>
</el-form-item>
<el-form-item label="图片" prop="imgUrl">
{/* @ts-ignore */}
<UploadFile v-model={form.value.imgUrl} />
</el-form-item>
<el-form-item label="专栏栏目选择" prop="relateColumn">
<el-radio-group v-model={form.value.relateColumn}>
{columnList.value.map((item) => (
<el-radio value={item.id}>{item.title}</el-radio>
))}
</el-radio-group>
</el-form-item>
<el-form-item label="主标签" prop="mainTagId">
{{
// @ts-ignore
default: () => <SelectTags v-model={form.value.mainTagId} />,
label: () => (
// <el-tooltip content="主标签最多选1个" placement="top">
<span class="cursor-pointer">
副标签
{/* <el-icon class="ml-1">
<InfoFilled />
</el-icon> */}
</span>
// </el-tooltip>
),
}}
</el-form-item>
<el-form-item label="副标签">
{{
default: () => (
// @ts-ignore
<SelectTags
v-model={form.value.tagList}
filterTagsFn={filterTagsFn}
maxSelectedTags={3}
/>
),
label: () => (
// <el-tooltip content="副标签最多选3个" placement="top">
<span class="cursor-pointer">
副标签
{/* <el-icon class="ml-1">
<InfoFilled />
</el-icon> */}
</span>
// </el-tooltip>
),
}}
</el-form-item>
<el-form-item label="是否同步同事吧" prop="isRelateColleague">
<el-radio-group v-model={form.value.isRelateColleague}>
<el-radio value={BooleanFlag.YES} class="radio-item scheduled">
</el-radio>
<el-radio value={BooleanFlag.NO} class="radio-item scheduled">
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="发布类型" prop="sendType">
<el-radio-group v-model={form.value.sendType} class="radio-group">
<el-radio value={SendTypeEnum.IMMEDIATE} class="radio-item immediate">
立即发布
</el-radio>
<el-radio value={SendTypeEnum.SCHEDULED} class="radio-item scheduled">
定时发布
</el-radio>
</el-radio-group>
</el-form-item>
{form.value.sendType === SendTypeEnum.SCHEDULED && (
<el-form-item label="发布时间" prop="sendTime">
<el-date-picker
class="ml-2"
v-model={form.value.sendTime}
type="datetime"
placeholder="请选择发布时间"
/>
</el-form-item>
)}
</el-form>
</div>
)
})
import { ArticleTypeEnum, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants'
import UploadFile from '@/components/common/UploadFile/index.vue'
import { useResetData } from '@/hooks'
import { useColumnStore } from '@/stores/column'
import { storeToRefs } from 'pinia'
import type { AddOrUpdateInterviewDto, AddOrUpdateInterviewForm } from '@/api/article/types'
import type { TagItemDto } from '@/api/tag/types'
export default defineComponent((_, { expose }) => {
const columnStore = useColumnStore()
const { columnList } = storeToRefs(columnStore)
const [form, resetForm] = useResetData<AddOrUpdateInterviewForm>({
title: '',
content: '',
faceUrl: '',
imgUrl: '',
releaseStatus: ReleaseStatusTypeEnum.PUBLISH,
mainTagId: '',
tagList: [],
sendType: SendTypeEnum.IMMEDIATE,
sendTime: '',
type: ArticleTypeEnum.INTERVIEW,
relateColumn: 0,
})
const formRef = ref<InstanceType<typeof ElForm>>()
const rules = {
title: [{ required: true, message: '请输入实践标题', trigger: 'blur' }],
content: [{ required: true, message: '请输入实践内容', trigger: 'blur' }],
releaseStatus: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
mainTagId: [{ required: true, message: '请选择主标签', trigger: 'blur' }],
sendType: [{ required: true, message: '请选择发布类型', trigger: 'blur' }],
sendTime: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
relateColumn: [
{ required: true, message: '请选择专访栏目', trigger: 'blur', type: 'number', min: 1 },
],
}
const transformForm = (releaseStatus: ReleaseStatusTypeEnum): AddOrUpdateInterviewDto => {
return {
...form.value,
releaseStatus,
faceUrl: form.value.imgUrl?.split(',').filter(Boolean)[0] || '',
tagList: [form.value.mainTagId, ...form.value.tagList].map((tag, index) => {
return {
sort: index,
tagId: Number(tag),
}
}),
}
}
// 检验并且获取表单数据
const getValidatedFormData = async (releaseStatus: ReleaseStatusTypeEnum) => {
try {
await formRef.value?.validate()
return transformForm(releaseStatus)
} catch (error) {
console.log(error)
ElMessage.warning('请检查输入内容')
return null
}
}
const filterTagsFn = (allTags: TagItemDto[]) => {
// 引用了form.value.mainTagId
return allTags.filter((tag) => tag.id !== Number(form.value.mainTagId))
}
const resetFields = () => {
formRef.value?.resetFields()
resetForm()
}
expose({
getValidatedFormData,
resetFields,
})
return () => (
<div>
<el-form
ref={formRef}
model={form.value}
label-width="auto"
label-position="right"
rules={rules}
>
<el-form-item label="标题" prop="title">
<el-input
v-model={form.value.title}
placeholder="请输入实践标题"
maxlength={200}
show-word-limit
/>
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input
v-model={form.value.content}
type="textarea"
placeholder="分享你的企业文化实践实例"
rows={6}
maxlength={1000}
show-word-limit
class="content-input"
/>
</el-form-item>
<el-form-item label="图片" prop="imgUrl">
{/* @ts-ignore */}
<UploadFile v-model={form.value.imgUrl} />
</el-form-item>
<el-form-item label="专访栏目选择" prop="relateColumn">
<el-radio-group v-model={form.value.relateColumn}>
{columnList.value.map((item) => (
<el-radio value={item.id}>{item.title}</el-radio>
))}
</el-radio-group>
</el-form-item>
<el-form-item label="主标签" prop="mainTagId">
{{
// @ts-ignore
default: () => <SelectTags v-model={form.value.mainTagId} />,
label: () => (
// <el-tooltip content="主标签最多选1个" placement="top">
<span class="cursor-pointer">
副标签
{/* <el-icon class="ml-1">
<InfoFilled />
</el-icon> */}
</span>
// </el-tooltip>
),
}}
</el-form-item>
<el-form-item label="副标签">
{{
default: () => (
// @ts-ignore
<SelectTags
v-model={form.value.tagList}
filterTagsFn={filterTagsFn}
maxSelectedTags={3}
/>
),
label: () => (
// <el-tooltip content="副标签最多选3个" placement="top">
<span class="cursor-pointer">
副标签
{/* <el-icon class="ml-1">
<InfoFilled />
</el-icon> */}
</span>
// </el-tooltip>
),
}}
</el-form-item>
<el-form-item label="发布类型" prop="sendType">
<el-radio-group v-model={form.value.sendType} class="radio-group">
<el-radio value={SendTypeEnum.IMMEDIATE} class="radio-item immediate">
立即发布
</el-radio>
<el-radio value={SendTypeEnum.SCHEDULED} class="radio-item scheduled">
定时发布
</el-radio>
</el-radio-group>
</el-form-item>
{form.value.sendType === SendTypeEnum.SCHEDULED && (
<el-form-item label="发布时间" prop="sendTime">
<el-date-picker
class="ml-2"
v-model={form.value.sendTime}
type="datetime"
placeholder="请选择发布时间"
/>
</el-form-item>
)}
</el-form>
</div>
)
})
import { ArticleTypeEnum, ReleaseStatusTypeEnum } from '@/constants' import { ArticleTypeEnum, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants'
import UploadFile from '@/components/common/UploadFile/index.vue' import UploadFile from '@/components/common/UploadFile/index.vue'
import { useResetData } from '@/hooks' import { useResetData } from '@/hooks'
import type { AddOrUpdatePostDto } from '@/api'
export default defineComponent( export default defineComponent(
(_, { expose }) => { (_, { expose }) => {
const [form, resetForm] = useResetData({ const [form, resetForm] = useResetData<AddOrUpdatePostDto>({
title: '', title: '',
content: '', content: '',
faceUrl: '', faceUrl: '',
imgUrl: '',
releaseStatus: ReleaseStatusTypeEnum.PUBLISH, releaseStatus: ReleaseStatusTypeEnum.PUBLISH,
type: ArticleTypeEnum.POST, type: ArticleTypeEnum.POST,
sendType: SendTypeEnum.IMMEDIATE,
sendTime: '',
}) })
const formRef = ref<InstanceType<typeof ElForm>>() const formRef = ref<InstanceType<typeof ElForm>>()
const rules = { const rules = {
title: [{ required: true, message: '请输入帖子标题', trigger: 'blur' }], title: [{ required: true, message: '请输入帖子标题', trigger: 'blur' }],
content: [{ required: true, message: '请输入帖子内容', trigger: 'blur' }], content: [{ required: true, message: '请输入帖子内容', trigger: 'blur' }],
faceUrl: [{ required: true, message: '请上传贴图', trigger: 'change' }], sendType: [{ required: true, message: '请选择发布类型', trigger: 'blur' }],
releaseStatus: [{ required: true, message: '请选择发布时间', trigger: 'blur' }], sendTime: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
} }
const validate = async () => { const transformForm = (releaseStatus: ReleaseStatusTypeEnum) => {
return {
...form.value,
releaseStatus,
imgUrl: form.value.imgUrl?.split(',').filter(Boolean)[0] || '',
}
}
const getValidatedFormData = async (releaseStatus: ReleaseStatusTypeEnum) => {
try { try {
await formRef.value?.validate() await formRef.value?.validate()
return form.value return transformForm(releaseStatus)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
ElMessage.warning('请检查输入内容') ElMessage.warning('请检查输入内容')
...@@ -36,7 +48,7 @@ export default defineComponent( ...@@ -36,7 +48,7 @@ export default defineComponent(
} }
expose({ expose({
validate, getValidatedFormData,
resetFields, resetFields,
}) })
return () => ( return () => (
...@@ -71,16 +83,27 @@ export default defineComponent( ...@@ -71,16 +83,27 @@ export default defineComponent(
{/* @ts-ignore */} {/* @ts-ignore */}
<UploadFile v-model={form.value.faceUrl} /> <UploadFile v-model={form.value.faceUrl} />
</el-form-item> </el-form-item>
<el-form-item label="发布时间" prop="releaseStatus"> <el-form-item label="发布类型" prop="sendType">
<el-radio-group v-model={form.value.releaseStatus} class="radio-group"> <el-radio-group v-model={form.value.sendType} class="radio-group">
<el-radio value={ReleaseStatusTypeEnum.PUBLISH} class="radio-item immediate"> <el-radio value={SendTypeEnum.IMMEDIATE} class="radio-item immediate">
立即发布 立即发布
</el-radio> </el-radio>
<el-radio value={ReleaseStatusTypeEnum.DRAFT} class="radio-item scheduled"> <el-radio value={SendTypeEnum.SCHEDULED} class="radio-item scheduled">
定时发布 定时发布
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
{form.value.sendType === SendTypeEnum.SCHEDULED && (
<el-form-item label="发布时间" prop="sendTime">
<el-date-picker
class="w-full"
v-model={form.value.sendTime}
type="datetime"
placeholder="请选择发布时间"
value-format="X"
/>
</el-form-item>
)}
</el-form> </el-form>
</div> </div>
) )
......
...@@ -58,6 +58,7 @@ const typeMap: Record< ...@@ -58,6 +58,7 @@ const typeMap: Record<
[ArticleTypeEnum.POST]: { [ArticleTypeEnum.POST]: {
title: '帖子', title: '帖子',
component: defineAsyncComponent(() => import('./postForm.tsx')), component: defineAsyncComponent(() => import('./postForm.tsx')),
api: addOrUpdateArticle,
}, },
[ArticleTypeEnum.PRACTICE]: { [ArticleTypeEnum.PRACTICE]: {
title: '实践', title: '实践',
...@@ -66,11 +67,13 @@ const typeMap: Record< ...@@ -66,11 +67,13 @@ const typeMap: Record<
}, },
[ArticleTypeEnum.COLUMN]: { [ArticleTypeEnum.COLUMN]: {
title: '专栏', title: '专栏',
component: PostForm, component: defineAsyncComponent(() => import('./colnumForm.tsx')),
api: addOrUpdateArticle,
}, },
[ArticleTypeEnum.INTERVIEW]: { [ArticleTypeEnum.INTERVIEW]: {
title: '专访', title: '专访',
component: PostForm, component: defineAsyncComponent(() => import('./interviewForm.tsx')),
api: addOrUpdateArticle,
}, },
} }
......
import { defineStore } from 'pinia'
import { getColumnList } from '@/api'
import type { ColumnItemDto } from '@/api/article/types'
/**
* 关于专栏的不分页数据
*/
export const useColumnStore = defineStore('column', () => {
const columnList = ref<ColumnItemDto[]>([])
let isLoading = false
const fetchColumnList = async () => {
if (isLoading) return
isLoading = true
try {
const { data } = await getColumnList()
columnList.value = data
console.log(columnList.value, 'columnList')
} catch (error) {
console.error(error)
} finally {
isLoading = false
}
}
fetchColumnList()
return { columnList, fetchColumnList }
})
export * from './user' export * from './user'
export * from './tags' export * from './tags'
export * from './column'
import { defineStore } from 'pinia'
import { getInterviewList } from '@/api'
import type { InterviewItemDto } from '@/api/article/types'
/**
* 关于专访的相关数据 --不分页
*/
export const useInterviewStore = defineStore('interview', () => {
const interviewList = ref<InterviewItemDto[]>([])
let isLoading = false
const fetchInterviewList = async () => {
if (isLoading) return
if (interviewList.value.length > 0) return
isLoading = true
try {
const { data } = await getInterviewList()
interviewList.value = data
console.log(interviewList.value, 'interviewList')
} catch (error) {
console.error(error)
} finally {
isLoading = false
}
}
fetchInterviewList()
return { interviewList, fetchInterviewList }
})
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { getTagList } from '@/api' import { getTagList } from '@/api'
import type { TagItemDto } from '@/api/tag/types' import type { TagItemDto } from '@/api/tag/types'
/** /**
* 关于标签的store * 关于标签的store
*/ */
export const useTagsStore = defineStore('tags', () => { export const useTagsStore = defineStore('tags', () => {
const tagList = ref<TagItemDto[]>([]) const tagList = ref<TagItemDto[]>([])
let isLoading = false let isLoading = false
const fetchTagList = async () => { const fetchTagList = async () => {
...@@ -23,6 +21,8 @@ export const useTagsStore = defineStore('tags', () => { ...@@ -23,6 +21,8 @@ export const useTagsStore = defineStore('tags', () => {
isLoading = false isLoading = false
} }
} }
// 手动调用一次
fetchTagList()
return { tagList, fetchTagList } return { tagList, fetchTagList }
}) })
...@@ -8,28 +8,21 @@ ...@@ -8,28 +8,21 @@
class="group bg-white rounded-lg p-4 sm:p-6 cursor-pointer transition-all duration-300 hover:shadow-lg hover:shadow-gray-100 hover:-translate-y-1 border border-gray-100 hover:border-gray-200 mb-3 sm:mb-4" class="group bg-white rounded-lg p-4 sm:p-6 cursor-pointer transition-all duration-300 hover:shadow-lg hover:shadow-gray-100 hover:-translate-y-1 border border-gray-100 hover:border-gray-200 mb-3 sm:mb-4"
@click="router.push(`/postDetail/${item.id}`)" @click="router.push(`/postDetail/${item.id}`)"
> >
<div class="flex gap-3 sm:gap-4 lg:gap-6"> <div class="flex gap-3 justify-between">
<!-- 内容区域 --> <!-- 内容区域 -->
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0 flex flex-col justify-between">
<!-- 标题 --> <!-- 标题 -->
<h2 <h2
class="text-base sm:text-lg lg:text-xl font-semibold text-gray-900 mb-2 sm:mb-3 line-clamp-2 group-hover:text-blue-600 transition-colors duration-200 leading-tight" class="text-xl font-semibold text-gray-900 line-clamp-1 group-hover:text-blue-600 transition-colors duration-200 leading-tight"
> >
{{ item.title }} {{ item.title }}
</h2> </h2>
<!-- 内容摘要 --> <!-- 内容摘要 -->
<div class="mb-3 sm:mb-4 space-y-1"> <div class="my-2 space-y-1">
<p <p class="text-gray-600 text-sm sm:text-base leading-relaxed line-clamp-2">
class="text-gray-600 text-sm sm:text-base leading-relaxed line-clamp-1 sm:line-clamp-2"
>
{{ item.content }} {{ item.content }}
</p> </p>
<!-- <p
class="text-gray-600 text-sm sm:text-base leading-relaxed line-clamp-1 sm:line-clamp-2"
>
终于知道名门正派为什么这么庆祝邪修了,邪修大法就是好用啊!(ᵔ◡ᵔ)
</p> -->
</div> </div>
<!-- 统计信息 --> <!-- 统计信息 -->
...@@ -62,11 +55,9 @@ ...@@ -62,11 +55,9 @@
</div> </div>
<!-- 图片区域 --> <!-- 图片区域 -->
<div <div v-if="item.faceUrl" class="relative flex-shrink-0 w-36 h-24">
class="relative flex-shrink-0 w-20 h-16 sm:w-32 sm:h-24 lg:w-40 lg:h-28 xl:w-44 xl:h-32"
>
<img <img
src="@/assets/img/culture/ask.png" :src="item.faceUrl"
alt="文章配图" alt="文章配图"
class="w-full h-full object-cover rounded-lg sm:rounded-xl group-hover:scale-105 transition-transform duration-300" class="w-full h-full object-cover rounded-lg sm:rounded-xl group-hover:scale-105 transition-transform duration-300"
loading="lazy" loading="lazy"
...@@ -82,7 +73,7 @@ ...@@ -82,7 +73,7 @@
<!-- 底部分页 --> <!-- 底部分页 -->
<div class="bottom-pagination 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 py-6">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<!-- 左侧:回到顶部按钮 --> <!-- 左侧:回到顶部按钮 -->
<div class="left"> <div class="left">
...@@ -134,7 +125,7 @@ const router = useRouter() ...@@ -134,7 +125,7 @@ const router = useRouter()
const { list, total, searchParams, loading, goToPage, changePageSize, reset } = usePageSearch( const { list, total, searchParams, loading, goToPage, changePageSize, reset } = usePageSearch(
getArticleList, getArticleList,
{ {
defaultParams: { type: ArticleTypeEnum.POST }, // defaultParams: { type: ArticleTypeEnum.POST },
defaultCurrent: 1, defaultCurrent: 1,
defaultSize: 5, defaultSize: 5,
}, },
......
<template> <template>
<div class="page"> <div>
<div class="header h-40px items-center justify-between"> <div class="header h-40px items-center justify-between">
<div class="left flex gap-3 flex items-center"> <div class="left flex gap-3 flex items-center">
<Tabs <Tabs
......
...@@ -69,9 +69,11 @@ ...@@ -69,9 +69,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ArrowRight, View, ChatDotRound, Star } from '@element-plus/icons-vue' import { ArrowRight, View, ChatDotRound, Star } from '@element-plus/icons-vue'
import { getColumnList } from '@/api' import { useColumnStore } from '@/stores/column'
import { storeToRefs } from 'pinia'
import type { ColumnItemDto } from '@/api' const columnStore = useColumnStore()
const { columnList } = storeToRefs(columnStore)
const section2Items = ref([ const section2Items = ref([
{ {
...@@ -109,17 +111,6 @@ const section2Items = ref([ ...@@ -109,17 +111,6 @@ const section2Items = ref([
date: '2025-04-13 14:28', date: '2025-04-13 14:28',
}, },
]) ])
const columnList = ref<ColumnItemDto[]>([])
const getColumnListData = async () => {
const { data } = await getColumnList()
console.log(data)
columnList.value = data
}
onMounted(() => {
getColumnListData()
})
</script> </script>
<style scoped></style> <style scoped></style>
<template> <template>
<div class="w-full max-w-6xl mx-auto"> <div class="w-full max-w-6xl mx-auto">
<div <div
v-for="item in columnList" v-for="item in interviewList"
:key="item.id" :key="item.id"
class="bg-white rounded-lg shadow-sm mb-6 overflow-hidden" class="bg-white rounded-lg shadow-sm mb-6 overflow-hidden"
:style="{ '--dynamic-color': item.color }" :style="{ '--dynamic-color': item.color }"
...@@ -69,9 +69,11 @@ ...@@ -69,9 +69,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ArrowRight, View, ChatDotRound, Star } from '@element-plus/icons-vue' import { ArrowRight, View, ChatDotRound, Star } from '@element-plus/icons-vue'
import { getInterviewList } from '@/api' import { useInterviewStore } from '@/stores/interview'
import { storeToRefs } from 'pinia'
import type { ColumnItemDto } from '@/api' const interviewStore = useInterviewStore()
const { interviewList } = storeToRefs(interviewStore)
const section2Items = ref([ const section2Items = ref([
{ {
...@@ -109,17 +111,6 @@ const section2Items = ref([ ...@@ -109,17 +111,6 @@ const section2Items = ref([
date: '2025-04-13 14:28', date: '2025-04-13 14:28',
}, },
]) ])
const columnList = ref<ColumnItemDto[]>([])
const getColumnListData = async () => {
const { data } = await getInterviewList()
console.log(data)
columnList.value = data
}
onMounted(() => {
getColumnListData()
})
</script> </script>
<style scoped></style> <style scoped></style>
<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.isAudit" @tab-change="toggleTab">
<el-tab-pane
v-for="tab in auditTypeListOptions"
: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="flex gap-3">
<el-image :src="item.showAvatar" class="w-12 h-12 rounded-full flex-shrink-0" />
<div class="flex-1 min-w-0 flex flex-col justify-center">
<!-- 第一行:用户名 + 时间 + 标签 -->
<div class="flex items-center gap-2 mb-1.5">
<span class="text-gray-900 text-sm flex-shrink-0">{{ item.showName }}</span>
<span class="text-gray-400 text-sm flex-shrink-0 whitespace-nowrap">
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</span>
<div
class="flex flex-wrap gap-1.5 flex-1 min-w-0"
v-if="item.tagNameList?.length"
>
<el-tag v-for="tag in item.tagNameList" :key="tag" size="small">
{{ tag }}
</el-tag>
</div>
</div>
<!-- 第二行:标题 -->
<div class="text-gray-700 font-medium">
{{ item.title }}
</div>
</div>
</div>
</div>
<div
v-if="searchParams.isAudit === AuditStatusEnum.UNAUDITED"
class="flex items-center text-gray-400 text-sm ml-4"
>
<el-button
type="primary"
link
@click="handleAudit({ articleId: item.id, auditResult: AuditStatusEnum.AGREED })"
>
同意
</el-button>
<el-button
type="danger"
link
@click="
handleAudit({
articleId: item.id,
auditResult: AuditStatusEnum.REJECTED,
})
"
>
拒绝
</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 { getAuditList, auditArticle } from '@/api'
import { usePageSearch } from '@/hooks'
import { auditTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { AuditStatusEnum } from '@/constants'
import type { AuditArticleDto } from '@/api'
const toggleTab = (key: AuditStatusEnum) => {
searchParams.value.isAudit = key
refresh()
}
// State
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
getAuditList,
{
defaultParams: {
isAudit: AuditStatusEnum.UNAUDITED,
},
},
)
const handleAudit = async (data: AuditArticleDto) => {
await auditArticle(data)
ElMessage.success('审核成功')
refresh()
}
const getEmptyText = () => {
const emptyTexts: Record<string, string> = {
posts: '还没有发布任何帖子',
videos: '还没有上传任何视频',
questions: '还没有提出任何问题',
articles: '还没有发表任何专栏文章',
practice: '还没有分享任何实践经验',
interviews: '还没有参与任何专访',
}
return emptyTexts[searchParams.value.isAudit] || '暂无数据'
}
</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.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>
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
</div> </div>
</div> </div>
<!-- 左侧菜单 --> <!-- 左侧菜单 ——个人菜单 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden"> <div class="bg-white rounded-lg shadow-sm mb-4">
<div <div
v-for="item in menuItems" v-for="item in menuUserItems"
:key="item.key" :key="item.key"
@click="activeMenu = item.key" @click="activeMenu = item.key"
:class="[ :class="[
...@@ -52,8 +52,27 @@ ...@@ -52,8 +52,27 @@
<span class="text-sm">{{ item.label }}</span> <span class="text-sm">{{ item.label }}</span>
</div> </div>
</div> </div>
<!-- 左侧菜单 —— 官方账号菜单 审核操作等 -->
<div class="bg-white rounded-lg shadow-sm">
<div
v-for="item in menuOfficialItems"
:key="item.key"
@click="activeMenu = item.key"
:class="[
'flex items-center gap-3 px-4 py-3 cursor-pointer transition-colors border-b border-gray-100 last:border-b-0',
activeMenu === item.key
? 'bg-blue-50 text-blue-600 border-r-3 border-r-blue-600'
: 'text-gray-700 hover:bg-gray-50',
]"
>
<el-icon :size="16">
<component :is="item.icon" />
</el-icon>
<span class="text-sm">{{ item.label }}</span>
</div>
</div>
<!-- 左侧菜单 -->
</div> </div>
<!-- 右侧内容区域 --> <!-- 右侧内容区域 -->
<div class="flex-1"> <div class="flex-1">
<div class="bg-white rounded-lg shadow-sm min-h-500px"> <div class="bg-white rounded-lg shadow-sm min-h-500px">
...@@ -142,6 +161,7 @@ import SelfDraft from './components/selfDraft.vue' ...@@ -142,6 +161,7 @@ import SelfDraft from './components/selfDraft.vue'
import SelfCase from './components/selfCase.vue' import SelfCase from './components/selfCase.vue'
import SelfTask from './components/selfTask.vue' import SelfTask from './components/selfTask.vue'
import SelfComment from './components/selfComment.vue' import SelfComment from './components/selfComment.vue'
import SelfAudit from './components/selfAudit.vue'
import { hasOfficialAccount } from '@/api' import { hasOfficialAccount } from '@/api'
const editUserInfoRef = useTemplateRef<InstanceType<typeof EditUserInfo>>('editUserInfoRef') const editUserInfoRef = useTemplateRef<InstanceType<typeof EditUserInfo>>('editUserInfoRef')
...@@ -157,8 +177,8 @@ const activeTab = ref('published') ...@@ -157,8 +177,8 @@ const activeTab = ref('published')
// 当前页码 // 当前页码
const currentPage = ref(1) const currentPage = ref(1)
// 左侧菜单项 // 左侧普通用户菜单
const menuItems = [ const menuUserItems = [
{ key: 'posts', label: '我的帖子', icon: User, component: SelfPublish, tab: '发布' }, { key: 'posts', label: '我的帖子', icon: User, component: SelfPublish, tab: '发布' },
{ key: 'activity', label: '我的草稿', icon: Document, component: SelfDraft, tab: '草稿' }, { key: 'activity', label: '我的草稿', icon: Document, component: SelfDraft, tab: '草稿' },
{ key: 'favorites', label: '我的收藏', icon: Star, component: SelfCollect, tab: '收藏' }, { key: 'favorites', label: '我的收藏', icon: Star, component: SelfCollect, tab: '收藏' },
...@@ -172,22 +192,18 @@ const menuItems = [ ...@@ -172,22 +192,18 @@ const menuItems = [
component: SelfComment, component: SelfComment,
tab: '评论回复', tab: '评论回复',
}, },
{ key: 'votes', label: '我的投票', icon: Trophy },
{ key: 'articles', label: '我的文章', icon: Document },
{ key: 'comments', label: '评论回复', icon: ChatDotRound },
{ key: 'follows', label: '获赞列表', icon: Trophy },
{ key: 'social', label: '关注和粉', icon: Link },
{ key: 'feedback', label: '反馈列表', icon: View },
{ key: 'screen', label: '屏蔽管理', icon: Setting },
] ]
const currentComponent = computed(() => {
return menuItems.find((item) => item.key === activeMenu.value)?.component // 左侧官方账号菜单
}) const menuOfficialItems = [
// 标签页 { key: 'audit', label: '审核列表', icon: User, component: SelfAudit, tab: '审核列表' },
const tabs = ref([ ]
{ key: 'published', label: '发布' },
{ key: 'draft', label: '草稿' }, const currentComponent = computed(
]) () =>
[...menuUserItems, ...menuOfficialItems].find((item) => item.key === activeMenu.value)
?.component,
)
const handleEdit = () => { const handleEdit = () => {
console.log('修改资料') console.log('修改资料')
......
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