Commit b034b191 by lijiabin

【需求 17679】 perf: 优化类型

parent e5c7e6a6
......@@ -16,6 +16,7 @@ import type {
SearchMoreColumnItemDto,
SearchMoreVideoParams,
SearchMoreVideoItemDto,
SecondCommentItemDto,
} from './types'
import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
......@@ -316,8 +317,8 @@ export const addComplaint = (data: { articleId: number; reason: string }) => {
/**
* 问吧-获取回答列表的评论(二级评论)
*/
export const getSecondCommentList = (data: { pId: number }) => {
return service.request<boolean>({
export const getSecondCommentList = (data: CommentSearchParams) => {
return service.request<BackendServicePageResult<SecondCommentItemDto>>({
url: `/api/cultureComment/getQuestionComment`,
method: 'POST',
data,
......
......@@ -132,7 +132,7 @@ export interface ArticleItemDto {
faceUrl: string
videoUrl: string
description: string
createUserId: number
createUserId: string
createTime: number
viewCount: number
playCount: number
......@@ -312,7 +312,7 @@ export interface CommentChildrenSearchParams extends PageSearchParams {
export interface AddCommentDto {
articleId: number | string
content: string
pId?: number | string
pid?: number | string
}
/**
......@@ -336,7 +336,7 @@ export interface CommentItemDto {
regionHide: number
replyUser: string
replyName: string
userId: number
userId: string
isHaveChildren: BooleanFlag
childrenNum: number
showChildrenPage: boolean
......@@ -345,6 +345,7 @@ export interface CommentItemDto {
loadingChildren: boolean
showComment: boolean
isExpand: boolean
childNum: number
}
/**
......@@ -412,3 +413,8 @@ export interface SearchMoreVideoItemDto {
videoDuration: string
viewCount: number
}
/**
* 获取问吧二级评论的返回参数
*/
export type SecondCommentItemDto = CommentItemDto
......@@ -26,7 +26,7 @@ export interface LoginResponseDto {
credentialsNonExpired: boolean
accountNonLocked: boolean
token: string
userId: number
userId: string
hiddenAvatar: string
hiddenName: string
signature: string
......
<template>
<el-dropdown @command="handleMore" trigger="click">
<!-- <el-button class="p-2 rounded-md cursor-pointer border-none!"> -->
<el-icon class="cursor-pointer"><More /></el-icon>
<!-- </el-button> -->
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="举报">举报</el-dropdown-item>
......@@ -15,10 +13,6 @@
import { addComplaint } from '@/api'
import type { ArticleItemDto } from '@/api/article/types'
// defineOptions({
// inheritAttrs: false,
// })
const { articleDetail } = defineProps<{
articleDetail: ArticleItemDto
}>()
......
......@@ -348,7 +348,6 @@ const {
const emit = defineEmits<{
(e: 'commentSuccess'): void
}>()
const router = useRouter()
const total = defineModel<number>('total', { required: true, default: 0 })
......
......@@ -67,7 +67,6 @@
<img
:src="item.avatar"
class="w-10 h-10 rounded-full object-cover cursor-pointer hover:opacity-80 transition-opacity flex-shrink-0"
@click="handleUserInfo(item)"
/>
<div class="flex-1 border-b border-gray-100">
......@@ -197,8 +196,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue'
import { ArrowLeft, Star, StarFilled, CaretRight, Position } from '@element-plus/icons-vue'
import { ArrowLeft, CaretRight, Position } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import { useUserStore } from '@/stores'
......@@ -251,7 +249,7 @@ const { list, total, search, searchParams, goToPage, changePageSize, refresh, lo
immediate: false,
})
const open = async (item: CommentItemDto) => {
const open = async () => {
// const { data } = await getSecondCommentChildren({
// pid: item.id,
// current: 1,
......@@ -276,10 +274,6 @@ const open = async (item: CommentItemDto) => {
visible.value = true
}
const close = () => {
visible.value = false
}
const formatDate = (time: number) => {
return dayjs(time * 1000).format('MM-DD HH:mm')
}
......@@ -353,11 +347,6 @@ const handleLike = async (item: CommentItemDto) => {
}
}
const handleUserInfo = (item: CommentItemDto) => {
// 您的跳转逻辑
// router.push(...)
}
defineExpose({
open,
})
......
<template>
<button class="btn" v-bind="attrs">测试111</button>
</template>
<script setup lang="ts">
// 二次封装el-button 除去el-button的默认样式 然后保留其他功能
import type { ButtonProps } from 'element-plus'
// const props = defineProps<ButtonProps>()
const attrs = useAttrs()
</script>
<style scoped>
.el-button {
/* 会作用到根元素 */
all: unset !important;
}
</style>
......@@ -46,8 +46,6 @@ const hasReachedLimit = computed(() => fileList.value.length >= props.limit)
const showUploadBtn = computed(() => (hasReachedLimit.value ? 'none' : 'flex'))
const isInternalUpdate = ref(false)
const uploadProgress = ref(0)
const parseModelValueToUrls = (value: T): string[] => {
if (!value) return []
return Array.isArray(value) ? value.filter(Boolean) : (value as string).split(',').filter(Boolean)
......@@ -125,15 +123,15 @@ const handleChange: UploadProps['onChange'] = async (uploadFile, uploadFiles) =>
try {
let fileIndex = fileList.value.findIndex((file) => file.uid === uid)
if (fileIndex !== -1) {
fileList.value[fileIndex].status = 'uploading'
fileList.value[fileIndex]!.status = 'uploading'
}
const { data } = await uploadFileApi(uploadFile.raw, (progress) => {
console.log('progress', progress)
})
console.log('data', data)
const url = data.fileUrl || data.data[0].filePath
const name = data.fileName || data.data[0].finalName
const url = data.data[0]?.filePath || ''
const name = data.data[0]?.finalName || ''
fileIndex = fileList.value.findIndex((file) => file.uid === uid)
......@@ -160,7 +158,7 @@ const handleChange: UploadProps['onChange'] = async (uploadFile, uploadFiles) =>
}
}
const handleBeforeRemove: UploadProps['beforeRemove'] = (uploadFile) => {
const handleBeforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确定要删除这个文件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
......
......@@ -183,15 +183,15 @@ const startUpload = async () => {
// 根据你的 API 返回结构调整
const videoData: VideoInfo = {
url: data.data[0].filePath,
url: data.data[0]?.filePath || '',
// 暂时写死
// url: 'https://soundasia.oss-cn-shenzhen.aliyuncs.com/OA/readName/mp4/2025/11/12/Common/1762918987602.mp4',
name: currentFile.value.name,
size: currentFile.value.size,
duration: metadata.duration,
resolution: metadata.resolution,
poster: data.data[0].filePath,
fileId: data.data[0].fileId,
poster: data.data[0]?.filePath || '',
fileId: data.data[0]?.fileId || '',
}
videoInfo.value = videoData
......
......@@ -28,23 +28,23 @@ const editorRef = shallowRef()
const valueHtml = defineModel<string>()
// 去掉上传视频的功能
const toolbarConfig = {}
toolbarConfig.excludeKeys = ['group-video', 'group-more-video', 'group-more-video']
const toolbarConfig = {
excludeKeys: ['group-video', 'group-more-video', 'group-more-video'],
}
// 去掉上传视频
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {},
}
// 修改 uploadImage 菜单配置
editorConfig.MENU_CONF['uploadImage'] = {
customUpload: async (file, insertFn) => {
MENU_CONF: {
uploadImage: {
customUpload: async (file: File, insertFn: (url: string) => void) => {
const { data } = await uploadFile(file)
console.log(data)
insertFn(data.data[0].filePath)
insertFn(data.data[0]?.filePath || '')
},
},
},
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
......@@ -52,7 +52,7 @@ onBeforeUnmount(() => {
editor.destroy()
})
const handleCreated = (editor) => {
const handleCreated = (editor: typeof Editor) => {
editorRef.value = editor // 记录 editor 实例,重要!
}
</script>
......
<template>
<md-editor
v-model="value"
preview-theme="arknights"
:class="!preview && height === 'auto' ? 'md_fixed' : ''"
v-bind="isPreview"
:style="{ height }"
@on-upload-img="handleUpload"
></md-editor>
<!-- 图片预览插件 -->
<ElImageViewer v-if="previewShow" :url-list="previewList" :initial-index="previewIndex" @close="closePreview"></ElImageViewer>
</template>
<script setup lang="ts">
import { uploadImage } from '@/api'
import MdEditor from 'md-editor-v3'
import 'md-editor-v3/lib/style.css'
interface IProp {
modelValue?: string
preview?: boolean
height?: string
}
const prop = withDefaults(defineProps<IProp>(), {
modelValue: '',
preview: false,
height: 'auto'
})
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
}>()
const value = computed({
get() {
return prop.modelValue || ''
},
set(val: string) {
emit('update:modelValue', val)
}
})
// 预览
const isPreview = computed(() => {
if (!prop.preview) return {}
return {
preview: true,
htmlPreview: true,
previewOnly: true
}
})
/**
* 文件上传
*/
type InsertFnType = (urls: string[]) => void
const handleUpload = async (files: File[], callback: InsertFnType) => {
const res = await uploadImage(files)
const url = res.data.originList
// 最后插入图片
callback(url)
}
/**
* 图片预览
*/
const previewShow = ref(false)
const previewList = ref<string[]>([])
const previewIndex = ref(0)
const req = /<img[^>]+src=['"]([^'"]+)['"]+/g
watch(
() => prop.modelValue,
val => {
let temp: RegExpExecArray | null
while ((temp = req.exec(val)) != null) {
previewList.value.push(temp[1])
}
}
)
MdEditor.config({
markedRenderer(renderer) {
renderer.image = (href, title = '', desc = '') => {
if (!href) return ''
let previewHref = href
if (href.indexOf('-small') > -1) {
previewHref = href.replace('-small', '')
} else if (href.indexOf('-mid') > -1) {
previewHref = href.replace('-mid', '')
}
previewList.value.push(previewHref)
return `<img src="${href}" title="${title}" alt="${desc}" style="cursor: zoom-in" >`
}
return renderer
}
})
onMounted(() => {
nextTick(() => {
document.querySelector('.md-preview')?.addEventListener('click', e => {
const el = e.target as HTMLImageElement
if (el?.nodeName == 'IMG') {
let imgSrc = el.src
if (imgSrc.indexOf('-small') > -1) {
imgSrc = imgSrc.replace('-small', '')
} else if (imgSrc.indexOf('-mid') > -1) {
imgSrc = imgSrc.replace('-mid', '')
}
const index = previewList.value.findIndex(v => v === imgSrc)
if (index >= 0) {
previewIndex.value = index
} else {
previewList.value.push(imgSrc)
previewIndex.value = previewList.value.length - 1
}
showPreview()
}
})
})
})
const showPreview = () => {
// PC端预览
previewShow.value = true
}
const closePreview = () => {
previewShow.value = false
}
</script>
<style lang="scss" scoped>
.md_fixed {
overflow: visible;
min-height: 400px;
}
</style>
<style lang="scss">
.md {
font-family: 'Segoe UI Emoji', 'Apple Color Emoji', -apple-system, BlinkMacSystemFont, Segoe UI Variable, Segoe UI, system-ui,
ui-sans-serif, Helvetica, Arial, sans-serif;
}
.md_fixed {
.md-toolbar-wrapper {
position: sticky;
top: 0;
z-index: 10;
background-color: #fff;
box-shadow: 0 6px 6px -6px rgba(0, 0, 0, 0.1);
overflow: visible;
height: auto;
}
.md-toolbar-wrapper .md-toolbar {
position: relative;
min-width: 0;
flex-wrap: wrap;
}
}
.md_fixed .md-toolbar-wrapper .md-toolbar-left,
.md-toolbar-wrapper .md-toolbar-right {
flex-wrap: wrap;
}
.md-preview {
line-height: 1.5;
img {
max-width: 100%;
}
}
</style>
import type { ArticleType, BooleanFlag } from '@/constants'
import { ArticleTypeEnum, BooleanFlag } from '@/constants'
import { useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
/**
......@@ -64,7 +64,7 @@ export function isCulturePath() {
}
// 点击头像跳转用户首页
export function jumpToUserHomePage({ userId, isReal }: { userId: number; isReal: BooleanFlag }) {
export function jumpToUserHomePage({ userId, isReal }: { userId: string; isReal: BooleanFlag }) {
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const isSelf = userInfo.value.userId === userId
......@@ -76,10 +76,10 @@ export function jumpToUserHomePage({ userId, isReal }: { userId: number; isReal:
}
// 根据文章类型跳到对应的文章详情页面
export function jumpToArticleDetailPage({ type, id }: { type: ArticleType; id: number }) {
if (type === 'video') {
export function jumpToArticleDetailPage({ type, id }: { type: ArticleTypeEnum; id: number }) {
if (type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${id}`)
} else if (type === 'question') {
} else if (type === ArticleTypeEnum.QUESTION) {
window.open(`/questionDetail/${id}`)
} else {
window.open(`/articleDetail/${id}`)
......
......@@ -480,7 +480,7 @@ onActivated(async () => {
}
// 回显主副标签
form.value.mainTagId = String(tagIdList[0]) || ''
form.value.mainTagId = tagIdList[0] ? String(tagIdList[0]) : ''
form.value.tagList = tagIdList.slice(1) || []
const { imgUrl, faceUrl } = data
......
......@@ -28,15 +28,9 @@
@click="handleBackUser"
>返回个人账号</el-button
>
<!-- 暂时不加权限 -->
<el-button
v-if="userInfo.isAdmin || userInfo.isOfficialAccount"
type="primary"
plain
size="small"
@click="handleAdmin"
>后台管理</el-button
>
<!-- v-if="userInfo.isAdmin || userInfo.isOfficialAccount" -->
<el-button type="primary" plain size="small" @click="handleAdmin">后台管理</el-button>
</div>
</div>
......
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