From 05d1310a6ec27656712c0c5e5e57b3365d3faf56 Mon Sep 17 00:00:00 2001 From: tj <1378534974@qq.com> Date: 星期四, 29 五月 2025 16:54:34 +0800 Subject: [PATCH] api --- static/common/official.png | 0 pages/home/home.vue | 7 components/card/flow-card.vue | 35 ++ sub-pages/community/index.vue | 39 +- enums/dict.ts | 11 environments/index.js | 2 types/index.ts | 131 +++++++++-- sub-pages/community/search-page.vue | 1 sub-pages/film-list/film-detail.vue | 82 ++++++- sub-pages/film-list/film-list.vue | 162 ++++++++------ sub-pages/utils/api.ts | 41 +++ components/card/flow-card copy.vue | 86 +++++++ store/user.ts | 6 13 files changed, 449 insertions(+), 154 deletions(-) diff --git a/components/card/flow-card copy.vue b/components/card/flow-card copy.vue new file mode 100644 index 0000000..552c74d --- /dev/null +++ b/components/card/flow-card copy.vue @@ -0,0 +1,86 @@ +<template> + <view class="card" @click="handleClick(item)"> + <image :src="item.imgurl" mode="widthFix" class="card-image" /> + <view class="card-title"> + <up-text :lines="2" size="14px" :text="item.title" bold></up-text> + </view> + <view class="card-footer"> + <view class="user-info"> + <up-avatar :src="item.avatar" size="40rpx" shape="circle" /> + <view class="user-text"> + <text class="nickname">{{ item.username }}</text> + </view> + </view> + <view class="opera-info"> + <up-icon name="heart" size="30rpx" color="#999" /> + <text>{{ item.likes }}</text> + </view> + </view> + </view> +</template> + +<script setup lang="ts"> +defineProps<{ + item: any +}>() + +const emit = defineEmits(['click']) +const handleClick = (item) => { + emit('click', item) +} +</script> + +<style scoped lang="scss"> +.card { + border-radius: 10rpx; + background-color: #ffffff; + font-size: 14px; + line-height: 20px; + color: rgb(51, 51, 51); + margin: 10rpx; + + .card-image { + width: 100%; + border-radius: inherit; + } + + .card-title { + padding: 10rpx; + font-weight: 500; + } + + .card-footer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10rpx; + } + + .user-info { + display: flex; + align-items: center; + + .user-text { + font-size: 18rpx; + line-height: 14px; + margin-left: 10rpx; + + .nickname { + font-weight: bold; + display: block; + color: #646464; + } + } + } + + .opera-info { + display: flex; + align-items: center; + + text { + margin-left: 10rpx; + font-size: 12px; + } + } +} +</style> \ No newline at end of file diff --git a/components/card/flow-card.vue b/components/card/flow-card.vue index 552c74d..3dcaf68 100644 --- a/components/card/flow-card.vue +++ b/components/card/flow-card.vue @@ -1,19 +1,23 @@ <template> <view class="card" @click="handleClick(item)"> - <image :src="item.imgurl" mode="widthFix" class="card-image" /> + <!-- <image :src="item.coverUrl" mode="widthFix" class="card-image" /> --> + <view class="image-wrapper"> + <image :src="item.coverUrl" mode="widthFix" class="card-image" /> + <image v-if="item.userType==='official'" src="/static/common/official.png" class="badge-icon" /> + </view> <view class="card-title"> - <up-text :lines="2" size="14px" :text="item.title" bold></up-text> + <up-text :lines="2" size="14px" :text="item.nameCn" bold></up-text> </view> <view class="card-footer"> <view class="user-info"> <up-avatar :src="item.avatar" size="40rpx" shape="circle" /> <view class="user-text"> - <text class="nickname">{{ item.username }}</text> + <text class="nickname">{{ item.nickname }}</text> </view> </view> <view class="opera-info"> <up-icon name="heart" size="30rpx" color="#999" /> - <text>{{ item.likes }}</text> + <text>{{ item.likeCount }}</text> </view> </view> </view> @@ -25,7 +29,7 @@ }>() const emit = defineEmits(['click']) -const handleClick = (item) => { +const handleClick = (item: any) => { emit('click', item) } </script> @@ -39,11 +43,28 @@ color: rgb(51, 51, 51); margin: 10rpx; - .card-image { + .image-wrapper { width: 100%; - border-radius: inherit; + position: relative; + display: inline-block; + + .card-image { + width: 100%; + border-radius: inherit; + } + + .badge-icon { + position: absolute; + bottom: 8rpx; + right: 0rpx; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + } + } + .card-title { padding: 10rpx; font-weight: 500; diff --git a/enums/dict.ts b/enums/dict.ts index 0fae0cc..859a70d 100644 --- a/enums/dict.ts +++ b/enums/dict.ts @@ -1,5 +1,14 @@ export enum FilmWorksCategory { CONTENT_SELECTED = '1', // 内容精选 COMMUNITY = '2', // 社区推荐 - // 可以根据业务继续扩展 + } + + + /** + * 类型 + */ + export enum FilmTabCategory { + USER_TYPE = '1', // 用户类型 + FILM_TYPE = '2', // 电影类型 + } \ No newline at end of file diff --git a/environments/index.js b/environments/index.js index e15cae7..6d7cb72 100644 --- a/environments/index.js +++ b/environments/index.js @@ -1,6 +1,6 @@ export default { - // httpBaseUri: 'http://192.168.1.211:8080/flower', httpBaseUri: 'http://192.168.1.198:8888/flower', + // httpBaseUri: 'http://14.103.144.28:8091/flower', clientId: '', secret: '', tenantId: '', diff --git a/pages/home/home.vue b/pages/home/home.vue index bc09653..a4f2ad9 100644 --- a/pages/home/home.vue +++ b/pages/home/home.vue @@ -62,7 +62,6 @@ import Community from './community.vue' import { SwiperChangeEvent } from '@dcloudio/uni-app' import { useGlobal } from '@/composables/useGlobal' -import { number } from 'uview-plus/libs/function/test' const { $http, $message, $store } = useGlobal() import { FilmWorks } from '@/types/index' import { formatRelativeTime } from '@/utils/time' @@ -164,8 +163,6 @@ const communityPage = ref(1) const communitySize = 10 const communityStatus = ref('loading') - - const getCommunitys = async () => { if (communityStatus.value === 'nomore') return @@ -190,9 +187,6 @@ communityStatus.value = 'noMore' } } -const getCommunitys_bak = async () => { - communitys.value = await getFilmWorks(FilmWorksCategory.COMMUNITY, 10, 1); -} // 内容精选 const getFilmWorks = async (type: String, pageSize: Number, currentPage: Number) => { const { @@ -210,7 +204,6 @@ $message.showToast('系统异常,无法获取数据') return null; } - } // 下一页 diff --git a/static/common/official.png b/static/common/official.png new file mode 100644 index 0000000..2e947f4 --- /dev/null +++ b/static/common/official.png Binary files differ diff --git a/store/user.ts b/store/user.ts index 57b723e..e9535f7 100644 --- a/store/user.ts +++ b/store/user.ts @@ -1,9 +1,9 @@ // stores/user.ts import { defineStore } from 'pinia' import { ref } from 'vue' -import http from '@/plugins/http.js' // 请替换成你实际的 http 封装路径 -import storage from '@/plugins/storage' // 同样替换为你的封装路径 -import message from '@/plugins/message' // 你使用的消息组件封装 +import http from '@/plugins/http.js' +import storage from '@/plugins/storage' +import message from '@/plugins/message' import { WechatLoginData } from '@/types/index' diff --git a/sub-pages/community/index.vue b/sub-pages/community/index.vue index 388b7d7..51f7dbb 100644 --- a/sub-pages/community/index.vue +++ b/sub-pages/community/index.vue @@ -4,7 +4,8 @@ <view class="header"> <up-icon name="list" size="40rpx" color="#333333" @click="onSettingClick" /> <view> - <up-tabs :list="list1"> + <!-- <up-tabs :list="list1"> --> + <up-tabs :list="userTabList"> <!-- <template #left> <up-icon name="list" size="40rpx" color="#333333" /> </template> --> @@ -43,8 +44,12 @@ <script setup lang="ts"> import SettingPopup from '@/components/setting/setting-popup.vue'; import { reactive, ref, onMounted } from 'vue'; -import { onLoad } from '@dcloudio/uni-app' - +import { FilmCategoryTree, FilmWorks } from '@/types/index' +import { onLoad, onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app' +import { FilmTabCategory, FilmWorksCategory } from '@/enums/dict' +import { useGlobal } from '@/composables/useGlobal' +const { $http, $message, $store } = useGlobal() +import { getTabList } from '@/sub-pages/utils/api' // 控制设置弹窗显示 const settingShow = ref(false); // 方法定义 @@ -53,21 +58,13 @@ } // 创建响应式数据 -const list1 = reactive([ - { name: '关注' }, - { name: '发现' }, - { name: '苏州' }, -]); - -const tabList = ref([ - { id: 'recommend', name: '推荐' }, - { id: 'straight', name: '直播' }, - { id: 'short', name: '短剧' }, - { id: 'food', name: '美食' }, - { id: 'travel', name: '穿搭' }, - { id: 'beauty', name: '美甲' }, - { id: 'more', name: '更多' }, -]) +// const list1 = reactive([ +// { name: '关注' }, +// { name: '发现' }, +// { name: '苏州' }, +// ]); +const userTabList = ref<FilmCategoryTree[]>([]) +const tabList = ref<FilmCategoryTree[]>([]) const flowList = ref([ { @@ -124,6 +121,12 @@ theme.value = storedTheme }) + +onShow(() => { + getTabList(FilmTabCategory.USER_TYPE,userTabList,false) + getTabList(FilmTabCategory.FILM_TYPE, tabList) +}); + </script> <style lang="scss" scoped> .header { diff --git a/sub-pages/community/search-page.vue b/sub-pages/community/search-page.vue index c3617e6..b87fa31 100644 --- a/sub-pages/community/search-page.vue +++ b/sub-pages/community/search-page.vue @@ -72,6 +72,7 @@ <script setup lang="ts"> import { ref } from 'vue' +import { onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app' const searchValue = ref('') diff --git a/sub-pages/film-list/film-detail.vue b/sub-pages/film-list/film-detail.vue index ab78d44..68e566f 100644 --- a/sub-pages/film-list/film-detail.vue +++ b/sub-pages/film-list/film-detail.vue @@ -20,25 +20,25 @@ <view class="swiper-container"> <swiper :current="currentNum" @change="onSwiperChange" circular :autoplay="false" class="custom-swiper"> - <swiper-item v-for="(item, index) in list6" :key="index" class="swiper-item"> + <swiper-item v-for="(item, index) in filmPictureList" :key="index" class="swiper-item"> <image :src="item" mode="aspectFill" class="swiper-image" @tap="previewImage(index)" /> </swiper-item> </swiper> <view class="indicator-num"> - <text class="indicator-num__text">{{ currentNum + 1 }}/{{ list6.length }}</text> + <text class="indicator-num__text">{{ currentNum + 1 }}/{{ filmPictureList.length }}</text> </view> </view> <view class="article-content"> <view class="title content-item"> - <text>我是标题标题我是标题标题我是标题标题我是标题标题</text> + <text>{{ filmInfo.coverTitle }}</text> </view> <view class="content-item"> - <rich-text :nodes="desc" /> + <rich-text :nodes="filmInfo.filmContent" /> </view> <view class="annotation content-item"> - <text>4分钟前 美国</text> + <text>{{ formatRelativeTime(filmInfo.createTime) }} 美国</text> </view> </view> @@ -46,7 +46,7 @@ <view class="comment"> <view class="writer-view" @click="showCommentLayer"> - <up-icon name="chat-fill" size="60rpx" /> + <up-icon name="chat-fill" size="60rpx" /> <view class="comment-operation"> <up-text size="12px" text="说点什么......" margin="0 0 0 20rpx" color="#B9B9B9" /> </view> @@ -77,8 +77,15 @@ </template> <script setup lang="ts"> + import { ref, reactive } from 'vue' +import { onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app' import { onLoad } from '@dcloudio/uni-app' +import { useGlobal } from '@/composables/useGlobal' +const { $http, $message, $store } = useGlobal() + +import { FilmInfo,FilmPicture } from '@/types/index' +import { formatRelativeTime } from '@/utils/time' // Swiper 当前页 const currentNum = ref(0) @@ -90,12 +97,6 @@ avatar: 'https://img.yzcdn.cn/vant/cat.jpeg' }) -const list6 = ref<string[]>([ - 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg', - 'https://img.yzcdn.cn/vant/cat.jpeg', - 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg' -]) - const urls2 = ref<string[]>([ 'https://img.yzcdn.cn/vant/cat.jpeg' ]) @@ -106,9 +107,20 @@ #新疆是个好地方 #新疆旅行攻略... `) -onLoad(() => { +onLoad((options:any) => { const theme = uni.getStorageSync('theme') || 'light' console.log('theme:', theme) + + // 获取传递来的参数 + console.log('传入参数:', options) + + // 示例:你传过来的参数可能是这样 ?id=123&type=test + const id = options.id + const type = options.type + console.log('id:', id, 'type:', type) + if(id){ + getFilmInfoById(id) + } }) const onSwiperChange = (e: any) => { @@ -117,14 +129,54 @@ const previewImage = (index: number) => { uni.previewImage({ - current: list6.value[index], - urls: list6.value + current: filmPictureList.value[index], + urls: filmPictureList.value }) } const showCommentLayer = () => { commentShow.value = true } + +onShow(() => { + +}); + +const filmInfo = ref<FilmInfo>() + +const filmPictureList = ref<string[]>([]) +const getFilmInfoById = async (id:String)=>{ + const { + code, data + } = await $http.request('get', '/api/filmWorks/list/view', { + params: { + id: id + } + }) + if (code == 0) { + filmInfo.value=data + console.log("详情",filmInfo.value) + if(data && data.filmPictures){ + // 只获取里面的url + // filmPictureList.value=JSON.parse(data.filmPictures) as Array<FilmPicture> + const tmpPicture = JSON.parse(data.filmPictures) as FilmPicture[] + filmPictureList.value = tmpPicture.map(item => item.url) + // 如果 filmPictureList.value是空的情况下,则把封面放入到图片列表中 + debugger; + if (filmPictureList.value.length === 0) { + filmPictureList.value.push(data.coverUrl) + } + }else{ + if (filmPictureList.value.length === 0) { + filmPictureList.value.push(data.coverUrl) + } + } + console.log("图片列表",filmPictureList.value) + } else { + $message.showToast('系统异常,无法获取数据') + return null; + } +} </script> diff --git a/sub-pages/film-list/film-list.vue b/sub-pages/film-list/film-list.vue index 957e691..f069e46 100644 --- a/sub-pages/film-list/film-list.vue +++ b/sub-pages/film-list/film-list.vue @@ -14,7 +14,7 @@ </up-tabs> <view class="list-view"> - <up-waterfall v-model="flowList"> + <up-waterfall v-model="films"> <template #left="{ leftList }"> <FlowCard v-for="(item, index) in leftList" :key="index" :item="item" @click="handleDetailClick" /> </template> @@ -22,79 +22,26 @@ <FlowCard v-for="(item, index) in rightList" :key="index" :item="item" @click="handleDetailClick" /> </template> </up-waterfall> + <up-loadmore :status="filmStatus" :line="true" /> </view> </view> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue' -import { onLoad } from '@dcloudio/uni-app' +import { onLoad, onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app' +import { FilmCategoryTree,FilmWorks } from '@/types/index' +import { useGlobal } from '@/composables/useGlobal' +const { $http, $message, $store } = useGlobal() +import { FilmTabCategory,FilmWorksCategory } from '@/enums/dict' +import { useNavigator } from '@/composables/useNavigator' +const { navigateTo } = useNavigator() -interface Item { - id: number - title: string - imgurl: string - username: string - avatar: string - date: string - likes: number -} +import { getTabList } from '@/sub-pages/utils/api' const theme = ref('light') const search = ref('') -const flowList = ref<Item[]>([]) - -const tabList = ref([ - { name: '关注' }, - { name: '推荐' }, - { name: '电影' }, - { name: '科技' }, - { name: '音乐' }, - { name: '美食' }, - { name: '文化' }, - { name: '财经' }, - { name: '手工' } -]) - -const items: Item[] = [ - { - id: 1, - title: 'iPhone 高清全屏壁纸,划走就后悔', - imgurl: 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg', - username: '草莓喵喵', - avatar: '/static/avatar1.jpg', - date: '2024-12-01', - likes: 1397 - }, - { - id: 2, - title: '高清 4K 全屏手机壁纸 #高质量壁纸高清 4K 全屏手机壁纸 #高质量壁纸', - imgurl: 'https://img.yzcdn.cn/vant/cat.jpeg', - username: '4K wallpaper', - avatar: '/static/avatar2.jpg', - date: '02-24', - likes: 167 - }, - { - id: 3, - title: 'iPhone 实况动态壁纸 #动态壁纸', - imgurl: 'https://img.yzcdn.cn/vant/cat.jpeg', - username: '图墙精选', - avatar: '/static/avatar3.jpg', - date: '03-01', - likes: 980 - }, - { - id: 4, - title: '高清小清新壁纸 浪漫的人都有自己的海', - imgurl: 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg', - username: 'wallpaper', - avatar: '/static/avatar4.jpg', - date: '04-10', - likes: 456 - } -] - +const tabList = ref<FilmCategoryTree[]>([]) const onSearch = (value: string) => { uni.showToast({ title: `搜索:${value}`, @@ -102,12 +49,10 @@ }) } -const handleDetailClick = (item: Item) => { - const url = - item.id === 1 - ? `/sub-pages/film-list/film-official-detail?id=${item.id}` - : `/sub-pages/film-list/film-detail?id=${item.id}` - uni.navigateTo({ url }) +const handleDetailClick = (item: FilmCategoryTree) => { + const urlOfficicl=`/sub-pages/film-list/film-official-detail?id=${item.id}`; + const url= `/sub-pages/film-list/film-detail?id=${item.id}` + navigateTo(url) } const showToast = (msg: string) => { @@ -119,11 +64,82 @@ theme.value = storedTheme }) + onMounted(() => { flowList.value = items }) + +onShow(() => { + // 获取分类 + getTabList(FilmTabCategory.FILM_TYPE,tabList) + + // 获取电影 + getfilms() + +}); + +onPullDownRefresh(async () => { + console.log('用户下拉刷新了') + filmPage.value = 1 + getfilms() + uni.stopPullDownRefresh() // 停止下拉刷新动画 +}) + +onReachBottom(() => { + console.log('用户触底了') + getfilms() +}) + +const films = ref<FilmWorks[]>([]) +const filmPage = ref(1) +const filmSize = 10 +const filmStatus = ref('loading') +const getfilms = async () => { + if (filmStatus.value === 'nomore') return + + filmStatus.value = 'loading' + + // TODO 暂时使用光影社区的类别 + const records = await getFilmWorksBase('', filmSize, filmPage.value) + + if (records && records.length > 0) { + // 使用 Set 进行去重 + const existingIds = new Set(films.value.map(item => item.id)) + const uniqueRecords = records.filter(item => !existingIds.has(item.id)) + + films.value = [...films.value, ...uniqueRecords] + + // 如果返回的记录数少于请求的 size,说明没有更多数据 + if (records.length < filmSize) { + filmStatus.value = 'noMore' + } + + filmPage.value++ + } else { + filmStatus.value = 'noMore' + } +} + +const getFilmWorksBase = async (type: String, pageSize: Number, currentPage: Number) => { + const { + code, data + } = await $http.request('get', '/api/filmWorks/list', { + params: { + classify: type, + size: pageSize, + current: currentPage + } + }) + if (code == 0) { + return data.records + } else { + $message.showToast('系统异常,无法获取数据') + return null; + } +} + + + </script> -<style lang="scss" scoped> - -</style> \ No newline at end of file +<style lang="scss" scoped></style> \ No newline at end of file diff --git a/sub-pages/utils/api.ts b/sub-pages/utils/api.ts new file mode 100644 index 0000000..1eed362 --- /dev/null +++ b/sub-pages/utils/api.ts @@ -0,0 +1,41 @@ +// sub-pages/utils/api.ts + +import { ref, Ref } from 'vue' +import { FilmCategoryTree, FilmWorks } from '@/types/index' +import http from '@/plugins/http.js' +import message from '@/plugins/message' + +export const getTabList = async ( + parentId: string, + targetList: Ref<FilmCategoryTree[]>, + isShowDefault: boolean = true +) => { + const { code, data } = await http.request('get', '/api/film/category/list', { + params: { parentId } + }) + + if (code === 0) { + const defaultOption: FilmCategoryTree = { + id: '', + name: '全部', + parentId, + imageUrl: '', + color: '', + sortBy: 0, + shown: true, + levelLimit: '', + childrenCount: 0, + children: [] + } + if (isShowDefault) { + targetList.value = [defaultOption, ...data] + } else { + targetList.value = data + } + + console.log('tabList', targetList.value) + } else { + message.showToast('系统异常,无法获取数据') // 或者用 uni.showToast() + return null + } +} diff --git a/types/index.ts b/types/index.ts index 0aa5aff..4984d83 100644 --- a/types/index.ts +++ b/types/index.ts @@ -8,12 +8,12 @@ } export interface WechatLoginData { - code: string - imgurl?: string - nickname?: string - inviter?: string - phoneNumber?: string - purePhoneNumber?: string + code: string + imgurl?: string + nickname?: string + inviter?: string + phoneNumber?: string + purePhoneNumber?: string } export interface ProtocolData { @@ -22,73 +22,73 @@ content: string; } -export interface FilmWorks{ +export interface FilmWorks { id?: number; /** 中文名称 */ nameCn?: string; - + /** 英文名称 */ nameEn?: string; - + /** 作品类型 */ type?: string; typeStr?: string; - + /** 上映年份 */ releaseYear?: string; - + /** 导演(多个用逗号分隔) */ director?: string; - + /** 制片方 */ producer?: string; - + /** 主要演员(多个用逗号分隔) */ actors?: string; - + /** 剧情关键词(用逗号分隔) */ keywords?: string; - + /** 剧情简介 */ synopsis?: string; - + /** 封面图片URL */ coverUrl?: string; - + /** 封面图片描述文本 */ coverAlt?: string; - + /** 创建者用户类型 */ userType?: string; userTypeStr?: string; - + /** 置顶权重(越大越靠前) */ stickyWeight?: number; - + /** 状态 */ status?: string; statusStr?: string; - + /** 创建者ID */ createBy?: string; - + /** 最后修改者ID */ updateBy?: string; - + /** 收藏量 */ collectCount?: number; - + /** 点赞量 */ likeCount?: number; - + /** 评论量 */ commentCount?: number; - + /** 分享量 */ shareCount?: number; - + /** 分类 */ classify?: number; @@ -101,7 +101,80 @@ avatar?: String; nickname?: String; - + createTime?: String; -} \ No newline at end of file +} + +interface Node { + id: any; + parentId: any; + children: Node[]; +} + +export interface FilmCategoryTree extends Node { + /** 名称 */ + name: string; + + /** 父分类名称 */ + parentName: string; + + /** 图标 */ + imageUrl: string; + + /** 颜色 */ + color: string; + + /** 排序 */ + sortBy: number; + + /** 是否展示 */ + shown: boolean; + + /** 级别限制 */ + levelLimit: string; + + /** 子分类数量 */ + childrenCount: number; +} + +export interface FilmPicture { + name: string; + size: number; + url: string; +} + +export interface FilmInfo { + id: number; + nameCn: string; + nameEn: string; + nickname: string | null; + actors: string; + director: string; + producer: string; + filmContent: string | null; + filmPictures: FilmPicture[]; + coverUrl: string; + coverAlt: string; + coverTitle: string; + classify: string | null; + keywords: string; + tag: string; + type: string; + typeStr: string; + status: string; + statusStr: string; + stickyWeight: number; + synopsis: string; + avatar: string | null; + releaseYear: number | null; + collectCount: number; + commentCount: number; + likeCount: number; + shareCount: number; + userType: string; + userTypeStr: string; + createBy: string; + createTime: string; + updateBy: string | null; +} -- Gitblit v1.9.3