mcwl-pc/app/pages/model-details/[id].vue

620 lines
20 KiB
Vue

<script setup lang="ts">
import { commonApi } from "@/api/common";
import { Close, DiamondSharp, PersonAddOutline } from "@vicons/ionicons5";
import {
CircleUser,
Download,
EllipsisVertical, Heart, Play,
SquarePlus
} from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from "vue";
import { useRouter } from "vue-router";
const userStore = useUserStore();
const message = useMessage();
const router = useRouter();
// 用于版本tabs当前选中的选项卡
definePageMeta({
layout: "default",
});
// const userStore = useUserStore()
const route = useRoute();
const { id } = route.params as { id: string };
const activeTab = ref(null);
const commentHeight = ref(800);
const detailsInfo = ref({});
const currentUserInfo = ref<any>({});
const isVisibleReport = ref(false);
// 先获取用户信息 再获取版本信息
const versionByWorkInfo = ref([]);
async function getInfo() {
try {
const res = await request.get(`/model/selectModelById?id=${id}`);
if (res.code === 200) {
detailsInfo.value = res.data;
detailsInfo.value.styleList = JSON.parse(res.data.styleList);
debugger
// detailsInfo.value.styleList =JSON.parse(res.data.styleList)
// // 1翻译
try {
const res1 = await request.get(`/ModelVersion/finbyid?id=${res.data.id}`); // 获取版本
if (res1.code === 200 && res1.data.length > 0) {
versionByWorkInfo.value = res1.data;
versionByWorkInfo.value.forEach((item) => {
item.sampleImagePaths = item.sampleImagePaths.split(",");
});
nextTick(() => {
activeTab.value = versionByWorkInfo.value[0].id;
});
// const commentRes = await request.get(`/WorkFlowComment/comment/${res.data.id}`)
}
} catch (error) {
console.log(error);
}
// // 获取当前作品的用户信息
try {
const res = await request.get(
`/system/user/selectUserById?id=${detailsInfo.value.userId}`
);
if (res.code === 200) {
currentUserInfo.value = res.data;
}
} catch (error) {
console.log(error);
}
getAttention();
}
} catch (error) {
console.log(error);
}
}
getInfo();
// 获取用户点赞/粉丝/关注数量
interface SelectUserInfo {
attention: number;
bean: number;
imageLikeNum: number;
modelDownLoadNum: number;
modelLikeNum: number;
modelRunNum: number;
}
const selectUserInfo = ref<SelectUserInfo>({
attention: 0,
bean: 0,
imageLikeNum: 0,
modelDownLoadNum: 0,
modelLikeNum: 0,
modelRunNum: 0,
});
// 获取点赞粉丝等的数量
async function getAttention() {
try {
const res = await request.get(
`/attention/selectUserInfo?userId=${detailsInfo.value.userId}`
);
if (res.code === 200) {
selectUserInfo.value = res.data;
}
} catch (err) {
console.log(err);
}
}
// 举报/编辑/删除
const isDelete = ref(false);
async function handleSelect(event: Event, type: string) {
event.stopPropagation(); // 阻止事件冒泡
if (type === "report") {
isVisibleReport.value = true;
// await request.get(`/WorkFlow/report?id=${id}`) // 举报
} else if (type === "edit") {
router.push({
path: `/publish-model`,
query: {
type: "edit",
id: detailsInfo.value.id,
},
});
} else {
isDelete.value = true;
}
}
// 删除
async function onDelete() {
try {
const res = await request.get(`/model/delete?id=${detailsInfo.value.id}`);
if (res.code === 200) {
message.success("删除成功");
isDelete.value = false;
router.push("/personal-center");
}
} catch (err) {
console.log(err);
}
}
// 关注用户/取消关注
async function onChangeAttention() {
try {
const res = await request.get(
`/attention/addAttention?userId=${detailsInfo.value.userId}`
);
if (res.code === 200) {
if (res.data) {
detailsInfo.value.isAttention = 1;
message.success("关注成功");
} else {
detailsInfo.value.isAttention = 0;
message.success("取消关注成功");
}
}
} catch (err) {
console.log(err);
}
}
// 点赞
async function onLike() {
try {
const res = await request.get(
`/ModelComment/modelLike?modelId=${detailsInfo.value.id}`
);
if (res.code === 200) {
detailsInfo.value.isLike === 0
? (detailsInfo.value.isLike = 1)
: (detailsInfo.value.isLike = 0);
if (detailsInfo.value.isLike === 0) {
message.success("取消点赞成功");
} else {
message.success("点赞成功");
}
}
} catch (err) {
console.log(err);
}
}
// 举报
const reportParams = ref({
reportId: undefined,
text: "",
type:1
});
const reportList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "report_type" });
if (res.code === 200) {
reportList.value = res.data;
}
} catch (error) {
console.log(error);
}
}
getDictType();
function handleChange(item: any) {
reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") {
reportParams.value.text = "";
}
console.log("object", reportParams.value);
}
function closeReport() {
isVisibleReport.value = false;
}
async function onReport(){
if( reportParams.value.reportId !== undefined){
reportParams.value.productId = detailsInfo.value.id
try{
const res = await request.post('/report/addReport', reportParams.value)
if(res.code === 200){
message.success("举报成功");
closeReport()
}
}catch(err){
console.log(err);
}
}
}
function toPersonalCenter(){
const baseUrl = window.location.origin
if(userStore?.userInfo?.userId === detailsInfo.value.userId){
window.open(`${baseUrl}/personal-center`, '_blank', 'noopener,noreferrer')
}else{
debugger
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer')
}
}
</script>
<template>
<div class="flex justify-center">
<div class="w-[1125px] p-4">
<div class="flex items-center">
<div class="text-[26px] font-bold mr-4">
{{ detailsInfo.modelName }}
</div>
<n-tooltip trigger="hover">
<template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full">
<component :is="Play" class="h-[14px] w-[14px] text-black menu-icon m-1" />
<span> {{ detailsInfo.reals || 0 }} </span>
</div>
</template>
在线生成数
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full mx-4">
<component
:is="Download"
class="h-[14px] w-[14px] text-black menu-icon m-1"
/>
<span> {{ detailsInfo.numbers || 0 }} </span>
</div>
</template>
下载数
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full">
<!-- <img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt="" /> -->
<component
:is="Heart"
class="h-[12px] w-[12px] mr-1 text-[#000]"
/>
<span>{{ detailsInfo.likeNum || 0 }} </span>
</div>
</template>
点赞数
</n-tooltip>
</div>
<div class="flex items-center mt-3 mb-5">
<div
v-for="(item, index) in detailsInfo.styleList"
:key="index"
class="text-[12px] bg-[#ebf2fe] p-1 px-2 text-[#557abf] mr-4 rounded-md"
>
{{ item }}
</div>
</div>
<div class="flex w-full gap-1">
<div class="w-2/3">
<div class="w-full">
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tab-pane
v-for="(item, index) in versionByWorkInfo"
:key="index"
:name="item.id"
:tab="item.versionName"
>
<!-- 显示最后一步上传图片的图片 -->
<div class="grid grid-cols-2 gap-2.5 box-border">
<img
v-for="(subItem, subIndex) in item.sampleImagePaths"
:key="subIndex"
:src="subItem"
class="w-full h-[350px] rounded-lg"
alt=""
/>
</div>
<div v-if="detailsInfo.original === 1" class="font-bold text-[20px] my-6">
转载自作者: {{ detailsInfo.authorName }}
</div>
<!-- 富文本中输入的文字 图片 -->
<div class="w-full mt-2">
<div v-html="item.versionDescription" />
</div>
</n-tab-pane>
</n-tabs>
</div>
<div class="mt-4">
<div style="padding: 20px">
<NConfigProvider>
<NMessageProvider>
<BaseComment
v-if="detailsInfo.id"
type="model"
:height="commentHeight"
:details-info="detailsInfo"
/>
</NMessageProvider>
</NConfigProvider>
</div>
</div>
</div>
<div class="w-1/3 mt-3">
<div
class="flex justify-between text-[#a3a1a1] text-[12px] items-center -ml-60"
>
<div class="flex justify-end">
<div v-if="detailsInfo.createTime" class="mr-2">
首发时间{{ detailsInfo.createTime }}
</div>
<div v-if="detailsInfo.updateTime">
更新时间:{{ detailsInfo.updateTime }}
</div>
</div>
<div class="flex items-center relative">
<n-icon
size="20"
:color="detailsInfo.isLike === 0 ? '#ccc' : '#ff0000'"
@click="onLike"
>
<Heart class="cursor-pointer" />
</n-icon>
<div class="group relative">
<component
:is="EllipsisVertical"
class="h-[18px] w-[48px] text-[#557abf] cursor-pointer"
/>
<div
class="absolute right-0 top-[10px] hidden group-hover:block text-[#000000] text-[12px] bg-white rounded-lg text-center px-2 py-2 w-20 mt-2 shadow-lg z-10"
>
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'report')"
>
举报
</div>
<template v-if="userStore?.userInfo?.userId === detailsInfo.userId">
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'edit')"
>
编辑
</div>
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'delete')"
>
删除
</div>
</template>
</div>
</div>
</div>
</div>
<div
class="flex items-center mt-10 p-2 bg-[#f3f5f9] w-full rounded-md h-[80px] box-border"
>
<div class="w-[60px] h-[60px] rounded-full overflow-hidden mr-4">
<client-only>
<NAvatar
@click="toPersonalCenter"
class="w-full h-full mr-2 block cursor-pointer"
round
size="small"
:src="currentUserInfo.avatar"
/>
</client-only>
</div>
<div class="flex-1">
<div class="flex items-center justify-between">
<div class="flex-1">
<client-only>
<div class="text[20px] font-bold">
{{ currentUserInfo.nickName }}
</div>
</client-only>
<!-- 0代表原创 1代表转载 -->
<div v-if="detailsInfo.original === 1" class="original">
<n-icon size="14" class="mr-2">
<DiamondSharp />
</n-icon>
原创作者
</div>
</div>
<div
class="flex-1 flex justify-end"
v-if="userStore?.userInfo?.userId !== detailsInfo.userId"
>
<div
class="flex items-center font-bold px-1 justify-center w-20 h-8 rounded-full text-[#426af7] border border-[#426af7] border-solid cursor-pointer"
@click="onChangeAttention"
>
<n-icon v-if="detailsInfo.isAttention === 0" size="16" class="mr-2">
<PersonAddOutline />
</n-icon>
{{ detailsInfo.isAttention === 1 ? "已关注" : "关注" }}
</div>
</div>
</div>
<div class="flex items-center text-[#969798]">
<component
:is="CircleUser"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798] m-0"
/>
<span class="mr-2"> {{ selectUserInfo.bean }} </span>
<!-- <component
:is="HardDriveUpload"
class="h-[12px] w-[14px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-2"> 2 </span> -->
<component
:is="Play"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-2"> {{ selectUserInfo.productNum }} </span>
<component
:is="Download"
class="h-[12px] w-[12px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-2"> {{ selectUserInfo.modelDownloadNum }} </span>
</div>
</div>
</div>
<!-- 不支持的bg #b1b2b2 -->
<div
class="flex items-center justify-center mt-4 w-full text-white bg-[#3c7af6] w-full rounded-md h-[50px] cursor-pointer"
>
<component
:is="Play"
class="h-[20px] w-[20px] text-white menu-icon m-1 text-[#969798]"
/>
<span class="mr-1"> 立即生图</span>
</div>
<div class="flex gap-y-2">
<div
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md"
>
<component
:is="SquarePlus"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1">加入模型课</span>
</div>
<div
class="flex flex-1 items-center bg-gradient-to-r from-[#ffe9c8] to-[#ffd264] justify-center ml-1 mt-4 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer"
>
<component
:is="Download"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1"> 下载 (122.22MB) </span>
</div>
</div>
<!-- <div style="background: linear-gradient(135deg,#3cc9ff, #8fa6ff, 41%, #d8b4ff 74%,#326bff)" class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#fff] w-full rounded-md h-[80px] cursor-pointer hover:bg-[#f1f2f7]">
<component :is="Download" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" />
<span class="mr-1">
下载客户端
</span>
</div> -->
<n-modal
v-model:show="isDelete"
:mask-closable="false"
preset="dialog"
title="提示!"
content="确定要将模型删除? 模型删除后无法找回"
negative-text="取消"
positive-text="确认"
@negative-click="onDelete"
@positive-click="onDelete"
/>
<n-modal
v-model:show="isVisibleReport"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl p-4">
<div class="flex items-center justify-between">
<div class="text-xl">举报</div>
<div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeReport">
<Close />
</n-icon>
</div>
</div>
<div class="flex flex-col">
<n-radio
class="m-4 text-[#fff000]"
size="large"
v-for="(item, index) in reportList"
:key="index"
:checked="reportParams.reportId === item.dictValue"
value="Definitely Maybe"
name="basic-demo"
@change="handleChange(item)"
>
{{ item.dictLabel }}
</n-radio>
<n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'"
v-model:value="reportParams.text"
placeholder="点击输入"
type="textarea"
:autosize="{
minRows: 5,
maxRows: 10,
}"
/>
<div
@click="onReport"
class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer"
:class="[
reportParams.reportId !== undefined
? 'bg-[#4c79ee]'
: 'bg-[#cccccc]',
]"
>
确认
</div>
</div>
</div>
</n-modal>
<div />
<!-- <Report></Report> -->
</div>
</div>
</div>
<!-- <Report></Report> -->
</div>
</template>
<style lang="scss">
.header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
}
.header-tag {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
display: flex;
align-self: flex-start;
justify-content: space-between;
}
.n-tabs.n-tabs--line-type .n-tabs-tab.n-tabs-tab,
.n-tabs.n-tabs--bar-type .n-tabs-tab.n-tabs-tab {
color: #949494;
}
.n-tabs.n-tabs--line-type .n-tabs-tab.n-tabs-tab--active,
.n-tabs.n-tabs--bar-type .n-tabs-tab.n-tabs-tab--active {
color: #000;
font-weight: 700;
font-size: 24px;
}
.n-tabs .n-tabs-bar {
position: absolute;
bottom: 0;
height: 4px;
background: linear-gradient(90deg, #173eff 0%, #1b7dff 100%);
border-radius: 2px;
transition: left 0.2s var(--n-bezier), max-width 0.2s var(--n-bezier),
opacity 0.3s var(--n-bezier), background-color 0.3s var(--n-bezier);
}
.original{
margin: 2px 0;
padding: 2px 0;
display: flex;
align-items: center;
justify-content: center;
width: 90px;
font-size: 12px;
color: #aa8645;
font-weight: 400;
background: linear-gradient(94.11deg, #efd6a9 10.52%, #f0dcbc 107.96%);
border-radius: 4px;
transform: skew(-10deg);
}
</style>