活动功能

planet
shenhan 2025-03-10 17:33:34 +08:00
parent 1717d5abba
commit c738606731
48 changed files with 1968 additions and 699 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

3
app/components.d.ts vendored
View File

@ -24,7 +24,7 @@ declare module 'vue' {
NInfiniteScroll: typeof import('naive-ui')['NInfiniteScroll'] NInfiniteScroll: typeof import('naive-ui')['NInfiniteScroll']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup'] NInputGroup: typeof import('naive-ui')['NInputGroup']
NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NInputNumber: typeof import('naive-ui')['NInputNumber']
NModal: typeof import('naive-ui')['NModal'] NModal: typeof import('naive-ui')['NModal']
NPopconfirm: typeof import('naive-ui')['NPopconfirm'] NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NQrCode: typeof import('naive-ui')['NQrCode'] NQrCode: typeof import('naive-ui')['NQrCode']
@ -32,6 +32,7 @@ declare module 'vue' {
NRadioGroup: typeof import('naive-ui')['NRadioGroup'] NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NSelect: typeof import('naive-ui')['NSelect'] NSelect: typeof import('naive-ui')['NSelect']
NSpace: typeof import('naive-ui')['NSpace'] NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NTabPane: typeof import('naive-ui')['NTabPane'] NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs'] NTabs: typeof import('naive-ui')['NTabs']
NTooltip: typeof import('naive-ui')['NTooltip'] NTooltip: typeof import('naive-ui')['NTooltip']

View File

@ -17,7 +17,7 @@ const ruleForm = ref({})
const rules = ref({ const rules = ref({
nickName: [ nickName: [
{ required: true, message: '请输入用户名', trigger: 'blur' }, { required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }, { min: 2, max: 15, message: '长度在 2 到 15 个字符', trigger: 'blur' },
], ],
}) })
// //
@ -79,7 +79,8 @@ watch(
ruleForm.value.avatar = newUserInfo.avatar ruleForm.value.avatar = newUserInfo.avatar
ruleForm.value.brief = newUserInfo.brief ruleForm.value.brief = newUserInfo.brief
ruleForm.value.userId = newUserInfo.userId ruleForm.value.userId = newUserInfo.userId
// ruleForm.value.invitationName = newUserInfo.invitationName ruleForm.value.invitationName = newUserInfo.invitationName
ruleForm.value.invitationCode = newUserInfo.invitationCode
} }
}, },
{ immediate: true, deep: true }, // ruleForm { immediate: true, deep: true }, // ruleForm
@ -128,13 +129,14 @@ onMounted(() => {
<n-form-item path="nickName" label="用户名"> <n-form-item path="nickName" label="用户名">
<n-input v-model:value="ruleForm.nickName" placeholder="请输入用户名" @keydown.enter.prevent /> <n-input v-model:value="ruleForm.nickName" placeholder="请输入用户名" @keydown.enter.prevent />
</n-form-item> </n-form-item>
<div v-if="userInfo.invitationName" class="mb-3">
已经填写: {{ userInfo.invitationName }} 的邀请码 <div v-if="userStore.userInfo.invitationName" class="mb-3">
已经填写: {{ userStore.userInfo.invitationName }} 的邀请码
</div> </div>
<!-- <n-form-item v-if="userInfo.invitationName" path="invitationCode"> <!-- <n-form-item v-if="userInfo.invitationName" path="invitationCode">
</n-form-item> --> </n-form-item> -->
<n-form-item v-else path="invitationCode" label="邀请码"> <n-form-item v-else path="invitationCode" label="邀请码">
<n-input v-model:value="ruleForm.invitationName" placeholder="请输入邀请码" @keydown.enter.prevent /> <n-input v-model:value="ruleForm.invitationCode" placeholder="请输入邀请码" @keydown.enter.prevent />
</n-form-item> </n-form-item>
<n-form-item label="简介" path="textareaValue"> <n-form-item label="简介" path="textareaValue">

View File

@ -0,0 +1,239 @@
<script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next';
import type { FormInst } from 'naive-ui';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue';
const props = defineProps({
isMember: {
type: Object,
default: () => {},
},
})
const emit = defineEmits(['closePayment', 'paymentSuccess'])
const message = useMessage()
let pollingTimer: ReturnType<typeof setInterval> | undefined
const formRef = ref<FormInst | null>(null)
// const isShowPayment = ref(false)
const userStore = useUserStore()
interface UserInfoType {
nickName: string
avatar: string
brief: string
userId: number | string
}
const userInfo = {
nickName: userStore.userInfo?.nickName ?? '',
avatar: userStore.userInfo?.avatar ?? '',
brief: userStore.userInfo?.brief ?? '',
userId: userStore.userInfo?.userId ?? '',
} as UserInfoType
function onCloseModel() {
emit('closePayment')
}
function onPaymentSuccess() {
emit('paymentSuccess')
}
const qrUrl = ref('')
//
const paymentStatus = ref(1)
const amount = ref(10)
const paymentParams = ref({
amount: 10,
type: 'wallet',
})
async function getQrCode() {
try {
paymentParams.value.amount = amount.value
const res = await request.post(`/ali/pay/doPay`, paymentParams.value)
if (res.code === 200) {
paymentStatus.value = 1
qrUrl.value = res.data.url
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`)
if (res2.data === 2) { // 1 2 4
paymentStatus.value = 2
clearTimeout(pollingTimer)
onPaymentSuccess()
emit('closePayment')
message.success('支付成功!')
}
else if (res2.data === 4) {
paymentStatus.value = 4
clearTimeout(pollingTimer)
}
}
catch (err) {
console.log('object', err)
}
}, 2000)
}
}
catch (err) {
console.log(err)
}
}
//
const isVisible = ref(true)
//
// const points = ref(0)
// async function getPoints() {
// try {
// const res = await request.get('/member/getPoints')
// if (res.code === 200) {
// points.value = res.data.points
// }
// }
// catch (err) {
// console.log(err)
// }
// }
// getPoints()
//
// const isMember = ref(false)
// async function getIsMember() {
// try {
// const res = await request.get('/member/isMember')
// if (res.code === 200) {
// isMember.value = res.data
// }
// }
// catch (err) {
// console.log(err)
// }
// }
// getIsMember()
onBeforeMount (() => {
getQrCode()
})
defineExpose({
isVisible,
})
onBeforeUnmount(() => {
clearInterval(pollingTimer)
})
</script>
<template>
<n-modal
v-model:show="isVisible"
:preset="null"
:mask-closable="false"
transform-origin="center"
class="custom-modal"
>
<div class="bg-white rounded-xl w-200">
<div
class="p-4 flex justify-between rounded-t-xl bg-gradient-to-r from-[#fcf2da] to-[#f9db9f]"
>
<div class="flex items-center">
<div>
<img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4">
</div>
<div class="flex flex-col">
<div class="text-[#814600] text-xl">
{{ userInfo.nickName }}
</div>
<div class="text-[#6a6a6a] text-xs mt-1">
{{ props.isMember.result === '1' ? `会员到期时间: ${props.isMember.endDate}` : '您还不是魔创未来的会员' }}
</div>
</div>
</div>
<div @click="onCloseModel">
<component :is="X" class="h-[18px] w-[18px] text-[#61666d] cursor-pointer" />
</div>
</div>
<!-- <div class="p-4">
余额{{ points }}积分
</div> -->
<div class="mb-4 mt-6 flex">
<n-form
ref="formRef"
:label-width="80"
:model="paymentParams"
size="large"
label-placement="left"
style="width: 240px"
>
<n-form-item label="输入积分" path="modelProduct.modelName">
<n-input v-model:value="amount" type="number" placeholder="输入积分" />
</n-form-item>
</n-form>
<!-- <div>
确定
</div> -->
<n-button type="primary" class="mt-1 ml-2" @click="getQrCode">
确定
</n-button>
</div>
<!-- <div v-for="(item, index) in activityList" :key="index">
{{ item.activityName }}
</div> -->
<div class="mt-1 text-[#9d8c75] text-[12px] w-[500px] px-3">
1000个算力约可生图1000张或训练5次按照生图默认参数或训练基础参数预估即训练图片张数20张*单张训练次数15*训练轮数10
您充值的算力永久有效
算力充值不退不换
</div>
<div class="flex justify-center items-center my-4">
<div class="w-30 h-30 flex justify-center items-center relative">
<n-qr-code :value="qrUrl" :size="90" style="padding: 0;" />
<div v-if="paymentStatus === 4" class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white" @click="getQrCode">
请点击刷新<RotateCcw />
</div>
</div>
<div class="flex justify-center ml-2 flex-col pb-[14px]">
<div class="flex items-baseline">
<div class="text-[#222] font-medium mr-1">
支付
</div>
<div class="text-[#814600] mr-1">
<span class="text-[16px] mr-1">¥</span>
<span class="text-[40px]">{{ paymentParams.amount }}</span>
</div>
<!-- <div class="px-2 bg-gradient-to-r from-[#ffa700] to-[#ff006b] text-[#814600] text-white rounded-[4px] ml-1 text-[12px">
已减¥11
</div> -->
</div>
<div class="flex items-center mb-1">
<img src="@/assets/img/alipay.png" class="mr-1"> 请扫码完成支付
</div>
<div class="text-[12px]">
<span class="text-[#999]">
开通即代表同意
</span>
<span class="text-[#814600]">
魔创未来会员协议
</span>
</div>
</div>
</div>
</div>
</n-modal>
</template>
<style lang="scss" scoped>
.member-item {
display: flex;
justify-content: center;
align-items: center;
width: 16.66%;
height: 40px;
border: 1px solid #f0f0f0;
font-size: 12px;
font-weight: 400;
margin-right: -1px;
margin-bottom: -1px;
}
</style>

View File

@ -190,11 +190,11 @@ onMounted(() => {});
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<NuxtLink to="/" class="text-xl font-semibold tracking-tight no-underline"> <NuxtLink to="/" class="text-xl font-semibold tracking-tight no-underline">
<!-- <img src="/vite.png" alt="Logo" class="h-9 w-9" /> --> <!-- <img src="/vite.png" alt="Logo" class="h-9 w-9" /> -->
<!-- 魔创未来 --> 魔创未来
<img <!-- <img
src="https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg" src="https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg"
alt="" alt=""
/> /> -->
<!-- <a class="Topbar_iconLogo__RhuYB" style="background-image: url(&quot;https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg&quot;);"></a> --> <!-- <a class="Topbar_iconLogo__RhuYB" style="background-image: url(&quot;https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg&quot;);"></a> -->
</NuxtLink> </NuxtLink>
<!-- <span class="text-xl font-semibold tracking-tight">魔创未来</span> --> <!-- <span class="text-xl font-semibold tracking-tight">魔创未来</span> -->

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next' import { RotateCcw, X } from 'lucide-vue-next';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue' import type { FormInst } from 'naive-ui';
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue';
const props = defineProps({ const props = defineProps({
isMember: { isMember: {
@ -85,19 +86,19 @@ async function getQrCode() {
const isVisible = ref(true) const isVisible = ref(true)
// //
const points = ref(0) // const points = ref(0)
async function getPoints() { // async function getPoints() {
try { // try {
const res = await request.get('/member/getPoints') // const res = await request.get('/member/getPoints')
if (res.code === 200) { // if (res.code === 200) {
points.value = res.data.points // points.value = res.data.points
} // }
} // }
catch (err) { // catch (err) {
console.log(err) // console.log(err)
} // }
} // }
getPoints() // getPoints()
// //
// const isMember = ref(false) // const isMember = ref(false)
@ -154,10 +155,10 @@ onBeforeUnmount(() => {
<component :is="X" class="h-[18px] w-[18px] text-[#61666d] cursor-pointer" /> <component :is="X" class="h-[18px] w-[18px] text-[#61666d] cursor-pointer" />
</div> </div>
</div> </div>
<div class="p-4"> <!-- <div class="p-4">
余额{{ points }}积分 余额{{ points }}积分
</div> </div> -->
<div class="mt-4 px-6 flex"> <div class="mb-4 mt-6 flex">
<n-form <n-form
ref="formRef" ref="formRef"
:label-width="80" :label-width="80"

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-wrap justify-center"> <div class="w-full">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-4 p-4"> <div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-4 p-4">
<div <div
v-for="item in dataList" v-for="item in dataList"
@ -42,7 +42,7 @@
<!-- 作者信息条 --> <!-- 作者信息条 -->
<div class="mt-1 px-2 py-1"> <div class="mt-1 px-2 py-1">
<div> <div>
<span class="text-[#19191c] text-[14px]"> <span class="text-[#19191c] text-[14px] max-w-xs truncate ">
{{ item.modelName }} {{ item.modelName }}
</span> </span>
</div> </div>
@ -52,13 +52,13 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="!loading && dataList.length === 0"> </div>
<Empty></Empty> <div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
</div> <Empty></Empty>
</div> </div>
<div <div
ref="loadingTrigger" ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center" class="h-20 w-full text-center text-gray-500 flex justify-center items-center"
> >
<div v-if="loading">...</div> <div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div> <div v-if="finished && dataList.length >= 20"></div>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { RotateCcw, X } from 'lucide-vue-next'; import { RotateCcw, X } from "lucide-vue-next";
import { useMessage } from 'naive-ui'; import { useMessage } from "naive-ui";
import { defineProps, onBeforeMount, onBeforeUnmount, ref } from 'vue'; import { defineProps, onBeforeMount, onBeforeUnmount, ref } from "vue";
const props = defineProps({ const props = defineProps({
info: { info: {
@ -12,139 +12,144 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
}) });
const emit = defineEmits(['closePayment', 'paymentSuccess']) const emit = defineEmits(["closePayment", "paymentSuccess"]);
const message = useMessage() const message = useMessage();
let pollingTimer: ReturnType<typeof setInterval> | undefined let pollingTimer: ReturnType<typeof setInterval> | undefined;
const currentNeedPayment = ref<number>(0) const currentNeedPayment = ref<number>(0);
// const isShowPayment = ref(false) // const isShowPayment = ref(false)
const userStore = useUserStore() const userStore = useUserStore();
interface UserInfoType { interface UserInfoType {
nickName: string nickName: string;
avatar: string avatar: string;
brief: string brief: string;
userId: number | string userId: number | string;
} }
const userInfo = { const userInfo = {
nickName: userStore.userInfo?.nickName ?? '', nickName: userStore.userInfo?.nickName ?? "",
avatar: userStore.userInfo?.avatar ?? '', avatar: userStore.userInfo?.avatar ?? "",
brief: userStore.userInfo?.brief ?? '', brief: userStore.userInfo?.brief ?? "",
userId: userStore.userInfo?.userId ?? '', userId: userStore.userInfo?.userId ?? "",
} as UserInfoType } as UserInfoType;
function onCloseModel() { function onCloseModel() {
emit('closePayment') emit("closePayment");
} }
function onPaymentSuccess() { function onPaymentSuccess() {
emit('paymentSuccess') emit("paymentSuccess");
} }
const qrUrl = ref('') const qrUrl = ref("");
interface Member { interface Member {
id: number id: number;
title: string title: string;
price: number price: number;
originalPrice: number originalPrice: number;
desc: string desc: string;
} }
// //
const currentActivity = ref(null) const currentActivity = ref(null);
const activityList = ref<Member[]>([]) const activityList = ref<Member[]>([]);
async function getPromotionList() { async function getPromotionList() {
try { try {
const res = await request.get(`/promotion/promotionList`) const res = await request.post(`/promotion/myPromotionList`, {
pageNum: 1,
pageSize: 50,
});
if (res.code === 200) { if (res.code === 200) {
activityList.value = res.data activityList.value = res.rows;
} }
} } catch (err) {
catch (err) { console.log(err);
console.log(err)
} }
} }
getPromotionList() getPromotionList();
// //
// //
// const paymentParams = ref({}) // const paymentParams = ref({})
const paymentStatus = ref(1) const paymentStatus = ref(1);
const paymentParams = ref({ const paymentParams = ref({
amount: props.info[0].unitPrice, amount: props.info[0].unitPrice,
productId: props.info[0].id, productId: props.info[0].id,
promotionId: 0, promotionId: 0,
type: 'member', type: "member",
}) });
async function getQrCode() { async function getQrCode() {
try { try {
const res = await request.post(`/ali/pay/doPay`, paymentParams.value) const res = await request.post(`/ali/pay/doPay`, paymentParams.value);
if (res.code === 200) { if (res.code === 200) {
paymentStatus.value = 1 paymentStatus.value = 1;
qrUrl.value = res.data.url qrUrl.value = res.data.url;
pollingTimer && clearTimeout(pollingTimer) pollingTimer && clearTimeout(pollingTimer);
pollingTimer = setInterval(async () => { pollingTimer = setInterval(async () => {
try { try {
const res2 = await request.get(`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`) const res2 = await request.get(
`/order/queryTradeStatus?outTradeNo=${res.data.orderNo}`
);
if (res2.data === 2) { if (res2.data === 2) {
paymentStatus.value = 2 paymentStatus.value = 2;
clearTimeout(pollingTimer) clearTimeout(pollingTimer);
message.success('支付成功!') message.success("支付成功!");
onPaymentSuccess() onPaymentSuccess();
emit('closePayment') emit("closePayment");
} } else if (res2.data === 4) {
else if (res2.data === 4) { paymentStatus.value = 4;
paymentStatus.value = 4 clearTimeout(pollingTimer);
clearTimeout(pollingTimer)
} }
} catch (err) {
console.log("object", err);
} }
catch (err) { }, 2000);
console.log('object', err)
}
}, 2000)
} }
} } catch (err) {
catch (err) { console.log(err);
console.log(err)
} }
} }
// //
async function handleActivityChange(value: number) { async function handleActivityChange(value: number) {
paymentParams.value.promotionId = value paymentParams.value.promotionId = value;
const res1 = await request.get(`/member/calculatePayment?promotionId=${value}&memberLevelId=${paymentParams.value.productId}`) const res1 = await request.get(
`/member/calculatePayment?promotionId=${value}&memberLevelId=${paymentParams.value.productId}`
);
if (res1.code === 200) { if (res1.code === 200) {
paymentParams.value.amount = res1.data paymentParams.value.amount = res1.data;
getQrCode() getQrCode();
} }
} }
// pay Card // pay Card
async function changeCurrentNeedPayment(index: number) { async function changeCurrentNeedPayment(index: number) {
currentNeedPayment.value = index currentNeedPayment.value = index;
paymentParams.value.productId = props.info[index].id paymentParams.value.productId = props.info[index].id;
const res1 = await request.get(`/member/calculatePayment?promotionId=${paymentParams.value.promotionId}&memberLevelId=${paymentParams.value.productId}`) const res1 = await request.get(
`/member/calculatePayment?promotionId=${paymentParams.value.promotionId}&memberLevelId=${paymentParams.value.productId}`
);
if (res1.code === 200) { if (res1.code === 200) {
paymentParams.value.amount = res1.data paymentParams.value.amount = res1.data;
getQrCode() getQrCode();
} }
} }
// //
const isVisible = ref(true) const isVisible = ref(true);
onBeforeMount (() => { onBeforeMount(() => {
getQrCode() getQrCode();
}) });
defineExpose({ defineExpose({
isVisible, isVisible,
}) });
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearInterval(pollingTimer) clearInterval(pollingTimer);
}) });
</script> </script>
<template> <template>
@ -161,14 +166,18 @@ onBeforeUnmount(() => {
> >
<div class="flex items-center"> <div class="flex items-center">
<div> <div>
<img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4"> <img :src="userInfo.avatar" class="w-14 h-14 rounded-full mr-4" />
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="text-[#814600] text-xl"> <div class="text-[#814600] text-xl">
{{ userInfo.nickName }} {{ userInfo.nickName }}
</div> </div>
<div class="text-[#6a6a6a] text-xs mt-1"> <div class="text-[#6a6a6a] text-xs mt-1">
{{ props.isMember.result === '1' ? `会员到期时间: ${props.isMember.endDate}` : '您还不是魔创未来的会员' }} {{
props.isMember.result === "1"
? `会员到期时间: ${props.isMember.endDate}`
: "您还不是魔创未来的会员"
}}
</div> </div>
</div> </div>
</div> </div>
@ -180,12 +189,14 @@ onBeforeUnmount(() => {
<div <div
v-for="(item, index) in info" v-for="(item, index) in info"
:key="item" :key="item"
:style="[currentNeedPayment === index :style="[
? { currentNeedPayment === index
background: 'linear-gradient(90deg, #fffaf1, #ffeccf)', ? {
border: '1px solid #f7b252', background: 'linear-gradient(90deg, #fffaf1, #ffeccf)',
} border: '1px solid #f7b252',
: {}]" }
: {},
]"
class="select-none h-44 border-1 border-solid border-[#e9e9e9] rounded-lg bg-[#f9f9f9] flex justify-between items-center flex-col p-4 box-border cursor-pointer" class="select-none h-44 border-1 border-solid border-[#e9e9e9] rounded-lg bg-[#f9f9f9] flex justify-between items-center flex-col p-4 box-border cursor-pointer"
@click="changeCurrentNeedPayment(index)" @click="changeCurrentNeedPayment(index)"
> >
@ -197,7 +208,9 @@ onBeforeUnmount(() => {
<div class="card-item"> <div class="card-item">
<span class="text-[#814600] text-[20px] mr-2">¥</span> <span class="text-[#814600] text-[20px] mr-2">¥</span>
<span class="text-[#814600] text-[36px] mr-2">{{ item.unitPrice }}</span> <span class="text-[#814600] text-[36px] mr-2">{{ item.unitPrice }}</span>
<span class="text-gray-400 text-[20px] line-through">{{ item.originalPrice }}</span> <span class="text-gray-400 text-[20px] line-through">{{
item.originalPrice
}}</span>
</div> </div>
<div class="card-item text-[#814600] w-7/10 text-center text-[12px]"> <div class="card-item text-[#814600] w-7/10 text-center text-[12px]">
{{ item.subscriptionPeriod }} {{ item.subscriptionPeriod }}
@ -205,57 +218,36 @@ onBeforeUnmount(() => {
</div> </div>
</div> </div>
<div class="flex items-center my-4"> <div class="flex items-center my-4">
<div class="w-[50px] text-right mr-2"> <div class="w-[50px] text-right mr-2">活动:</div>
活动:
</div>
<n-select <n-select
v-model:value="currentActivity" v-model:value="currentActivity"
placeholder="请选择活动" class="w-[200px]" label-field="activityName" value-field="id" :options="activityList" @change="handleActivityChange" placeholder="请选择活动"
class="w-[200px]"
label-field="activityName"
value-field="id"
:options="activityList"
@change="handleActivityChange"
/> />
</div> </div>
<!-- <div v-for="(item, index) in activityList" :key="index"> <!-- <div v-for="(item, index) in activityList" :key="index">
{{ item.activityName }} {{ item.activityName }}
</div> --> </div> -->
<div class="mt-4 px-6"> <div class="mt-4 px-6">
<div class="flex border-collapse "> <div class="flex border-collapse">
<div class="member-item bg-[#fef9f8]"> <div class="member-item bg-[#fef9f8]">基础版VIP</div>
基础版VIP <div class="member-item">每月15000点算力</div>
</div> <div class="member-item">20G存储空间</div>
<div class="member-item"> <div class="member-item">每月800次生图</div>
每月15000点算力 <div class="member-item">2个生图任务并行</div>
</div> <div class="member-item">--</div>
<div class="member-item">
20G存储空间
</div>
<div class="member-item">
每月800次生图
</div>
<div class="member-item">
2个生图任务并行
</div>
<div class="member-item">
--
</div>
</div> </div>
<div class="flex border-collapse "> <div class="flex border-collapse">
<div class="member-item bg-[#fef9f8]"> <div class="member-item bg-[#fef9f8]">专业版</div>
专业版 <div class="member-item">每月35000点算力</div>
</div> <div class="member-item">50G存储空间</div>
<div class="member-item"> <div class="member-item">每月5000次生图</div>
每月35000点算力 <div class="member-item">3个生图任务并行</div>
</div> <div class="member-item">可训练XL模型</div>
<div class="member-item">
50G存储空间
</div>
<div class="member-item">
每月5000次生图
</div>
<div class="member-item">
3个生图任务并行
</div>
<div class="member-item">
可训练XL模型
</div>
</div> </div>
</div> </div>
<div class="px-6 mt-1 text-[#9d8c75] text-[12px]"> <div class="px-6 mt-1 text-[#9d8c75] text-[12px]">
@ -263,16 +255,18 @@ onBeforeUnmount(() => {
</div> </div>
<div class="flex justify-center items-center my-4"> <div class="flex justify-center items-center my-4">
<div class="w-30 h-30 flex justify-center items-center relative"> <div class="w-30 h-30 flex justify-center items-center relative">
<n-qr-code :value="qrUrl" :size="90" style="padding: 0;" /> <n-qr-code :value="qrUrl" :size="90" style="padding: 0" />
<div v-if="paymentStatus === 4" class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white" @click="getQrCode"> <div
v-if="paymentStatus === 4"
class="absolute top-0 left-0 w-full h-full flex cursor-pointer flex-col justify-center items-center bg-opacity-50 bg-black text-white"
@click="getQrCode"
>
请点击刷新<RotateCcw /> 请点击刷新<RotateCcw />
</div> </div>
</div> </div>
<div class="flex justify-center ml-2 flex-col pb-[14px]"> <div class="flex justify-center ml-2 flex-col pb-[14px]">
<div class="flex items-baseline"> <div class="flex items-baseline">
<div class="text-[#222] font-medium mr-1"> <div class="text-[#222] font-medium mr-1">支付</div>
支付
</div>
<div class="text-[#814600] mr-1"> <div class="text-[#814600] mr-1">
<span class="text-[16px] mr-1">¥</span> <span class="text-[16px] mr-1">¥</span>
<span class="text-[40px]">{{ paymentParams.amount }}</span> <span class="text-[40px]">{{ paymentParams.amount }}</span>
@ -282,15 +276,11 @@ onBeforeUnmount(() => {
</div> --> </div> -->
</div> </div>
<div class="flex items-center mb-1"> <div class="flex items-center mb-1">
<img src="@/assets/img/alipay.png" class="mr-1"> 请扫码完成支付 <img src="@/assets/img/alipay.png" class="mr-1" /> 请扫码完成支付
</div> </div>
<div class="text-[12px]"> <div class="text-[12px]">
<span class="text-[#999]"> <span class="text-[#999]"> 开通即代表同意 </span>
开通即代表同意 <span class="text-[#814600]"> 魔创未来会员协议 </span>
</span>
<span class="text-[#814600]">
魔创未来会员协议
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -8,6 +8,7 @@ Play
import { NConfigProvider, NMessageProvider } from "naive-ui"; import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, ref } from 'vue'; import { nextTick, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const message = useMessage()
const props = defineProps({ const props = defineProps({
item: { item: {
@ -28,15 +29,22 @@ const props = defineProps({
const emit = defineEmits(['topedRefresh']) const emit = defineEmits(['topedRefresh'])
const router = useRouter() const router = useRouter()
const isDelete = ref(false)
// //
function toDetails() { function toDetails() {
if (props.currentType === '0') { if (props.currentType === '0') {
router.push(`/model-details/${props.item.id}`) if(props.currentState === 'mallProduct'){
router.push(`/model-details/${props.item.id}`)
}else{
router.push(`/model-details/${props.item.modelId}`)
}
} }
else if (props.currentType === '1') { else if (props.currentType === '1') {
// console.log('object', 111); if(props.currentState === 'mallProduct'){
router.push(`/workflow-details/${props.item.id}`) router.push(`/workflow-details/${props.item.id}`)
}else{
router.push(`/workflow-details/${props.item.workFlowId}`)
}
}else if(props.currentType === '2'){ }else if(props.currentType === '2'){
onEditPicture() onEditPicture()
} }
@ -94,6 +102,7 @@ function handleSelect(event: Event, key: string) {
} }
// //
const menuRef = ref(null)
interface TopUrlType { interface TopUrlType {
[key: string | number]: string [key: string | number]: string
} }
@ -109,6 +118,8 @@ async function handleTop() {
.isTop}`, .isTop}`,
) )
if (res.code === 200) { if (res.code === 200) {
message.success('置顶成功!')
menuRef.value.style.display = 'none';
// //
emit('topedRefresh') emit('topedRefresh')
} }
@ -122,7 +133,11 @@ interface Response {
code: number code: number
} }
//
async function handleDelete(): Promise<void> { async function handleDelete(): Promise<void> {
isDelete.value = true
}
async function onDelete(){
const { currentType, item } = props const { currentType, item } = props
let url: string let url: string
@ -142,6 +157,7 @@ async function handleDelete(): Promise<void> {
const res: Response = await request.get(url) const res: Response = await request.get(url)
if (res.code === 200) { if (res.code === 200) {
// //
message.success('删除成功!')
emit('topedRefresh') emit('topedRefresh')
} }
} }
@ -200,7 +216,12 @@ function updateLike(type:number){
props.item.likeNum += 1; props.item.likeNum += 1;
} }
} }
function showMenu(){
menuRef.value.style.display = 'block';
}
function hiddenMenu(){
menuRef.value.style.display = 'none';
}
</script> </script>
<template> <template>
@ -285,10 +306,13 @@ function updateLike(type:number){
> >
<div class="menu-content"> <div class="menu-content">
<component <component
@mouseenter="showMenu"
:is="EllipsisVertical" :is="EllipsisVertical"
class="h-[18px] w-[18px] text-white menu-icon" class="h-[18px] w-[18px] text-white menu-icon-ellipsis"
/> />
<div <div
@mouseleave="hiddenMenu"
ref="menuRef"
class="menu-group text-[#000000] text-[12px] bg-white rounded-lg text-center w-20 mt-2 hidden" class="menu-group text-[#000000] text-[12px] bg-white rounded-lg text-center w-20 mt-2 hidden"
> >
<div class="menu-item" @click="(event) => handleSelect(event, 'edit')"> <div class="menu-item" @click="(event) => handleSelect(event, 'edit')">
@ -335,7 +359,7 @@ function updateLike(type:number){
</div> </div>
</div> </div>
<div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]"> <div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]">
<div class="text-[#19191c] text-[14px]"> <div class="text-[#19191c] text-[14px] max-w-xs truncate ">
<span v-if="currentType === '0'"> <span v-if="currentType === '0'">
{{ item.modelName }} {{ item.modelName }}
</span> </span>
@ -363,10 +387,24 @@ function updateLike(type:number){
<Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" /> <Publish-picture v-if="isShowPublishPicture" type="edit" ref="PublishPictureRef" :form-data="publishPictureData" @close-publish-img="closePublishImg" />
</NMessageProvider> </NMessageProvider>
</NConfigProvider> </NConfigProvider>
<n-modal
v-model:show="isDelete"
:mask-closable="false"
preset="dialog"
title="提示!"
content="确定要将模型删除? 模型删除后无法找回"
negative-text="取消"
positive-text="确认"
@negative-click="isDelete = false"
@positive-click="onDelete"
/>
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
.menu-icon-ellipsis:hover + .menu-group{
display: block;
}
.modelSelectByUserIdModel { .modelSelectByUserIdModel {
position: absolute; position: absolute;
&:hover { &:hover {

View File

@ -17,8 +17,10 @@ const props = defineProps({
const dataInfo = ref({}); const dataInfo = ref({});
const isAttention = ref(false) const isAttention = ref(false)
async function getDetail() { async function getDetail() {
if (props.item && props.item.id) { if (props.item) {
const res = await request.get(`/image/detail?id=${props.item.id}`); // 使modelImageId 使id
let id = props.item.modelImageId || props.item.id
const res = await request.get(`/image/detail?id=${id}`);
if (res.code === 200) { if (res.code === 200) {
dataInfo.value = res.data; dataInfo.value = res.data;
const res1 = await request.get(`/attention/selectAttention?userId=${res.data.userId}`) const res1 = await request.get(`/attention/selectAttention?userId=${res.data.userId}`)
@ -30,8 +32,8 @@ async function getDetail() {
} }
} }
getDetail(); getDetail();
const tagsList = ref([]);
// //
const tagsList = ref([]);
async function getDictType() { async function getDictType() {
try { try {
const res = await commonApi.dictType({ type: "image_label" }); const res = await commonApi.dictType({ type: "image_label" });

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap w-full">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4"> <div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4">
<div <div
v-for="item in dataList" v-for="item in dataList"
@ -74,13 +74,14 @@
</div> </div>
</div> --> </div> -->
</div> </div>
<div v-if="!loading && dataList.length === 0">
</div>
<div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
<Empty></Empty> <Empty></Empty>
</div> </div>
</div>
<div <div
ref="loadingTrigger" ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center" class="h-20 w-full text-center text-gray-500 flex justify-center items-center"
> >
<div v-if="loading">...</div> <div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div> <div v-if="finished && dataList.length >= 20"></div>

View File

@ -14,9 +14,9 @@ const props = defineProps({
default: "", default: "",
} }
}) })
debugger
const emit = defineEmits(['closePublishImg']) const emit = defineEmits(['closePublishImg'])
const message = useMessage() const message = useMessage()
const loading = ref(false)
const isVisible = ref(true) const isVisible = ref(true)
const fileInput = ref<HTMLInputElement | null>(null) const fileInput = ref<HTMLInputElement | null>(null)
@ -38,11 +38,14 @@ async function handleFileChange(event: Event) {
if (files && files.length > 0) { if (files && files.length > 0) {
try{ try{
loading.value = true
const res = await uploadImagesInBatches(files) const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url) const urlList = res.map(item => item.url)
props.formData.imagePaths.push(...urlList) props.formData.imagePaths.push(...urlList)
}catch(err){ }catch(err){
console.log(err); console.log(err);
}finally{
loading.value = false
} }
} }
target.value = '' target.value = ''
@ -63,6 +66,7 @@ async function getDictType() {
async function onPublish() { async function onPublish() {
try { try {
const param = cloneDeep(props.formData) const param = cloneDeep(props.formData)
if(param.imagePaths.length === 0) return message.warning('请上传图片')
param.imagePaths = param.imagePaths.join(',') param.imagePaths = param.imagePaths.join(',')
param.tags = param.tags.join(',') param.tags = param.tags.join(',')
if (param.id) { if (param.id) {
@ -114,6 +118,8 @@ function closePublishImg() {
</div> </div>
</div> </div>
<div> <div>
<n-spin :show="loading">
<div class="upload-content"> <div class="upload-content">
<div class="flex flex-col bg-[#f3f5f9] justify-center items-center w-30 h-30 border border-dashed mt-2 rounded-lg bg-white"> <div class="flex flex-col bg-[#f3f5f9] justify-center items-center w-30 h-30 border border-dashed mt-2 rounded-lg bg-white">
<div class="my-6 w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center mt-6" @click="triggerFileInput()"> <div class="my-6 w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center mt-6" @click="triggerFileInput()">
@ -124,6 +130,8 @@ function closePublishImg() {
</div> --> </div> -->
</div> </div>
</div> </div>
</n-spin>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full"> <div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(item, index) in props.formData.imagePaths" :key="index"> <div v-for="(item, index) in props.formData.imagePaths" :key="index">
<img class="w-full h-[180px] object-cover rounded-lg" :src="item" alt=""> <img class="w-full h-[180px] object-cover rounded-lg" :src="item" alt="">

View File

@ -31,9 +31,9 @@ async function onGetUUid() {
// /wx/uuid/get // /wx/uuid/get
const res = await request.get('/wx/uuid/get') const res = await request.get('/wx/uuid/get')
if (res.code === 200) { if (res.code === 200) {
const appid = 'wx7d0003f44e27fbfd' const appid = 'wx0a72f196ec9c3a70'
const { uuid } = res const { uuid } = res
const redirect_uri = `http://a7u3z9.natappfree.cc/wx/uuid/bind/openid?uuid=${uuid}` const redirect_uri = `http://www.mc158c.com/api/wx/uuid/bind/openid?uuid=${uuid}`
const codeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent( const codeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(
redirect_uri, redirect_uri,
)}&response_type=code&scope=snsapi_userinfo&state=123456#wechat_redirect` )}&response_type=code&scope=snsapi_userinfo&state=123456#wechat_redirect`

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap w-full">
<div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4"> <div class="grid grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-7 gap-4 p-4">
<div <div
v-for="item in dataList" v-for="item in dataList"
@ -42,7 +42,7 @@
<!-- 作者信息条 --> <!-- 作者信息条 -->
<div class="mt-1 px-2 py-1"> <div class="mt-1 px-2 py-1">
<div> <div>
<span class="text-[#19191c] text-[14px]"> <span class="text-[#19191c] text-[14px] max-w-xs truncate ">
{{ item.workflowName }} {{ item.workflowName }}
</span> </span>
</div> </div>
@ -52,13 +52,13 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="!loading && dataList.length === 0"> </div>
<Empty></Empty> <div class="w-full flex justify-center" v-if="!loading && dataList.length === 0">
</div> <Empty></Empty>
</div> </div>
<div <div
ref="loadingTrigger" ref="loadingTrigger"
class="h-20 w-[1000px] text-center text-gray-500 flex justify-center items-center" class="h-20 w-full text-gray-500 flex justify-center items-center"
> >
<div v-if="loading">...</div> <div v-if="loading">...</div>
<div v-if="finished && dataList.length >= 20"></div> <div v-if="finished && dataList.length >= 20"></div>

View File

@ -31,7 +31,6 @@ const props = defineProps({
async function toDetail(item:any){ async function toDetail(item:any){
// try{ // try{
// const res = await request.get(`/advice/read?adviceId=${item.id}`) // const res = await request.get(`/advice/read?adviceId=${item.id}`)
// debugger
// }catch(err){ // }catch(err){
// console.log(err); // console.log(err);

View File

@ -128,8 +128,17 @@ function handleCategoryUpdateValue(value) {
// localForm.value.modelProduct.category = value.includes('-') ? value : `${value}-0` // localForm.value.modelProduct.category = value.includes('-') ? value : `${value}-0`
// } // }
} }
const isPublicList = [
{
label: "公开",
value: 1,
},
{
label: "仅自己可见",
value: 0,
},
];
// function changeModelType(item){ // function changeModelType(item){
// debugger
// } // }
</script> </script>
@ -244,6 +253,24 @@ function handleCategoryUpdateValue(value) {
{{ item.label }} {{ item.label }}
</div> </div>
</div> </div>
<div class="">权限设置</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">可见范围</div>
<div>
<n-radio-group v-model:value="localForm.modelProduct.jurisdiction" name="radiogroup">
<n-space>
<n-radio
v-for="(isPublicItem, isPublicIndex) in isPublicList"
:key="isPublicIndex"
:value="isPublicItem.value"
>
{{ isPublicItem.label }}
</n-radio>
</n-space>
</n-radio-group>
</div>
<div v-if="localForm.modelProduct.isOriginal === 1" class="text-[12px]"> <div v-if="localForm.modelProduct.isOriginal === 1" class="text-[12px]">
<div class="my-3"> <div class="my-3">
魔创未来原创模型加密保护计划 魔创未来原创模型加密保护计划

View File

@ -19,7 +19,7 @@ const emit = defineEmits(["update:modelValue", "nextStep", "prevStep"]);
const acceptTypes = const acceptTypes =
".safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft"; ".safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft";
const modelVersionItem = { const modelVersionItem = {
objectKey:null, objectKey: null,
isEncrypt: 0, //0 isEncrypt: 0, //0
delFlag: "0", // 0 2 delFlag: "0", // 0 2
versionName: "", // versionName: "", //
@ -29,7 +29,7 @@ const modelVersionItem = {
fileName: "", // fileName: "", //
sampleImagePaths: [], // 20, sampleImagePaths: [], // 20,
triggerWords: "", // triggerWords: "", //
isPublic: 1, // isPublic: null, //
isOnlineUse: 1, //线使 isOnlineUse: 1, //线使
allowFusion: 1, // allowFusion: 1, //
isFree: 0, // 0 isFree: 0, // 0
@ -41,20 +41,11 @@ const modelVersionItem = {
hideImageGenInfo: 0, // hideImageGenInfo: 0, //
id: null, id: null,
}; };
const isPublicList = [
{
label: "公开",
value: 1,
},
{
label: "仅自己可见",
value: 0,
},
];
defineExpose({ defineExpose({
addVersion, addVersion,
}); });
const loading = ref(false);
const localForm = computed({ const localForm = computed({
get() { get() {
return props.modelValue; return props.modelValue;
@ -147,20 +138,25 @@ async function handleFileChange(event: Event) {
const files = target.files; const files = target.files;
if (files && files.length > 0) { if (files && files.length > 0) {
const { name, size} = files[0] as { name: string, size: number}; const { name, size } = files[0] as { name: string; size: number };
try { try {
// 0 1 // 0 1
const res1 = await request.get(`/file/selectFile?type=model&name=${name}`); const res1 = await request.get(`/file/selectFile?type=model&name=${name}`);
if (res1.code == 200) { if (res1.code == 200) {
if (res1.data === 1) { if (res1.data === 1) {
try { try {
loading.value = true;
const res = await uploadFileBatches(files); const res = await uploadFileBatches(files);
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].path; localForm.value.modelVersionList[uploadFileIndex.value].filePath =
localForm.value.modelVersionList[uploadFileIndex.value].objectKey = res[0].objectKey; res[0].path;
localForm.value.modelVersionList[uploadFileIndex.value].objectKey =
res[0].objectKey;
localForm.value.modelVersionList[uploadFileIndex.value].fileName = name; localForm.value.modelVersionList[uploadFileIndex.value].fileName = name;
localForm.value.modelVersionList[uploadFileIndex.value].fileSize = size localForm.value.modelVersionList[uploadFileIndex.value].fileSize = size;
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} finally {
loading.value = false;
} }
} else { } else {
message.warning("该模型名称已存在"); message.warning("该模型名称已存在");
@ -262,22 +258,24 @@ function onDelete(index: number) {
</div> </div>
</div> </div>
<div v-else> <div v-else>
<div class="upload-content"> <n-spin :show="loading">
<div <div class="upload-content">
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
<div <div
class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
@click="triggerFileInput(index)"
> >
上传文件 <div
</div> class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center"
<div class="my-3">点击上传文件</div> @click="triggerFileInput(index)"
<div class="text-[#999999] text-xs"> >
.safetensors/.ckpt/.pt/.bin/.pth/.zip/.json/.flow/.lightflow/.yaml/.yml/.onnx/.gguf/.sft 上传文件
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">
.safetensors/.ckpt/.pt/.bin/.pth/.zip/.json/.flow/.lightflow/.yaml/.yml/.onnx/.gguf/.sft
</div>
</div> </div>
</div> </div>
</div> </n-spin>
</div> </div>
<div class="flex mt-6"> <div class="flex mt-6">
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" /> 版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
@ -308,21 +306,7 @@ function onDelete(index: number) {
</div> </div>
</div> --> </div> -->
<div class="">权限设置</div>
<div class="mt-1 mb-2 text-gray-400 text-[12px]">可见范围</div>
<div>
<n-radio-group v-model:value="item.isPublic" name="radiogroup">
<n-space>
<n-radio
v-for="(isPublicItem, isPublicIndex) in isPublicList"
:key="isPublicIndex"
:value="isPublicItem.value"
>
{{ isPublicItem.label }}
</n-radio>
</n-space>
</n-radio-group>
</div>
</n-form> </n-form>
<div v-if="item.isPublic === 1"> <div v-if="item.isPublic === 1">
<div class="mt-4 mb-1 text-gray-400 text-[12px]">付费设置</div> <div class="mt-4 mb-1 text-gray-400 text-[12px]">付费设置</div>

View File

@ -17,6 +17,7 @@ const route = useRoute()
const { type } = route.query const { type } = route.query
const message = useMessage() const message = useMessage()
const loading = ref(false)
const localForm = computed({ const localForm = computed({
get() { get() {
@ -103,11 +104,14 @@ async function handleFileChange(event: Event) {
if (sum >= 20) if (sum >= 20)
return message.error('最多20张') return message.error('最多20张')
try{ try{
loading.value = true
const res = await uploadImagesInBatches(files) const res = await uploadImagesInBatches(files)
const urlList = res.map(item => item.url) const urlList = res.map(item => item.url)
localForm.value.modelVersionList[uploadFileIndex.value].sampleImagePaths.push(...urlList) localForm.value.modelVersionList[uploadFileIndex.value].sampleImagePaths.push(...urlList)
}catch(err){ }catch(err){
console.log(err); console.log(err);
}finally{
loading.value = false
} }
} }
target.value = '' target.value = ''
@ -145,6 +149,7 @@ function onPositiveClick() {
最多20张图片, 图片不超过30M 最多20张图片, 图片不超过30M
</div> </div>
</div> </div>
<n-spin :show="loading">
<div> <div>
<div class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"> <div class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white">
<div class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" @click="triggerFileInput(index)"> <div class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" @click="triggerFileInput(index)">
@ -158,6 +163,8 @@ function onPositiveClick() {
</div> </div>
</div> </div>
</div> </div>
</n-spin>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full"> <div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.sampleImagePaths" :key="subIndex"> <div v-for="(subItem, subIndex) in item.sampleImagePaths" :key="subIndex">
<img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt=""> <img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt="">

View File

@ -13,7 +13,7 @@ const props = defineProps({
}, },
}); });
const emit = defineEmits(["update:modelValue", "nextStep", "preStep"]); const emit = defineEmits(["update:modelValue", "nextStep", "preStep"]);
const loading = ref(false)
const localForm = computed({ const localForm = computed({
get() { get() {
return props.modelValue; return props.modelValue;
@ -25,7 +25,7 @@ const localForm = computed({
watch( watch(
() => localForm.value, () => localForm.value,
(newVal:any) => { (newVal: any) => {
console.log("newVal", newVal); console.log("newVal", newVal);
emit("update:modelValue", newVal); emit("update:modelValue", newVal);
}, },
@ -84,8 +84,8 @@ async function nextStep() {
} }
try { try {
const promises = formRefs.value const promises = formRefs.value
.filter((form:any): form is FormInst => form !== null) .filter((form: any): form is FormInst => form !== null)
.map((form:any) => form.validate()); .map((form: any) => form.validate());
await Promise.all(promises); await Promise.all(promises);
emit("nextStep"); emit("nextStep");
@ -116,20 +116,25 @@ async function handleFileChange(event: Event) {
const files = target.files; const files = target.files;
if (files && files.length > 0) { if (files && files.length > 0) {
const { name , size} = files[0] as { name: string, size: number}; const { name, size } = files[0] as { name: string; size: number };
try { try {
const res1 = await request.get(`/file/selectFile?type=workflow&name=${name}`); const res1 = await request.get(`/file/selectFile?type=workflow&name=${name}`);
if (res1.code == 200) { if (res1.code == 200) {
if (res1.data === 1) { if (res1.data === 1) {
//0 1 //0 1
try { try {
loading.value = true
const res = await uploadFileBatches(files); const res = await uploadFileBatches(files);
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].path; localForm.value.workFlowVersionList[uploadFileIndex.value].filePath =
localForm.value.workFlowVersionList[uploadFileIndex.value].objectKey = res[0].objectKey; res[0].path;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = name localForm.value.workFlowVersionList[uploadFileIndex.value].objectKey =
localForm.value.workFlowVersionList[uploadFileIndex.value].fileSize = size res[0].objectKey;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = name;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileSize = size;
} catch (err) { } catch (err) {
console.log(err); console.log(err);
}finally{
loading.value = false
} }
} else { } else {
message.error("该工作流名称已存在"); message.error("该工作流名称已存在");
@ -143,7 +148,7 @@ async function handleFileChange(event: Event) {
} }
function computedDelFlag() { function computedDelFlag() {
return localForm.value.workFlowVersionList.filter((item:any) => item.delFlag === "0"); return localForm.value.workFlowVersionList.filter((item: any) => item.delFlag === "0");
} }
function onDelete(index: number) { function onDelete(index: number) {
if (computedDelFlag().length === 1) return; if (computedDelFlag().length === 1) return;
@ -203,20 +208,22 @@ function onDelete(index: number) {
</div> </div>
</div> </div>
<div v-else> <div v-else>
<div class="upload-content"> <n-spin :show="loading">
<div <div class="upload-content">
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
>
<div <div
class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center" class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
@click="triggerFileInput(index)"
> >
上传文件 <div
class="w-24 bg-gradient-to-r from-[#2D28FF] to-[#1A7DFF] h-8 text-white rounded-sm bg-[#3162ff] cursor-pointer flex justify-center items-center"
@click="triggerFileInput(index)"
>
上传文件
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">.json/.zip</div>
</div> </div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">.json/.zip</div>
</div> </div>
</div> </n-spin>
</div> </div>
</n-form> </n-form>
</div> </div>

View File

@ -30,7 +30,7 @@ function preStep() {
emit("preStep"); emit("preStep");
} }
const showSuccessModal = ref(false); const showSuccessModal = ref(false);
const loading = ref(false)
async function handlePublish() { async function handlePublish() {
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) { for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
if ( if (
@ -107,6 +107,7 @@ async function handleFileChange(event: Event) {
files.length; files.length;
if (sum >= 20) return message.error("最多20张"); if (sum >= 20) return message.error("最多20张");
try { try {
loading.value = true
const res = await uploadImagesInBatches(files); const res = await uploadImagesInBatches(files);
const urlList = res.map((item) => item.url); const urlList = res.map((item) => item.url);
localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push( localForm.value.workFlowVersionList[uploadFileIndex.value].imagePaths.push(
@ -114,6 +115,8 @@ async function handleFileChange(event: Event) {
); );
} catch (err) { } catch (err) {
console.log(err); console.log(err);
}finally{
loading.value = false
} }
} }
target.value = ""; target.value = "";
@ -151,6 +154,7 @@ function onPositiveClick() {
<div class="text-[12px] text-gray-400">最多20张图片图片不超过30M</div> <div class="text-[12px] text-gray-400">最多20张图片图片不超过30M</div>
</div> </div>
<div> <div>
<n-spin :show="loading">
<div <div
class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white" class="flex flex-col justify-center items-center w-30 h-40 border border-dashed mt-2 rounded-lg bg-white"
> >
@ -165,6 +169,8 @@ function onPositiveClick() {
请勿上传裸露暴力血腥或其他包含非法信息图片 请勿上传裸露暴力血腥或其他包含非法信息图片
</div> </div>
</div> </div>
</n-spin>
</div> </div>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full"> <div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.imagePaths" :key="subIndex"> <div v-for="(subItem, subIndex) in item.imagePaths" :key="subIndex">

View File

@ -1,8 +1,8 @@
export const appName = '魔创未来' export const appName = '魔创未来'
export const appDescription = '魔创未来' export const appDescription = '魔创未来'
export const authRoutes = ['/personal-center', '/publish-model', '/publish-workflow'] export const authRoutes = ['/personal-center']
export const verifyBlankRoute = ['/member-center', '/int-detail', '/personal-publish'] export const verifyBlankRoute = ['/member-center']
export const isOriginalList = [{ export const isOriginalList = [{
label: '原创', label: '原创',
value: 0, value: 0,

View File

@ -2,14 +2,27 @@
import { import {
Binary, Binary,
Code2, Code2,
Crown, Earth, Image, Crown,
Earth,
Image,
LayoutGrid, LayoutGrid,
Lightbulb, Lightbulb,
Maximize, Network, User, Maximize,
Network,
User,
Workflow Workflow
} from "lucide-vue-next"; } from "lucide-vue-next";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
const userStore = useUserStore(); const userStore = useUserStore();
// definePageMeta({
// middleware:[
// function (to, from ){
// if(to.path === "/personal-center" && !userStore.isLoggedIn){
// return abortNavigation()
// }
// }
// ]
// })
const modalStore = useModalStore(); const modalStore = useModalStore();
const menuStore = useMenuStore(); const menuStore = useMenuStore();
@ -66,7 +79,7 @@ const menuItems2 = ref({
icon: Network, icon: Network,
text: "在线工作流", text: "在线工作流",
route: "", route: "",
desc:'Comfy UI' desc: "Comfy UI",
}, },
{ {
icon: Earth, icon: Earth,
@ -92,7 +105,7 @@ const menuItems3 = ref({
}); });
// //
menuStore.menuItems = menuStore.menuItems.map((item:any) => ({ menuStore.menuItems = menuStore.menuItems.map((item: any) => ({
...item, ...item,
LucideIcon: iconMap[item.path], // Lucide LucideIcon: iconMap[item.path], // Lucide
})); }));
@ -109,27 +122,45 @@ function handleSide(event: Event, path: string) {
} }
// //
// nextTick(() => { // nextTick(() => {
// debugger
// if (route.path !== window.location.pathname) { // if (route.path !== window.location.pathname) {
// navigateTo(route.path, { replace: true }) // navigateTo(route.path, { replace: true })
// } // }
// }) // })
} else if (path === "/personal-center" && !userStore.isLoggedIn) {
modalStore.showLoginModal();
} else { } else {
menuStore.setActiveMenu(path); menuStore.setActiveMenu(path);
} }
} }
const appList = ref([]);
async function getAppList() {
try {
const res = await request.get(`/app/list`);
if (res.code === 200) {
appList.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getAppList();
function toUs(url: string) {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/us/${url}`, "_blank", "noopener,noreferrer");
}
</script> </script>
<template> <template>
<div class="flex h-screen flex-col bg-white dark:bg-dark-800"> <div class="flex h-screen flex-col bg-white dark:bg-dark-800">
<!-- Header --> <!-- Header -->
<Header /> <Header />
<!-- Main Content --> <!-- Main Content -->
<div class="flex flex-1 overflow-hidden"> <div class="flex flex-1 overflow-hidden">
<!-- Sidebar --> <!-- Sidebar -->
<nav <nav
class="w-[220px] border-r border-gray-100 bg-gray-50/50 dark:border-dark-700 dark:bg-dark-800/50" class="w-[230px] border-r border-gray-100 bg-gray-50/50 dark:border-dark-700 dark:bg-dark-800/50 overflow-y-auto"
> >
<div class="space-y-1 px-2"> <div class="space-y-1 px-2">
<div class="text-[#000] p-4"> <div class="text-[#000] p-4">
@ -183,12 +214,11 @@ function handleSide(event: Event, path: string) {
target="_blank" target="_blank"
@click="(event: Event) => handleSide(event, item.route)" @click="(event: Event) => handleSide(event, item.route)"
> >
<div class="cursor-pointer mb-3 flex flex-col justify-center py-3 px-2 w-full block hover:bg-gray-100 border-[#ccc] rounded-lg border-dashed border"> <div
class="cursor-pointer mb-3 flex flex-col justify-center py-3 px-2 w-full block hover:bg-gray-100 border-[#ccc] rounded-lg border-dashed border"
>
<div class="flex items-center"> <div class="flex items-center">
<component <component :is="item.icon" class="h-[18px] w-[18px] mr-[10px]" />
:is="item.icon"
class="h-[18px] w-[18px] mr-[10px]"
/>
<div class="text-sm"> <div class="text-sm">
{{ item.text }} {{ item.text }}
</div> </div>
@ -237,6 +267,41 @@ function handleSide(event: Event, path: string) {
</NuxtLink> </NuxtLink>
</div> </div>
</div> </div>
<div class="px-4">
<div class="text-xs text-gray-500 flex flex-wrap gap-2">
<div
class="cursor-pointer relative group"
v-for="(item, index) in appList"
:key="index"
>
{{ item.name }}
<div
class="flex flex-col justify-center items-center gap-2 absolute bottom-4 left-0 w-[90px] h-[115px] hidden group-hover:block bg-white p-2 z-index-999 border border-solid border-[#ccc] rounded-lg"
>
<div class="text-xs text-center mb-2">扫码关注</div>
<img class="w-[80px] h-[70px]" :src="item.url" alt="" />
</div>
</div>
</div>
<div class="flex justify-between text-xs text-gray-400 mt-2">
<div class="cursor-pointer" @click="toUs('agreement')"></div>
<div class="cursor-pointer" @click="toUs('privacy')"></div>
<div class="cursor-pointer" @click="toUs('aboutUs')"></div>
</div>
<!-- <div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">广州魔创未来科技有限公司</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">京ICP备2023015442号</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">网信算备</div>
<div class="cursor-pointer scale-80">110112129623601230015</div>
</div>
<div class="justify-between text-xs text-gray-400 mt-2 scale-80">
<div class="cursor-pointer scale-80">备案号: Beijing-PianYu-202402</div>
</div> -->
</div>
<!-- <NuxtLink <!-- <NuxtLink
v-for="item in menuStore.menuItems" v-for="item in menuStore.menuItems"
:key="item.path" :key="item.path"
@ -282,6 +347,7 @@ function handleSide(event: Event, path: string) {
/* cursor: pointer; */ /* cursor: pointer; */
background: var(--primary); background: var(--primary);
color: white; color: white;
/* position: absolute; */
/* border: dashed; */ /* border: dashed; */
} }

View File

@ -1,5 +1,6 @@
// middleware/auth.ts // middleware/auth.ts
import { authRoutes, verifyBlankRoute } from '@/constants/index' import { verifyBlankRoute } from '@/constants/index';
// import { useRouter } from 'vue-router' // import { useRouter } from 'vue-router'
// const router = useRouter() // const router = useRouter()
@ -14,19 +15,17 @@ import { authRoutes, verifyBlankRoute } from '@/constants/index'
export default defineNuxtRouteMiddleware((to, from) => { export default defineNuxtRouteMiddleware((to, from) => {
const userStore = useUserStore() const userStore = useUserStore()
const modalStore = useModalStore() const modalStore = useModalStore()
const menuStore = useMenuStore()
if(to.path !== '/search'){ if(to.path !== '/search'){
modalStore.searchQuery = '' modalStore.searchQuery = ''
} }
const menuStore = useMenuStore()
if (verifyBlankRoute.includes(to.path) && !verifyBlankRoute.includes(from.path)) { if (verifyBlankRoute.includes(to.path) && !verifyBlankRoute.includes(from.path)) {
return abortNavigation() return abortNavigation()
} }
// 如果是需要登录的路由,且用户未登录
if (authRoutes.includes(to.path) && !userStore.isLoggedIn) { // if(to.path === "/personal-center" && !userStore.isLoggedIn){
// 显示登录模态框 // return abortNavigation()
modalStore.showLoginModal() // }
menuStore.setActiveMenu(from.path) menuStore.setActiveMenu(from.path)
// return abortNavigation()
// return navigateTo('/model-square')
}
}) })

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, onMounted } from 'vue'; import { onMounted, ref } from 'vue';
definePageMeta({ definePageMeta({
layout: 'header', layout: 'header',
}) })
const activeTab = ref('') const activeTab = ref('oasis')
// const route = useRoute(); // const route = useRoute();
// const { id } = route.params as { id: string }; // const { id } = route.params as { id: string };
@ -12,16 +12,30 @@ interface PointsResult {
points: number points: number
memberConsumeList: any[] memberConsumeList: any[]
} }
const pointsResult = ref<PointsResult>(null)
//
const consumePointsFinished = ref(false);
const consumePointsParams = ref({
"pageNum": 1,
"pageSize": 20
})
const pointsResult = ref([])
async function getPoints() { async function getPoints() {
try { try {
const res = await request.get('/member/getPoints') if (consumePointsFinished.value) return
const res = await request.post('/member/getConsumePoints', {
...consumePointsParams.value
})
if (res.code === 200) { if (res.code === 200) {
pointsResult.value = res.data as PointsResult if(consumePointsParams.value.pageNum === 1){
debugger pointsResult.value = res.rows
nextTick(() => { }else{
activeTab.value = 'beatles' pointsResult.value = [...pointsResult.value, ...res.rows]
}) }
if (pointsResult.value.length >= res.total) {
consumePointsFinished.value = true;
}
consumePointsParams.value.pageNum++
} }
} }
catch (err) { catch (err) {
@ -29,6 +43,40 @@ async function getPoints() {
} }
} }
getPoints() getPoints()
//
const rechargePointsFinished = ref(false);
const rechargePointsParams = ref({
"pageNum": 1,
"pageSize": 20
})
const rechargePoints = ref([])
async function getRechargePoints() {
try {
if (rechargePointsFinished.value) return;
const res = await request.post('/member/getRechargePoints', {
...rechargePointsParams.value
})
if (res.code === 200) {
if (rechargePointsParams.value.pageNum === 1) {
rechargePoints.value = res.rows;
} else {
rechargePoints.value = [...rechargePoints.value, ...res.rows];
}
//
if (rechargePoints.value.length >= res.total) {
rechargePointsFinished.value = true;
}
rechargePointsParams.value.pageNum++;
}
}
catch (err) {
console.log(err)
}
}
getRechargePoints()
onMounted(() => { onMounted(() => {
// nextTick(() => { // nextTick(() => {
// activeTab.value = 'beatles' // activeTab.value = 'beatles'
@ -40,47 +88,56 @@ onMounted(() => {
<div class="flex justify-center bg-[#f2f5f8] items-center h-[calc(100vh-48px)]"> <div class="flex justify-center bg-[#f2f5f8] items-center h-[calc(100vh-48px)]">
<div class="w-[1200px] bg-white rounded-lg shadow-lg p-10 h-[calc(100%-40px)]"> <div class="w-[1200px] bg-white rounded-lg shadow-lg p-10 h-[calc(100%-40px)]">
<h1 class="text-2xl font-bold mb-4"> <h1 class="text-2xl font-bold mb-4">
算力明细 积分明细
</h1> </h1>
<n-tabs v-model:value="activeTab" type="line" animated> <n-tabs v-model:value="activeTab" type="line" animated>
<!-- <n-tab-pane name="oasis" tab="已获取"> <n-tab-pane name="oasis" tab="已获取">
<div class="h-[500px] overflow-y-auto"> <div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full"> <div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]"> <div class="w-[250px]">
获取时间 获取时间
</div> </div>
<div class="w-[250px]"> <div class="w-[200px]">
获取来源 获取来源
</div> </div>
<div class="flex-1">
算力生效时间
</div>
<div class="flex-1">
算力到期时间
</div>
<div class="w-[200px]">
算力值
</div>
</div>
<div v-for="item in pointsResult.memberConsumeList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]"> <div class="w-[250px]">
{{ item.consumeTime }} 积分生效时间
</div> </div>
<div class="w-[250px]"> <div class="w-[250px]">
每日赠送算力清零 积分到期时间
</div> </div>
<div class="flex-1"> <div class="flex-1">
- 积分值
</div>
<div class="w-[180px]">
{{ item.consumePoints }}
</div> </div>
</div> </div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getRechargePoints"
>
<div v-for="item in rechargePoints" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.rechargeTime }}
</div>
<div class="w-[200px]">
{{ item.getSource }}
</div>
<div class="w-[250px]">
{{ item.effectStartTime }}
</div>
<div class="w-[250px]">
{{ item.effectEndTime }}
</div>
<div class="flex-1">
{{ item.points }}
</div>
</div>
</n-infinite-scroll>
</div> </div>
</n-tab-pane> --> </n-tab-pane>
<n-tab-pane name="beatles" tab="已消耗"> <n-tab-pane name="beatles" tab="已消耗">
<div class="h-[500px] overflow-y-auto"> <div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full"> <div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]"> <div class="w-[250px]">
消耗时间 消耗时间
</div> </div>
@ -91,10 +148,15 @@ onMounted(() => {
任务详情 任务详情
</div> </div>
<div class="w-[200px]"> <div class="w-[200px]">
算力 积分
</div> </div>
</div> </div>
<div v-for="item in pointsResult.memberConsumeList" :key="item" class="mc-table flex w-full"> <n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getPoints"
>
<div v-for="item in pointsResult" :key="item" class="mc-table flex w-full">
<div class="w-[250px]"> <div class="w-[250px]">
{{ item.consumeTime }} {{ item.consumeTime }}
</div> </div>
@ -108,6 +170,8 @@ onMounted(() => {
{{ item.consumePoints }} {{ item.consumePoints }}
</div> </div>
</div> </div>
</n-infinite-scroll>
</div> </div>
</n-tab-pane> </n-tab-pane>
</n-tabs> </n-tabs>
@ -117,10 +181,8 @@ onMounted(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
.mc-table { .mc-table {
> div { padding: 10px;
line-height: 40px; line-height: 40px;
height: 50px; border-bottom: 1px solid #eee;
border-bottom: 1px solid #eee;
}
} }
</style> </style>

View File

@ -0,0 +1,145 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
definePageMeta({
layout: "header",
});
const activeTab = ref("oasis");
// const route = useRoute();
// const { id } = route.params as { id: string };
//
const recordFinished = ref(false)
const recordParams = ref({
"pageNum": 1,
"pageSize": 10
})
const pointsResult = ref([]);
async function getPoints() {
try {
if(recordFinished.value) return
const res = await request.post("/personalCenter/getRecord",{...recordParams.value});
if (res.code === 200) {
if (recordParams.value.pageNum === 1) {
pointsResult.value = res.rows;
} else {
pointsResult.value = [...pointsResult.value, ...res.rows];
}
//
if (pointsResult.value.length >= res.total) {
recordFinished.value = true;
}
recordParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getPoints();
//
const walletRecordFinished = ref(false)
const walletRecordParams = ref({
"pageNum": 1,
"pageSize": 15
})
const walletRecordList = ref([]);
async function getWalletRecord() {
try {
if(walletRecordFinished.value) return
const res = await request.post("/personalCenter/getWalletRecord", {...walletRecordParams.value});
if (res.code === 200) {
if (walletRecordParams.value.pageNum === 1) {
walletRecordList.value = res.rows;
} else {
walletRecordList.value = [...walletRecordList.value, ...res.rows];
}
//
if (walletRecordList.value.length >= res.total) {
walletRecordFinished.value = true;
}
walletRecordParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getWalletRecord();
onMounted(() => {
// nextTick(() => {
// activeTab.value = 'beatles'
// })
});
</script>
<template>
<div class="flex justify-center bg-[#f2f5f8] items-center h-[calc(100vh-48px)]">
<div class="w-[1200px] bg-white rounded-lg shadow-lg p-10 h-[calc(100%-40px)]">
<h1 class="text-2xl font-bold mb-4">金币明细</h1>
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tab-pane name="oasis" tab="充值记录">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">获取时间</div>
<div class="w-[250px]">获取来源</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px);"
:distance="10"
@load="getPoints"
>
<div v-for="item in pointsResult" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.orderTime }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.paymentAmount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
<n-tab-pane name="beatles" tab="消费记录">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-gray-200 sticky top-0">
<div class="w-[250px]">消耗时间</div>
<div class="w-[250px]">消耗类型</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">充值金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px);"
:distance="10"
@load="getWalletRecord"
>
<div v-for="item in walletRecordList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.consumeDate }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.amount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
</n-tabs>
</div>
</div>
</template>
<style lang="scss" scoped>
.mc-table {
padding: 10px;
line-height: 40px;
border-bottom: 1px solid #eee;
}
</style>

View File

@ -1,132 +1,212 @@
<script setup lang="ts"> <script setup>
import { CheckmarkCircleSharp, Close } from '@vicons/ionicons5'; import { CheckmarkCircleSharp, Close } from "@vicons/ionicons5";
import { NConfigProvider, NMessageProvider } from 'naive-ui'; import { NConfigProvider, NMessageProvider } from "naive-ui";
const message = useMessage();
definePageMeta({ definePageMeta({
layout: 'header', layout: "header",
}) });
// //
const needPayment = ref([{ const needPayment = ref([
amount: '', {
productId: '', amount: "",
promotionId: '', productId: "",
type: 'member', promotionId: "",
}]) type: "member",
const userStore = useUserStore() },
const userInfo = userStore.userInfo as UserInfoType ]);
const userStore = useUserStore();
const userInfo = userStore.userInfo;
// //
interface Payment { // interface Payment {
isVisible: boolean // isVisible: boolean;
} // }
// //
const isMember = ref(false) const isMember = ref(false);
async function getIsMember() { async function getIsMember() {
try { try {
const res = await request.get('/member/isMember') const res = await request.get("/member/isMember");
if (res.code === 200) { if (res.code === 200) {
isMember.value = res.data isMember.value = res.data;
} }
} } catch (err) {
catch (err) { console.log(err);
console.log(err)
} }
} }
getIsMember() getIsMember();
// //
const MemberBenefitList = ref([]) const MemberBenefitList = ref([]);
async function getMemberBenefitList() { async function getMemberBenefitList() {
try { try {
const res = await request.get('/memberLevel/getMemberBenefitList') const res = await request.get("/memberLevel/getMemberBenefitList");
if (res.code === 200) { if (res.code === 200) {
MemberBenefitList.value = res.data MemberBenefitList.value = res.data;
} }
} } catch (err) {
catch (err) { console.log(err);
console.log(err)
} }
} }
getMemberBenefitList() getMemberBenefitList();
// //
interface memberLevel { // interface memberLevel {
memberName: string // memberName: string;
unitPrice: number // unitPrice: number;
originalPrice: number // originalPrice: number;
subscriptionPeriod: number // subscriptionPeriod: number;
} // }
const memberLevelList = ref<memberLevel[]>([]) const memberLevelList = ref([]);
async function getMemberLevelList() { async function getMemberLevelList() {
try { try {
const res = await request.get('/memberLevel/list') const res = await request.get("/memberLevel/list");
if (res.code === 200) { if (res.code === 200) {
memberLevelList.value = res.data memberLevelList.value = res.data;
} }
} } catch (err) {
catch (err) { console.log(err);
console.log(err)
} }
} }
getMemberLevelList() getMemberLevelList();
// //
const isShowPayment = ref(false) const isShowPayment = ref(false);
const PaymentRef = ref<Payment | null>(null) const PaymentRef = ref(null);
function showPayment(info: any) { function showPayment(info) {
if (info === 1) { if (info === 1) {
needPayment.value = memberLevelList.value needPayment.value = memberLevelList.value;
} else {
needPayment.value = [info];
} }
else { isShowPayment.value = true;
needPayment.value = [info]
}
isShowPayment.value = true
if (PaymentRef.value) { if (PaymentRef.value) {
PaymentRef.value.isVisible = true PaymentRef.value.isVisible = true;
} }
} }
// //
function closePayment() { function closePayment() {
isShowPayment.value = false isShowPayment.value = false;
if (PaymentRef.value) { if (PaymentRef.value) {
PaymentRef.value.isVisible = false PaymentRef.value.isVisible = false;
} }
} }
// //
const isShowIntPayment = ref(false) const isShowIntPayment = ref(false);
const IntPaymentRef = ref<Payment | null>(null) const IntPaymentRef = ref(null);
function showIntPayment() { function showIntPayment() {
isShowIntPayment.value = true isShowIntPayment.value = true;
if (IntPaymentRef.value) { if (IntPaymentRef.value) {
IntPaymentRef.value.isVisible = true IntPaymentRef.value.isVisible = true;
} }
} }
// //
function closeIntPayment() { function closeIntPayment() {
isShowIntPayment.value = false isShowIntPayment.value = false;
if (IntPaymentRef.value) { if (IntPaymentRef.value) {
IntPaymentRef.value.isVisible = false IntPaymentRef.value.isVisible = false;
}
}
//
const isShowGoldPayment = ref(false);
const goldPaymentRef = ref(null);
function closeGoldPayment() {
isShowGoldPayment.value = false;
if (goldPaymentRef.value) {
goldPaymentRef.value.isVisible = false;
} }
} }
// //
function paymentSuccess() { function paymentSuccess() {
getIsMember() getIsMember();
integralGold();
} }
// //
function toIntDetail() { function toIntDetail() {
const baseUrl = window.location.origin const baseUrl = window.location.origin;
window.open(`${baseUrl}/int-detail`, '_blank', 'noopener,noreferrer') window.open(`${baseUrl}/int-detail`, "_blank", "noopener,noreferrer");
} }
function toOrderManage(){ //
const baseUrl = window.location.origin function toOrderManage() {
window.open(`${baseUrl}/order-management`, '_blank', 'noopener,noreferrer') const baseUrl = window.location.origin;
window.open(`${baseUrl}/order-management`, "_blank", "noopener,noreferrer");
}
//
function toGoldDetail() {
const baseUrl = window.location.origin;
window.open(`${baseUrl}/gold-detail`, "_blank", "noopener,noreferrer");
}
//
function showGoldPayment() {
isShowGoldPayment.value = true;
if (goldPaymentRef.value) {
goldPaymentRef.value.isVisible = true;
}
}
//
const integralGold = ref({});
async function getIntegralGold() {
try {
const res = await request.post("/personalCenter/getPointAndWallet");
if (res.code === 200) {
integralGold.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getIntegralGold();
const isShowActivity = ref(true);
//
function closeActivityIcon() {
isShowActivity.value = false;
}
//
const activityList = ref([])
const isShowactivityList = ref(false);
async function showActivityList() {
try {
const res = await request.post("/promotion/promotionList", {
pageNum: 1,
pageSize: 50,
});
if (res.code === 200) {
activityList.value = res.rows
isShowactivityList.value = true;
}
} catch (err) {
console.log(err);
}
}
//
async function getActivity(item) {
if(item.isJoin === 1) return
try {
const res = await request.get(`/promotion/joinPromotion?promotionId=${item.id}`);
if (res.code === 200) {
message.success('领取成功')
item.isJoin = 1
}
} catch (err) {
if(err.code === 601){
message.warning(err.msg)
}
}
} }
</script> </script>
@ -137,16 +217,23 @@ function toOrderManage(){
<!-- 左侧用户信息 --> <!-- 左侧用户信息 -->
<div class="w-60 bg-[#2b2421] rounded-lg p-6 my-3"> <div class="w-60 bg-[#2b2421] rounded-lg p-6 my-3">
<!-- 右上角订阅管理 --> <!-- 右上角订阅管理 -->
<div class="text-right"> <!-- <div class="text-right">
<button class="text-[#8b8685] text-sm bg-inherit border-none cursor-pointer" @click="toOrderManage"> <button
class="text-[#8b8685] text-sm bg-inherit border-none cursor-pointer"
@click="toOrderManage"
>
订阅管理 > 订阅管理 >
</button> </button>
</div> </div> -->
<!-- 用户头像和信息 --> <!-- 用户头像和信息 -->
<div class="flex flex-col items-center mt-2"> <div class="flex flex-col items-center mt-2">
<client-only> <client-only>
<img :src="userInfo.avatar" alt="头像" class="w-20 h-20 rounded-full mb-3"> <img
:src="userInfo.avatar"
alt="头像"
class="w-20 h-20 rounded-full mb-3"
/>
<span class="text-white text-sm mb-2">{{ userInfo.nickName }}</span> <span class="text-white text-sm mb-2">{{ userInfo.nickName }}</span>
</client-only> </client-only>
<div class="flex items-center text-[#8b8685] text-xs"> <div class="flex items-center text-[#8b8685] text-xs">
@ -160,7 +247,11 @@ function toOrderManage(){
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
/> />
</svg> </svg>
{{ isMember.result === '1' ? `会员到期时间: ${isMember.endDate}` : '您还不是魔创未来的会员' }} {{
isMember.result === "1"
? `会员到期时间: ${isMember.endDate}`
: "您还不是魔创未来的会员"
}}
</div> </div>
</div> </div>
@ -187,41 +278,49 @@ function toOrderManage(){
<div class="grid grid-cols-3 gap-8"> <div class="grid grid-cols-3 gap-8">
<!-- 算力余额 --> <!-- 算力余额 -->
<div> <div>
<h3 class="text-[#c3986b] mb-4"> <h3 class="text-[#c3986b] mb-4">积分余额</h3>
算力余额
</h3>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<span class="text-[#c3986b] mr-2">300</span> <span class="text-[#c3986b] mr-2">{{ integralGold.point || 0 }}</span>
<button class="text-[#c3986b] bg-inherit border-none cursor-pointer" @click="showIntPayment"> <button
class="text-[#c3986b] bg-inherit border-none cursor-pointer"
@click="showIntPayment"
>
充值 > 充值 >
</button> </button>
</div> </div>
<button class="text-white bg-inherit border-none cursor-pointer p-0" @click="toIntDetail"> <button
算力明细 > class="text-white bg-inherit border-none cursor-pointer p-0"
@click="toIntDetail"
>
积分明细 >
</button> </button>
</div> </div>
<!-- 生图加速余额 --> <!-- 生图加速余额 -->
<div> <div>
<h3 class="text-[#c3986b] mb-4"> <h3 class="text-[#c3986b] mb-4">金币余额</h3>
生图加速余额
</h3>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<span class="text-[#c3986b] mr-2">0</span> <span class="text-[#c3986b] mr-2"
<button class="text-[#c3986b] bg-inherit border-none cursor-pointer"> >{{ integralGold.wallet || 0 }} </span
>
<button
class="text-[#c3986b] bg-inherit border-none cursor-pointer"
@click="showGoldPayment"
>
充值 > 充值 >
</button> </button>
</div> </div>
<button class="text-white bg-inherit border-none cursor-pointer p-0"> <button
class="text-white bg-inherit border-none cursor-pointer p-0"
@click="toGoldDetail"
>
加速明细 > 加速明细 >
</button> </button>
</div> </div>
<!-- 训练加速余额 --> <!-- 训练加速余额 -->
<div> <div>
<h3 class="text-[#c3986b] mb-4"> <h3 class="text-[#c3986b] mb-4">训练加速余额</h3>
训练加速余额
</h3>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<span class="text-[#c3986b]">0</span> <span class="text-[#c3986b]">0</span>
</div> </div>
@ -244,9 +343,7 @@ function toOrderManage(){
<!-- 进度条 --> <!-- 进度条 -->
<div class="relative"> <div class="relative">
<div class="h-1 bg-[#3a322e] rounded-full"> <div class="h-1 bg-[#3a322e] rounded-full">
<div class="absolute right-0 -top-6 text-[#8b8685] text-sm"> <div class="absolute right-0 -top-6 text-[#8b8685] text-sm">0G/3G</div>
0G/3G
</div>
</div> </div>
</div> </div>
@ -281,14 +378,17 @@ function toOrderManage(){
<div class="card-item"> <div class="card-item">
<span class="text-[#814600] text-[20px] mr-2">¥</span> <span class="text-[#814600] text-[20px] mr-2">¥</span>
<span class="text-[#814600] text-[40px] mr-2">{{ item.unitPrice }}</span> <span class="text-[#814600] text-[40px] mr-2">{{ item.unitPrice }}</span>
<span class="text-gray-400 text-[20px] line-through">¥{{ item.originalPrice }}</span> <span class="text-gray-400 text-[20px] line-through"
>¥{{ item.originalPrice }}</span
>
</div> </div>
<div class="card-item text-[#e08909] w-7/10 text-center text-[12px]"> <div class="card-item text-[#e08909] w-7/10 text-center text-[12px]">
{{ item.subscriptionPeriod }} {{ item.subscriptionPeriod }}
</div> </div>
<div class="card-item"> <div class="card-item">
<button <button
class="bg-gradient-to-r from-[#fbdfa4] to-[#f3c180] text-[#4c3d33] w-40 h-10 rounded-full text-[12px] border-none cursor-pointer" @click="showPayment(item)" class="bg-gradient-to-r from-[#fbdfa4] to-[#f3c180] text-[#4c3d33] w-40 h-10 rounded-full text-[12px] border-none cursor-pointer"
@click="showPayment(item)"
> >
立即开通 立即开通
</button> </button>
@ -297,9 +397,7 @@ function toOrderManage(){
</div> </div>
<div class="py-8"> <div class="py-8">
<div class="flex justify-center mb-4"> <div class="flex justify-center mb-4">
<div class="text-xl font-bold"> <div class="text-xl font-bold">会员权益</div>
会员权益
</div>
</div> </div>
<!-- <div class="flex items-center"> <!-- <div class="flex items-center">
<div v-for="(item, index) in MemberBenefitList" :key="index" class="w-1/4 w-full"> <div v-for="(item, index) in MemberBenefitList" :key="index" class="w-1/4 w-full">
@ -315,67 +413,35 @@ function toOrderManage(){
</div> --> </div> -->
<div class="text-[#525252]"> <div class="text-[#525252]">
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#f7f0ea]"> <div class="member-item bg-[#f7f0ea]">会员权益</div>
会员权益 <div class="member-item bg-[#f5f5f5]">用户免费</div>
</div> <div class="member-item bg-[#fdf6ea]">基础版VIP</div>
<div class="member-item bg-[#f5f5f5]"> <div class="member-item bg-[#fce6bf]">专业版VIP</div>
用户免费
</div>
<div class="member-item bg-[#fdf6ea]">
基础版VIP
</div>
<div class="member-item bg-[#fce6bf]">
专业版VIP
</div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">算力</div>
算力 <div class="member-item bg-[#fff]">每天300点</div>
</div> <div class="member-item bg-[#fff]">每月15000点</div>
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]member-item">每月35000点</div>
每天300点
</div>
<div class="member-item bg-[#fff]">
每月15000点
</div>
<div class="member-item bg-[#fff]member-item">
每月35000点
</div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">云端存储空间</div>
云端存储空间 <div class="member-item bg-[#fafafa]">3GB</div>
</div> <div class="member-item bg-[#fdf6ea]">20GB</div>
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fce6bf]">50GB</div>
3GB
</div>
<div class="member-item bg-[#fdf6ea]">
20GB
</div>
<div class="member-item bg-[#fce6bf]">
50GB
</div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">生图加速特权</div>
生图加速特权
</div>
<div class="member-item bg-[#fff]member-item"> <div class="member-item bg-[#fff]member-item">
<n-icon size="20" color="#ed7470"> <n-icon size="20" color="#ed7470">
<Close /> <Close />
</n-icon> </n-icon>
</div> </div>
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">每月800次</div>
每月800次 <div class="member-item bg-[#fff]">每月5000次</div>
</div>
<div class="member-item bg-[#fff]">
每月5000次
</div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">会员专属模型</div>
会员专属模型
</div>
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#ed7470"> <n-icon size="20" color="#ed7470">
<Close /> <Close />
@ -393,9 +459,7 @@ function toOrderManage(){
</div> </div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">生图高级功能</div>
生图高级功能
</div>
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">
<n-icon size="20" color="#ed7470"> <n-icon size="20" color="#ed7470">
<Close /> <Close />
@ -413,9 +477,7 @@ function toOrderManage(){
</div> </div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">训练XL模型</div>
训练XL模型
</div>
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#ed7470"> <n-icon size="20" color="#ed7470">
<Close /> <Close />
@ -433,9 +495,7 @@ function toOrderManage(){
</div> </div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">图片去水印下载</div>
图片去水印下载
</div>
<div class="member-item bg-[#fff]"> <div class="member-item bg-[#fff]">
<n-icon size="20" color="#ed7470"> <n-icon size="20" color="#ed7470">
<Close /> <Close />
@ -453,46 +513,126 @@ function toOrderManage(){
</div> </div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">多任务并行生图</div>
多任务并行生图
</div>
<div class="member-item bg-[#fafafa]"> <div class="member-item bg-[#fafafa]">
<n-icon size="20" color="#58c08f"> <n-icon size="20" color="#58c08f">
<CheckmarkCircleSharp /> <CheckmarkCircleSharp />
</n-icon> </n-icon>
</div> </div>
<div class="member-item bg-[#fdf6ea]"> <div class="member-item bg-[#fdf6ea]">2</div>
2 <div class="member-item bg-[#fce6bf]">3</div>
</div>
<div class="member-item bg-[#fce6bf] ">
3
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="text-[#999] text-[12px]"> <div class="text-[#999] text-[12px]">
<div class="mt-1"> <div class="mt-1">
会员每月算力和加速特权按月下发有效期31天到期重置会员模型下载次数上限为每月200次 会员每月算力和加速特权按月下发, 有效期31天,
到期重置会员模型下载次数上限为每月200次
</div> </div>
<div class="mt-1"> <div class="mt-1">
发票或团队/企业定制需求请点击立即咨询联系我们企业合作需求也可直接联系xxxx 发票或团队/企业定制需求, 请点击立即咨询联系我们, 企业合作需求也可直接联系xxxx
</div>
<div class="mt-1">
更多问题可见帮助中心
</div> </div>
<div class="mt-1">更多问题可见帮助中心</div>
</div> </div>
</div> </div>
</div> </div>
<NConfigProvider> <NConfigProvider>
<NMessageProvider> <NMessageProvider>
<Payment v-if="isShowPayment" ref="PaymentRef" :info="needPayment" :is-member="isMember" @close-payment="closePayment" /> <Payment
<IntPayment v-if="isShowIntPayment" ref="IntPaymentRef" :is-member="isMember" @payment-success="paymentSuccess" @close-payment="closeIntPayment" /> v-if="isShowPayment"
ref="PaymentRef"
:info="needPayment"
:is-member="isMember"
@close-payment="closePayment"
/>
<IntPayment
v-if="isShowIntPayment"
ref="IntPaymentRef"
:is-member="isMember"
@payment-success="paymentSuccess"
@close-payment="closeIntPayment"
/>
<GoldPayment
v-if="isShowGoldPayment"
ref="goldPaymentRef"
:is-member="isMember"
@payment-success="paymentSuccess"
@close-payment="closeGoldPayment"
/>
</NMessageProvider> </NMessageProvider>
</NConfigProvider> </NConfigProvider>
<div class="activity-box" v-if="isShowActivity">
<div class="absolute -top-6 -right-0 cursor-pointer">
<n-icon size="20" color="#bbb" @click="closeActivityIcon">
<Close />
</n-icon>
</div>
<img
class="cursor-pointer"
@click="showActivityList"
src="@/assets/img/activityIcon.png"
alt=""
/>
</div>
<n-modal v-model:show="isShowactivityList" transform-origin="center">
<n-card
style="width: 350px; background: #e65e40"
:bordered="false"
size="huge"
:content-style="{ padding: 0 }"
role="dialog"
aria-modal="true"
>
<div class="p-4 rounded-lg">
<div class="flex justify-end mb-4">
<n-icon
class="cursor-pointer"
@click="isShowactivityList = false"
size="20"
color="#bbb"
>
<Close />
</n-icon>
</div>
<div class="flex flex-col gap-3">
<div
class="px-2 py-4 bg-white h-20 w-full flex rounded-lg"
v-for="(item, index) in activityList"
:key="index"
>
<div class="w-[70%] flex flex-col justify-around">
<div>{{ item.activityName }}</div>
<div class="text-xs text-gray-500">有效期: {{item.startTime}}</div>
<div class="text-xs text-gray-500">失效期: {{item.endTime}}</div>
</div>
<div class="w-[30%] flex items-center justify-center">
<div
@click="getActivity(item)"
class="w-14 h-6 flex items-center justify-center cursor-pointer text-white text-xs bg-[#e9613f] rounded-full"
:style="{backgroundColor: item.isJoin === 0 ? '#e9613f' : '#ccc'}"
>
{{ item.isJoin === 0 ? '领取' : '已领取' }}
</div>
</div>
</div>
</div>
</div>
</n-card>
</n-modal>
</div> </div>
</template> </template>
<style scoped> <style scoped>
/* .n-card__content{
padding:20px !important
} */
.activity-box {
position: fixed;
bottom: 20px;
right: 20px;
justify-content: space-around
}
.card-item { .card-item {
@apply flex items-center justify-center h-1/4; @apply flex items-center justify-center h-1/4;
} }

View File

@ -1,13 +1,17 @@
<script setup lang="ts"> <script setup>
import { commonApi } from "@/api/common"; import { commonApi } from "@/api/common";
import { Close, DiamondSharp, PersonAddOutline } from "@vicons/ionicons5"; import { Close, DiamondSharp, PersonAddOutline } from "@vicons/ionicons5";
import { import {
CircleUser, CircleUser,
Download, Download,
EllipsisVertical, Heart, Play, EllipsisVertical,
Heart,
Play,
SquareCheck,
SquarePlus SquarePlus
} from "lucide-vue-next"; } from "lucide-vue-next";
//
import { formatFileSize } from '@/utils/index.ts';
import { NConfigProvider, NMessageProvider } from "naive-ui"; import { NConfigProvider, NMessageProvider } from "naive-ui";
import { ref } from "vue"; import { ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
@ -21,11 +25,11 @@ definePageMeta({
}); });
// const userStore = useUserStore() // const userStore = useUserStore()
const route = useRoute(); const route = useRoute();
const { id } = route.params as { id: string }; const { id } = route.params
const activeTab = ref(null); const activeTab = ref(null);
const commentHeight = ref(800); const commentHeight = ref(800);
const detailsInfo = ref({}); const detailsInfo = ref({});
const currentUserInfo = ref<any>({}); const currentUserInfo = ref({});
const isVisibleReport = ref(false); const isVisibleReport = ref(false);
// //
const versionByWorkInfo = ref([]); const versionByWorkInfo = ref([]);
@ -34,7 +38,9 @@ async function getInfo() {
const res = await request.get(`/model/selectModelById?id=${id}`); const res = await request.get(`/model/selectModelById?id=${id}`);
if (res.code === 200) { if (res.code === 200) {
detailsInfo.value = res.data; detailsInfo.value = res.data;
detailsInfo.value.styleList = JSON.parse(res.data.styleList); if (res.data.tags) {
detailsInfo.value.tagsList = JSON.parse(res.data.tags);
}
// detailsInfo.value.styleList =JSON.parse(res.data.styleList) // detailsInfo.value.styleList =JSON.parse(res.data.styleList)
// // 1 // // 1
try { try {
@ -73,15 +79,15 @@ async function getInfo() {
getInfo(); getInfo();
// // // //
interface SelectUserInfo { // interface SelectUserInfo {
attention: number; // attention: number;
bean: number; // bean: number;
imageLikeNum: number; // imageLikeNum: number;
modelDownLoadNum: number; // modelDownLoadNum: number;
modelLikeNum: number; // modelLikeNum: number;
modelRunNum: number; // modelRunNum: number;
} // }
const selectUserInfo = ref<SelectUserInfo>({ const selectUserInfo = ref({
attention: 0, attention: 0,
bean: 0, bean: 0,
imageLikeNum: 0, imageLikeNum: 0,
@ -106,8 +112,8 @@ async function getAttention() {
// // // //
const isDelete = ref(false); const isDelete = ref(false);
async function handleSelect(event: Event, type: string) { async function handleSelect(type) {
event.stopPropagation(); // // event.stopPropagation(); //
if (type === "report") { if (type === "report") {
isVisibleReport.value = true; isVisibleReport.value = true;
// await request.get(`/WorkFlow/report?id=${id}`) // // await request.get(`/WorkFlow/report?id=${id}`) //
@ -183,7 +189,7 @@ async function onLike() {
const reportParams = ref({ const reportParams = ref({
reportId: undefined, reportId: undefined,
text: "", text: "",
type:1 type: 1,
}); });
const reportList = ref([]); const reportList = ref([]);
async function getDictType() { async function getDictType() {
@ -197,7 +203,7 @@ async function getDictType() {
} }
} }
getDictType(); getDictType();
function handleChange(item: any) { function handleChange(item) {
reportParams.value.reportId = item.dictValue; reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") { if (item.dictValue !== "5") {
reportParams.value.text = ""; reportParams.value.text = "";
@ -209,30 +215,78 @@ function closeReport() {
isVisibleReport.value = false; isVisibleReport.value = false;
} }
async function onReport(){ async function onReport() {
if( reportParams.value.reportId !== undefined){ if (reportParams.value.reportId !== undefined) {
reportParams.value.productId = detailsInfo.value.id reportParams.value.productId = detailsInfo.value.id;
try{ try {
const res = await request.post('/report/addReport', reportParams.value) const res = await request.post("/report/addReport", reportParams.value);
if(res.code === 200){ if (res.code === 200) {
message.success("举报成功"); message.success("举报成功");
closeReport() closeReport();
} }
}catch(err){ } catch (err) {
console.log(err); console.log(err);
} }
} }
} }
function toPersonalCenter(){ function toPersonalCenter() {
const baseUrl = window.location.origin const baseUrl = window.location.origin;
if(userStore?.userInfo?.userId === detailsInfo.value.userId){ if (userStore?.userInfo?.userId === detailsInfo.value.userId) {
window.open(`${baseUrl}/personal-center`, '_blank', 'noopener,noreferrer') window.open(`${baseUrl}/personal-center`, "_blank", "noopener,noreferrer");
}else{ } else {
debugger window.open(
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer') `${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`,
"_blank",
"noopener,noreferrer"
);
} }
} }
const currentTabsIndex = ref(0);
function handleTabChange(id) {
for (let i = 0; i < versionByWorkInfo.value.length; i++) {
if (id === versionByWorkInfo.value[i].id) {
currentTabsIndex.value = i;
}
}
}
async function addCollect(){
try {
const params = {
"productId": versionByWorkInfo.value[currentTabsIndex.value].id,
"productType": 0,
}
const res = await request.post("/collect/addCollect", params);
if (res.code === 200) {
versionByWorkInfo.value[currentTabsIndex.value].isCollect = res.data
if(res.data === 0){
message.success("已加入模型库, 可通过在线生图使用");
}else{
message.success("已从模型库中移除");
}
}
} catch (err) {
console.log(err);
}
}
async function handelDown(){
try {
const res = await request.get(`/ModelVersion/modelFileDownload?id=${versionByWorkInfo.value[currentTabsIndex.value].id}`);
if (res.code === 200) {
const link = document.createElement('a');
link.href = res.data;
link.download = res.msg; //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
} catch (err) {
console.log(err);
}
}
</script> </script>
<template> <template>
@ -270,10 +324,7 @@ function toPersonalCenter(){
<template #trigger> <template #trigger>
<div class="flex items-center bg-[#f4f5f9] px-2 rounded-full"> <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="" /> --> <!-- <img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-1" alt="" /> -->
<component <component :is="Heart" class="h-[12px] w-[12px] mr-1 text-[#000]" />
:is="Heart"
class="h-[12px] w-[12px] mr-1 text-[#000]"
/>
<span>{{ detailsInfo.likeNum || 0 }} </span> <span>{{ detailsInfo.likeNum || 0 }} </span>
</div> </div>
</template> </template>
@ -283,7 +334,7 @@ function toPersonalCenter(){
<div class="flex items-center mt-3 mb-5"> <div class="flex items-center mt-3 mb-5">
<div <div
v-for="(item, index) in detailsInfo.styleList" v-for="(item, index) in detailsInfo.tagsList"
:key="index" :key="index"
class="text-[12px] bg-[#ebf2fe] p-1 px-2 text-[#557abf] mr-4 rounded-md" class="text-[12px] bg-[#ebf2fe] p-1 px-2 text-[#557abf] mr-4 rounded-md"
> >
@ -293,7 +344,12 @@ function toPersonalCenter(){
<div class="flex w-full gap-1"> <div class="flex w-full gap-1">
<div class="w-2/3"> <div class="w-2/3">
<div class="w-full"> <div class="w-full">
<n-tabs v-model:value="activeTab" type="line" animated> <n-tabs
v-model:value="activeTab"
@update:value="handleTabChange"
type="line"
animated
>
<n-tab-pane <n-tab-pane
v-for="(item, index) in versionByWorkInfo" v-for="(item, index) in versionByWorkInfo"
:key="index" :key="index"
@ -471,23 +527,32 @@ function toPersonalCenter(){
</div> </div>
<div class="flex gap-y-2"> <div class="flex gap-y-2">
<div <div
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md" v-if="versionByWorkInfo.length > 0"
@click="addCollect"
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md cursor-pointer"
> >
<component <component
:is="SquarePlus" :is="
versionByWorkInfo[currentTabsIndex].isCollect === 1
? SquarePlus
: SquareCheck
"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/> />
<span class="mr-1">加入模型课</span> <span class="mr-1">
{{ versionByWorkInfo[currentTabsIndex].isCollect === 1 ? '加入模型库' : '已加入'}}
</span>
</div> </div>
<div <div
@click="handelDown"
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" 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 <component
:is="Download" :is="Download"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/> />
<span class="mr-1"> 下载 (122.22MB) </span> <span class="mr-1" v-if="versionByWorkInfo.length > 0"> {{ formatFileSize(versionByWorkInfo[currentTabsIndex].fileSize) }} </span>
</div> </div>
</div> </div>
@ -505,7 +570,7 @@ function toPersonalCenter(){
content="确定要将模型删除? 模型删除后无法找回" content="确定要将模型删除? 模型删除后无法找回"
negative-text="取消" negative-text="取消"
positive-text="确认" positive-text="确认"
@negative-click="onDelete" @negative-click="isDelete = false"
@positive-click="onDelete" @positive-click="onDelete"
/> />
@ -539,7 +604,9 @@ function toPersonalCenter(){
{{ item.dictLabel }} {{ item.dictLabel }}
</n-radio> </n-radio>
<n-input <n-input
v-if="reportParams.reportId !== undefined && reportParams.reportId === '5'" v-if="
reportParams.reportId !== undefined && reportParams.reportId === '5'
"
v-model:value="reportParams.text" v-model:value="reportParams.text"
placeholder="点击输入" placeholder="点击输入"
type="textarea" type="textarea"
@ -549,12 +616,10 @@ function toPersonalCenter(){
}" }"
/> />
<div <div
@click="onReport" @click="onReport"
class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer" class="mt-4 w-[100%] h-10 flex rounded-lg text-white items-center justify-center cursor-pointer"
:class="[ :class="[
reportParams.reportId !== undefined reportParams.reportId !== undefined ? 'bg-[#4c79ee]' : 'bg-[#cccccc]',
? 'bg-[#4c79ee]'
: 'bg-[#cccccc]',
]" ]"
> >
确认 确认
@ -571,7 +636,7 @@ function toPersonalCenter(){
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss" scoped>
.header-num { .header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full; @apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
} }
@ -599,9 +664,9 @@ function toPersonalCenter(){
background: linear-gradient(90deg, #173eff 0%, #1b7dff 100%); background: linear-gradient(90deg, #173eff 0%, #1b7dff 100%);
border-radius: 2px; border-radius: 2px;
transition: left 0.2s var(--n-bezier), max-width 0.2s var(--n-bezier), 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); opacity 0.3s var(--n-bezier), background-color 0.3s var(--n-bezier);
} }
.original{ .original {
margin: 2px 0; margin: 2px 0;
padding: 2px 0; padding: 2px 0;
display: flex; display: flex;
@ -609,7 +674,7 @@ function toPersonalCenter(){
justify-content: center; justify-content: center;
width: 90px; width: 90px;
font-size: 12px; font-size: 12px;
color: #aa8645; color: #aa8645;
font-weight: 400; font-weight: 400;
background: linear-gradient(94.11deg, #efd6a9 10.52%, #f0dcbc 107.96%); background: linear-gradient(94.11deg, #efd6a9 10.52%, #f0dcbc 107.96%);
border-radius: 4px; border-radius: 4px;

View File

@ -8,6 +8,8 @@ import { useUserStore } from "@/stores/user";
import { formatDate } from "@/utils/index.ts"; import { formatDate } from "@/utils/index.ts";
import { NConfigProvider, NMessageProvider } from "naive-ui"; import { NConfigProvider, NMessageProvider } from "naive-ui";
import { nextTick, onMounted, onUnmounted, ref } from "vue"; import { nextTick, onMounted, onUnmounted, ref } from "vue";
let pollingTimer: ReturnType<typeof setInterval> | undefined
const route = useRoute(); const route = useRoute();
const { type, status } = route.query as { type: string; status: string }; const { type, status } = route.query as { type: string; status: string };
@ -16,6 +18,9 @@ const finished = ref(false);
const total = ref(0); // const total = ref(0); //
const loadingTrigger = ref(null); const loadingTrigger = ref(null);
import { useRouter } from "vue-router";
const router = useRouter();
const observer = ref<IntersectionObserver | null>(null); const observer = ref<IntersectionObserver | null>(null);
definePageMeta({ definePageMeta({
layout: "default", layout: "default",
@ -58,7 +63,7 @@ const typeList = ref([
// form // form
const publishParams = ref({ const publishParams = ref({
pageNum: 1, pageNum: 1,
pageSize: 12, pageSize: 20,
status: "0", status: "0",
orderByColumn: "create_time", orderByColumn: "create_time",
date: null, date: null,
@ -69,7 +74,7 @@ const publishParams = ref({
function initPublishParams() { function initPublishParams() {
publishParams.value = { publishParams.value = {
pageNum: 1, pageNum: 1,
pageSize: 12, pageSize: 20,
status: "0", status: "0",
orderByColumn: "create_time", orderByColumn: "create_time",
date: null, date: null,
@ -81,14 +86,14 @@ function initPublishParams() {
// form // form
const likesParams = ref({ const likesParams = ref({
pageNum: 1, pageNum: 1,
pageSize: 12, pageSize: 20,
orderByColumn: "create_time", orderByColumn: "create_time",
}); });
function initLikesParams() { function initLikesParams() {
likesParams.value = { likesParams.value = {
pageNum: 1, pageNum: 1,
pageSize: 12, pageSize: 20,
orderByColumn: "create_time", orderByColumn: "create_time",
}; };
} }
@ -245,7 +250,7 @@ getAttention();
// Banner // Banner
const bannerStyle = { const bannerStyle = {
backgroundImage: backgroundImage:
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')", "url('https://img.zcool.cn/community/special_cover/3a9a64d3628c000c2a1000657eec.jpg')",
}; };
// //
@ -362,7 +367,7 @@ const attentionFinished = ref(false);
const attentionList = ref([]); const attentionList = ref([]);
const attentionListParams = ref({ const attentionListParams = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 15, pageSize: 20,
}); });
async function getAttentionList() { async function getAttentionList() {
try { try {
@ -397,7 +402,8 @@ const likeFinished = ref(false);
const likeList = ref([]); const likeList = ref([]);
const likeListParams = ref({ const likeListParams = ref({
pageNumber: 1, pageNumber: 1,
pageSize: 15, pageSize: 20,
type:null
}); });
async function getLikeList() { async function getLikeList() {
try { try {
@ -434,6 +440,10 @@ function closefanList() {
// / // /
async function onAttention(item: any) { async function onAttention(item: any) {
try { try {
const userId = userStore.userInfo.userId
if(userId === item.userId){
return message.warning('自己不能关注自己')
}
const res = await request.get(`/attention/addAttention?userId=${item.userId}`); const res = await request.get(`/attention/addAttention?userId=${item.userId}`);
if (res.code === 200) { if (res.code === 200) {
if (res.data) { if (res.data) {
@ -490,101 +500,7 @@ function handlePositiveClick() {
const activeTab = ref('like') const activeTab = ref('like')
// //
const invitationList = ref({ const invitationList = ref({});
totalAmount: 2889,
earningsDisplayList: [
{
user: {
userId: 2,
userName: "ry",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 1,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 105,
userName: "默认用户:oKwIrhqh",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 2,
},
{
user: {
userId: 107,
userName: "默认用户:hQDEthgT",
avatar:
"https://img1.baidu.com/it/u=728383910,3448060628&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800",
},
count: 0,
},
],
});
async function handleNegativeClick() { async function handleNegativeClick() {
try { try {
const res = await request.get(`/invitation/earningsDisplay`); const res = await request.get(`/invitation/earningsDisplay`);
@ -600,13 +516,64 @@ const showLike = (type:string) =>{
isShowFan.value= true isShowFan.value= true
activeTab.value = type activeTab.value = type
} }
const toWallet = () => {
router.push({
path: `/wallet`,
});
}
//
const zfbStatus = ref('0')
async function getBindStatus(){
const res = await request.get(`/ali/pay/queryBindStatus`)
if (res.data === '1') { //'1 0
zfbStatus.value = res.data
message.success('绑定成功!')
}
}
getBindStatus()
//
const qrUrl = ref('')
const isShowBindingModal = ref(false)
const showBinding = async() =>{
try {
const res = await request.get(`/ali/pay/generateQrCode`);
if (res.code === 200) {
qrUrl.value = res.data;
isShowBindingModal.value = true
pollingTimer && clearTimeout(pollingTimer)
pollingTimer = setInterval(async () => {
try {
const res2 = await request.get(`/ali/pay/queryBindStatus`)
if (res2.data === '1') {
closeBindingModal()
message.success('绑定成功!')
}
}
catch (err) {
closeBindingModal()
message.warning('绑定失败,请稍后再试!')
}
}, 2000)
}
} catch (err) {
console.log(err);
}
}
const closeBindingModal = () =>{
pollingTimer && clearTimeout(pollingTimer)
isShowBindingModal.value = false
}
</script> </script>
<template> <template>
<div class="mx-auto"> <div class="mx-auto relative">
<!-- Banner Section --> <!-- Banner Section -->
<div class="banner-content h-32 bg-blue bg-cover bg-center" :style="bannerStyle" /> <div class="banner-content h-32 bg-blue bg-cover bg-center" :style="bannerStyle" />
<!-- User Info Section --> <!-- User Info Section -->
<div class="info-content mt-[-50px] p-5"> <div class="info-content mt-[-50px] p-5">
<div class="edit-info-content flex items-center"> <div class="edit-info-content flex items-center">
@ -662,6 +629,15 @@ const showLike = (type:string) =>{
邀请码: {{ invitationCode }} 邀请码: {{ invitationCode }}
</n-popconfirm> </n-popconfirm>
</div> </div>
<div class="ml-4 cursor-pointer" @click="toWallet()">
<img src="@/assets/img/wallet.png" alt="">
</div>
<div v-if="zfbStatus === '1'" class="bg-[#3875f6] rounded-full px-4 py-2">
已绑定支付宝
</div>
<div v-else @click="showBinding" class="text-xs px-3 py-2 border border-solid border-[#ccc] rounded-full ml-4 bg-white cursor-pointer">
绑定支付宝
</div>
</div> </div>
<!-- User Details --> <!-- User Details -->
@ -946,6 +922,26 @@ const showLike = (type:string) =>{
</div> </div>
</n-card> </n-card>
</n-modal> </n-modal>
<div v-if="isShowBindingModal" class="fan-centent">
<div class="relative flex flex-col items-center">
<div class="bg-[#000] py-10 px-20 flex flex-col items-center justify-center rounded-lg">
<div class="text-xl text-white mb-4">
扫码绑定
</div>
<n-qr-code :value="qrUrl" :size="150" style="padding: 0;" />
<div class="text-base text-white mt-4">
请用手机支付宝扫码
</div>
</div>
<n-icon
size="30"
class="cursor-pointer mt-4 text-white"
@click="closeBindingModal"
>
<Close />
</n-icon>
</div>
</div>
</div> </div>
</template> </template>

View File

@ -140,7 +140,7 @@
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" /> <img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }} {{ item.nickName }}
</div> </div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)"> <div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item, 'attention')">
{{ item.attention ? '已关注' : '未关注' }} {{ item.attention ? '已关注' : '未关注' }}
</div> </div>
</div> </div>
@ -161,7 +161,7 @@
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" /> <img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }} {{ item.nickName }}
</div> </div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)"> <div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item, 'like')">
{{ item.attention ? '已关注' : '未关注' }} {{ item.attention ? '已关注' : '未关注' }}
</div> </div>
</div> </div>
@ -182,7 +182,7 @@ import { nextTick, onMounted, onUnmounted, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const observer = ref<IntersectionObserver | null>(null); const observer = ref<IntersectionObserver | null>(null);
const message = useMessage() const message = useMessage()
const userStore = useUserStore();
const route = useRoute(); const route = useRoute();
const { userId } = route.query; const { userId } = route.query;
const loading = ref(false); const loading = ref(false);
@ -191,9 +191,9 @@ const total = ref(0); // 总条数
const loadingTrigger = ref(null); const loadingTrigger = ref(null);
const urlList = ref({ const urlList = ref({
"0": "/model/selectByUserIdModel", "0": "/personalCenter/selectByUserIdModel",
"1": "/model/selectByUserIdWorkFlow", "1": "/personalCenter/selectByUserIdWorkFlow",
"2": "/model/selectByUserIdImage", "2": "/personalCenter/selectByUserIdImage",
}); });
const currentType = ref("0"); const currentType = ref("0");
const typeList = ref([ const typeList = ref([
@ -222,12 +222,12 @@ function closefanList() {
const bannerStyle = { const bannerStyle = {
backgroundImage: backgroundImage:
"url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png')", "url('https://img.zcool.cn/community/special_cover/3a9a64d3628c000c2a1000657eec.jpg')",
}; };
const publishParams = ref({ const publishParams = ref({
pageNum: 1, pageNum: 1,
pageSize: 12, pageSize: 20,
orderByColumn: "create_time", orderByColumn: "create_time",
userId: userId, userId: userId,
}); });
@ -287,6 +287,10 @@ getIsAttention()
// / // /
async function onAttention(item:any){ async function onAttention(item:any){
const myUserId = userStore.userInfo.userId
if(myUserId === item.userId){
return message.warning('自己不能关注自己')
}
let paramsUserId let paramsUserId
if(item.userId){ if(item.userId){
paramsUserId = item.userId paramsUserId = item.userId

View File

@ -110,7 +110,7 @@ function changeCategory(item: any) {
</MenuFold> </MenuFold>
</div> </div>
</div> </div>
<div class="flex flex-wrap"> <div class="w-full">
<NConfigProvider> <NConfigProvider>
<NMessageProvider> <NMessageProvider>
<PictureList ref="listRef" :params="params" /> <PictureList ref="listRef" :params="params" />

View File

@ -19,6 +19,7 @@ async function initFormData() {
if (type === "add") { if (type === "add") {
formData.value = { formData.value = {
modelProduct: { modelProduct: {
jurisdiction:1, //
modelName: "", modelName: "",
modelType: null, // , modelType: null, // ,
category: null, // category: null, //
@ -102,10 +103,10 @@ const timeLineList = ref([
}, },
]); ]);
async function nextStep() { async function nextStep() {
if(currentStep.value === 1){ if(currentStep.value === 1 && type === 'add'){
const name = formData.value.modelProduct.modelName const name = formData.value.modelProduct.modelName
try { try {
const res = await request.get(`/file/selectFile?type=model&name=${name}`); const res = await request.get(`/model/selectModelByName?name=${name}`);
if (res.code == 200) { if (res.code == 200) {
if(res.data === 1){ //0 1 if(res.data === 1){ //0 1
currentStep.value += 1; currentStep.value += 1;

View File

@ -5,10 +5,10 @@ import UploadImg from "@/components/publishWorkFlow/UploadImg.vue";
import { CirclePlus } from "lucide-vue-next"; import { CirclePlus } from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui"; import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const message = useMessage();
const route = useRoute(); const route = useRoute();
const { type, id } = route.query; const { type, id } = route.query;
const formData = ref(); const formData = ref();
async function initFormData() { async function initFormData() {
@ -73,12 +73,16 @@ function handleAddVersion() {
} }
async function nextStep() { async function nextStep() {
// currentStep.value += 1; // currentStep.value += 1;
if(currentStep.value === 1){ if(currentStep.value === 1 && type === 'add'){
const name = formData.value.workFlow.workflowName const name = formData.value.workFlow.workflowName
try { try {
const res = await request.get(`/file/selectFile?type=workflow&name=${name}`); const res = await request.get(`/WorkFlow/selectWorkFlowByName?name=${name}`);
if (res.code == 200) { if (res.code == 200) {
currentStep.value += 1; if(res.data === 0 ){
currentStep.value += 1;
}else{
message.warning('该工作流名称已存在')
}
} }
} catch (err) { } catch (err) {
console.log(err); console.log(err);

View File

@ -67,7 +67,6 @@ const imageParams = ref({
if(type != 'undefined'){ if(type != 'undefined'){
currentType.value = type currentType.value = type
} }
// debugger
// if(keyword){ // if(keyword){
// modelParams.value.name = keyword; // modelParams.value.name = keyword;
// imageParams.value.name = keyword; // imageParams.value.name = keyword;

View File

@ -0,0 +1,19 @@
<template>
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1
class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200"
>
关于魔创未来
</h1>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped></style>

View File

@ -0,0 +1,19 @@
<template>
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1
class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200"
>
用户协议
</h1>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped></style>

View File

@ -0,0 +1,119 @@
<template>
<div class="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-8">
<h1 class="text-3xl font-bold text-center text-blue-600 mb-10 pb-6 border-b border-gray-200">
隐私声明
</h1>
<div class="space-y-8">
<!-- 声明内容 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<p class="text-gray-600 leading-relaxed">
我们重视您的隐私本网站承诺对您的个人信息进行严格保密未经您的许可我们不会向任何第三方透露您的个人信息
</p>
</section>
<!-- 信息收集范围 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
信息收集范围
</h2>
<p class="text-gray-600 mb-4">在您浏览本网站时我们可能会收集以下信息</p>
<ul class="list-disc list-inside text-gray-600 space-y-2">
<li>必要的访问日志IP地址访问时间</li>
<li>浏览器类型操作系统等基本设备信息</li>
<li>访问页面的记录</li>
</ul>
</section>
<!-- 信息用途 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
信息用途
</h2>
<p class="text-gray-600 mb-4">我们收集这些信息的目的是</p>
<ul class="list-disc list-inside text-gray-600 space-y-2">
<li>优化网站性能和用户体验</li>
<li>进行网站安全维护</li>
<li>提供更好的服务支持</li>
</ul>
</section>
<!-- Cookie说明 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
Cookie说明
</h2>
<p class="text-gray-600">
本网站使用Cookie来改善您的浏览体验这些Cookie不会收集您的个人身份信息您可以通过浏览器设置来管理或禁用Cookie
</p>
</section>
<!-- 安全措施 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
安全措施
</h2>
<p class="text-gray-600">
我们采用业界标准的安全措施来保护您的信息安全包括但不限于SSL加密传输数据访问控制等
</p>
</section>
<!-- 免责声明 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
免责声明
</h2>
<p class="text-gray-600">
对于通过本网站链接到的第三方网站我们不对其隐私保护措施负责建议您在访问这些网站时查看其隐私政策
</p>
</section>
<!-- 更新提醒 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
更新提醒
</h2>
<p class="text-gray-600">
我们保留随时更新本隐私声明的权利更新后的声明将在本页面公布请您定期查看
</p>
</section>
<!-- 联系方式 -->
<section class="hover:bg-gray-50 p-6 rounded-lg transition duration-300">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<div class="w-1 h-6 bg-blue-500 rounded mr-3"></div>
联系方式
</h2>
<div class="bg-gray-50 p-6 rounded-lg">
<p class="text-gray-600">如您对本隐私声明有任何疑问请通过以下方式联系我们</p>
<p class="text-gray-600 mt-2">📧 邮箱contact@example.com</p>
</div>
</section>
<!-- 更新日期 -->
<div class="text-right text-gray-500 pt-6 border-t border-gray-200">
最后更新日期2024年3月8日
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "header",
});
</script>
<style scoped>
</style>

View File

@ -0,0 +1,224 @@
<template>
<div>
<div class="p-4 flex text-white gap-3">
<div
class="w-60 h-28 bg-[#a494f7] px-8 py-6 rounded-lg flex flex-col justify-around"
>
<div class="text-xl">累计收入金额</div>
<div class="text-base">¥ {{ totalAmount || 0 }}</div>
</div>
<div
class="w-60 h-28 bg-[#e87988] px-8 py-6 rounded-lg flex flex-col justify-around"
>
<div class="text-xl flex justify-between items-center">
<div>可提现金额</div>
<div
class="text-sm cursor-pointer select-none text-[#524f4f]"
@click="showModal"
>
提现 >
</div>
</div>
<div class="text-base">¥ {{ integralGold.wallet || 0 }}</div>
</div>
</div>
<div class="p-4 text-[#06186d]">
<n-tabs v-model:value="activeTab" type="line" animated>
<!-- <n-tab-pane name="allDetail" tab="全部明细">
<div
class="border border-solid border-gray-200 rounded-lg relative text-[#06186d]"
>
<div class="mc-table flex w-full bg-gray-100 sticky top-0">
<div class="w-[250px]">获取时间</div>
<div class="w-[250px]">获取来源</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">金币值</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getPoints"
>
<div v-for="item in allDetailList" :key="item" class="mc-table flex w-full">
<div class="w-[250px]">
{{ item.orderTime }}
</div>
<div class="w-[250px]">{{ item.productName }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.paymentAmount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane> -->
<n-tab-pane name="withdrawDetail" tab="提现明细">
<div class="border border-solid border-gray-200 rounded-lg relative">
<div class="mc-table flex w-full bg-[#e5ecf4] sticky top-0">
<div class="w-[250px]">提现时间</div>
<div class="w-[250px]">账户类型</div>
<div class="flex-1">详情</div>
<div class="w-[200px]">提现金额</div>
</div>
<n-infinite-scroll
style="height: calc(100vh - 300px)"
:distance="10"
@load="getWithdrawDetail"
>
<div
v-for="item in withdrawDetailList"
:key="item"
class="mc-table flex w-full"
>
<div class="w-[250px]">
{{ item.createTime }}
</div>
<div class="w-[250px]">{{ item.account }}</div>
<div class="flex-1">-</div>
<div class="w-[200px]">
{{ item.amount }}
</div>
</div>
</n-infinite-scroll>
</div>
</n-tab-pane>
</n-tabs>
</div>
<n-modal v-model:show="showWalletModal">
<n-card
style="width: 600px"
:bordered="false"
size="huge"
role="dialog"
aria-modal="false"
preset="dialog"
>
<div class="flex justify-between">
<div class="text-xl">
提现
</div>
<n-icon size="20" class="mr-2 cursor-pointer" @click="closeWalletModal">
<Close />
</n-icon>
</div>
<div class="py-4">
<div class="text-sm text-gray-600">
可提现金额: ¥ {{ integralGold.wallet || 0 }}
</div>
<div class="mt-6">
<n-input-number
placeholder="输入要提现的金额"
v-model:value="needWalletNum"
:precision="2"
clearable
/>
</div>
</div>
<div class="flex justify-center mt-6">
<n-button type="error" @click="closeWalletModal"> </n-button>
<n-button type="primary" class="ml-8" @click="handleWallet"> </n-button>
</div>
</n-card>
</n-modal>
</div>
</template>
<script setup>
import { isAmount } from '@/utils/index.ts';
import { Close } from "@vicons/ionicons5";
import { ref } from "vue";
const activeTab = ref("withdrawDetail");
const showWalletModal = ref(false);
const showModal = () => {
showWalletModal.value = true;
};
const closeWalletModal = () => {
showWalletModal.value = false;
needWalletNum.value = 0
};
// const allDetailList = ref([]);
//
const integralGold = ref({});
async function getIntegralGold() {
try {
const res = await request.post("/personalCenter/getPointAndWallet");
if (res.code === 200) {
integralGold.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getIntegralGold();
//
const needWalletNum = ref(0)
const handleWallet = async() =>{
if(isAmount(needWalletNum.value)){
try {
const res = await request.get(`/ali/pay/fetch?amount=${needWalletNum.value}`);
if (res.code === 200) {
closeWalletModal()
getIntegralGold()
}
} catch (err) {
console.log(err);
}
}else{
message.warning('请输入正确的金额')
}
}
//
const totalAmount = ref(0);
async function getTotalAmount() {
try {
const res = await request.get("/invitation/totalAmount");
if (res.code === 200) {
totalAmount.value = res.data;
}
} catch (err) {
console.log(err);
}
}
getTotalAmount();
//
const withdrawFinished = ref(false);
const withdrawDetailList = ref([]);
const withdrawParams = ref({
pageNum: 1,
pageSize: 10,
});
async function getWithdrawDetail() {
try {
if (withdrawFinished.value) return;
const res = await request.post("/invitation/withdrawalRecord", withdrawParams.value);
if (res.code === 200) {
// withdrawDetailList.value = res.data;
if (withdrawParams.value.pageNum === 1) {
withdrawDetailList.value = res.rows;
} else {
withdrawDetailList.value = [...withdrawDetailList.value, ...res.rows];
}
//
if (withdrawDetailList.value.length >= res.total) {
withdrawFinished.value = true;
}
withdrawParams.value.pageNum++;
}
} catch (err) {
console.log(err);
}
}
getWithdrawDetail();
</script>
<style scoped>
.mc-table {
padding: 10px;
line-height: 40px;
border-bottom: 1px solid #eee;
}
</style>

View File

@ -109,7 +109,7 @@ function changeCategory(item: any) {
</MenuFold> </MenuFold>
</div> </div>
</div> </div>
<div class="flex flex-wrap"> <div class="w-full">
<NConfigProvider> <NConfigProvider>
<NMessageProvider> <NMessageProvider>
<WorkFlowList ref="listRef" :params="params" /> <WorkFlowList ref="listRef" :params="params" />

View File

@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup>
import { commonApi } from "@/api/common"; import { commonApi } from "@/api/common";
import { formatFileSize } from '@/utils/index.ts';
import { Close, DiamondSharp, PersonAddOutline } from '@vicons/ionicons5'; import { Close, DiamondSharp, PersonAddOutline } from '@vicons/ionicons5';
import { import {
CircleUser, CircleUser,
Download, Download,
EllipsisVertical, Heart, Play EllipsisVertical, Heart, Play, SquareCheck, SquarePlus
} from 'lucide-vue-next'; } from 'lucide-vue-next';
// import { NConfigProvider, NMessageProvider } from 'naive-ui'; // import { NConfigProvider, NMessageProvider } from 'naive-ui';
import { nextTick, ref } from 'vue'; import { nextTick, ref } from 'vue';
@ -20,11 +21,11 @@ definePageMeta({
}) })
// const userStore = useUserStore() // const userStore = useUserStore()
const route = useRoute() const route = useRoute()
const { id } = route.params as { id: string } const { id } = route.params
const activeTab = ref(null) const activeTab = ref(null)
const commentHeight = ref(800) const commentHeight = ref(800)
const detailsInfo = ref({}) const detailsInfo = ref({})
const currentUserInfo = ref<any>({}) const currentUserInfo = ref({})
const isVisibleReport = ref(false); const isVisibleReport = ref(false);
// //
@ -74,13 +75,13 @@ async function getInfo() {
getInfo() getInfo()
// // // //
interface SelectUserInfo { // interface SelectUserInfo {
likeCount: number // likeCount: number
bean: number // bean: number
download: number // download: number
attention: number // attention: number
} // }
const selectUserInfo = ref<SelectUserInfo>({ const selectUserInfo = ref({
likeCount: 0, likeCount: 0,
bean: 0, bean: 0,
download: 0, download: 0,
@ -102,8 +103,7 @@ async function getAttention() {
// // // //
const isDelete = ref(false) const isDelete = ref(false)
async function handleSelect(event: Event, type: string) { async function handleSelect(type) {
event.stopPropagation() //
if (type === 'report') { if (type === 'report') {
// await request.get(`/WorkFlow/report?id=${id}`) // // await request.get(`/WorkFlow/report?id=${id}`) //
isVisibleReport.value = true; isVisibleReport.value = true;
@ -195,7 +195,7 @@ async function getDictType() {
} }
} }
getDictType(); getDictType();
function handleChange(item: any) { function handleChange(item) {
reportParams.value.reportId = item.dictValue; reportParams.value.reportId = item.dictValue;
if (item.dictValue !== "5") { if (item.dictValue !== "5") {
reportParams.value.text = ""; reportParams.value.text = "";
@ -230,6 +230,50 @@ function toPersonalCenter(){
window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer') window.open(`${baseUrl}/personal-publish?userId=${detailsInfo.value.userId}`, '_blank', 'noopener,noreferrer')
} }
} }
const currentTabsIndex = ref(0);
function handleTabChange(id) {
for (let i = 0; i < versionByWorkInfo.value.length; i++) {
if (id === versionByWorkInfo.value[i].id) {
currentTabsIndex.value = i;
}
}
}
async function addCollect(){
try {
const params = {
"productId": versionByWorkInfo.value[currentTabsIndex.value].id,
"productType": 1,
}
const res = await request.post("/collect/addCollect", params);
if (res.code === 200) {
versionByWorkInfo.value[currentTabsIndex.value].isCollect = res.data
if(res.data === 0){
message.success("已加入收藏");
}else{
message.success("已取消收藏");
}
}
} catch (err) {
console.log(err);
}
}
async function handelDown(){
try {
const res = await request.get(`/WorkFlowVersion/workFlowFileDownload?id=${versionByWorkInfo.value[currentTabsIndex.value].id}`);
if (res.code === 200) {
const link = document.createElement('a');
link.href = res.data;
link.download = res.msg; //
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
} catch (err) {
console.log(err);
}
}
</script> </script>
<template> <template>
@ -290,7 +334,9 @@ function toPersonalCenter(){
<div class="flex w-full gap-1"> <div class="flex w-full gap-1">
<div class="w-2/3"> <div class="w-2/3">
<div class="w-full"> <div class="w-full">
<n-tabs v-model:value="activeTab" type="line" animated> <n-tabs v-model:value="activeTab" type="line" animated
@update:value="handleTabChange"
>
<n-tab-pane <n-tab-pane
v-for="(item, index) in versionByWorkInfo" v-for="(item, index) in versionByWorkInfo"
:key="index" :key="index"
@ -462,7 +508,7 @@ function toPersonalCenter(){
<span class="mr-1"> 立即生图 </span> <span class="mr-1"> 立即生图 </span>
</div> </div>
<div <!-- <div
class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer hover:bg-[#f1f2f7]" class="flex items-center justify-center mt-4 w-full h-14 text-black bg-[#eceef4] w-full rounded-md h-[50px] cursor-pointer hover:bg-[#f1f2f7]"
> >
<component <component
@ -470,8 +516,37 @@ function toPersonalCenter(){
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/> />
<span class="mr-1"> 下载 (122.22MB) </span> <span class="mr-1"> 下载 (122.22MB) </span>
</div> </div> -->
<div class="flex gap-y-2">
<div
v-if="versionByWorkInfo.length > 0"
@click="addCollect"
class="flex flex-1 items-center justify-center bg-[#eceef4] h-[50px] mt-4 mr-1 rounded-md cursor-pointer"
>
<component
:is="
versionByWorkInfo[currentTabsIndex].isCollect === 1
? SquarePlus
: SquareCheck
"
class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]"
/>
<span class="mr-1">
{{ versionByWorkInfo[currentTabsIndex].isCollect === 1 ? '加入收藏' : '已收藏'}}
</span>
</div>
<div
@click="handelDown"
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" v-if="versionByWorkInfo.length > 0"> {{ formatFileSize(versionByWorkInfo[currentTabsIndex].fileSize) }} </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]"> <!-- <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]" /> <component :is="Download" class="h-[20px] w-[20px] text-black menu-icon m-1 text-[#969798]" />
<span class="mr-1"> <span class="mr-1">
@ -486,7 +561,7 @@ function toPersonalCenter(){
content="确定要将工作流删除? 工作流删除后无法找回" content="确定要将工作流删除? 工作流删除后无法找回"
negative-text="取消" negative-text="取消"
positive-text="确认" positive-text="确认"
@negative-click="onDelete" @negative-click="isDelete = false"
@positive-click="onDelete" @positive-click="onDelete"
/> />
@ -550,7 +625,7 @@ function toPersonalCenter(){
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss" scoped>
.header-num { .header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full; @apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
} }

View File

@ -24,7 +24,9 @@ export const useUserStore = defineStore('user', () => {
function setUserInfo(info: any) { function setUserInfo(info: any) {
userInfo.value = info userInfo.value = info
debugger if(!info.avatar){
userInfo.value.avatar = defaultAvatar
}
} }
async function getUserInfo() { async function getUserInfo() {
const res = await request.get('/system/user/selectUserById', { const res = await request.get('/system/user/selectUserById', {
@ -37,7 +39,6 @@ export const useUserStore = defineStore('user', () => {
} }
// 登出 // 登出
function logout() { function logout() {
console.log('object-------out');
isLoggedIn.value = false isLoggedIn.value = false
token.value = '' token.value = ''
userInfo.value = {} as UserInfoType userInfo.value = {} as UserInfoType
@ -97,11 +98,9 @@ export const useUserStore = defineStore('user', () => {
// actions: { // actions: {
// setToken(token: string) { // setToken(token: string) {
// this.token = token // this.token = token
// debugger
// }, // },
// setUserInfo(userInfo: Record<string, any>) { // setUserInfo(userInfo: Record<string, any>) {
// this.userInfo = userInfo // this.userInfo = userInfo
// debugger
// }, // },
// // logout() { // // logout() {
// // getLogout().then(() => { // // getLogout().then(() => {

View File

@ -5,3 +5,24 @@ export async function formatDate(timestamp: string) {
const day = String(date.getDate()).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}` return `${year}-${month}-${day}`
} }
export function formatFileSize(bytes:number = 0, decimals = 2) {
if (bytes === 0) return '0 B';
const k = 1024; // 1 KB = 1024 B
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算单位索引
// 转换为合适的单位并保留指定小数位数
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
}
export function isAmount(str:any) {
const amountRegex = /^\d+(\.\d{1,2})?$/;
return amountRegex.test(str);
}
// function isAmount(str) {
// // 正则表达式
// }

View File

@ -3,7 +3,6 @@ import { useModalStore } from '@/stores/modal.ts';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios'; import axios from 'axios';
import { createDiscreteApi } from 'naive-ui'; import { createDiscreteApi } from 'naive-ui';
const { message, loadingBar } = createDiscreteApi(['message', 'loadingBar']) const { message, loadingBar } = createDiscreteApi(['message', 'loadingBar'])
// 定义响应数据接口 // 定义响应数据接口
@ -105,7 +104,7 @@ class RequestHttp {
message.error('请求参数错误') message.error('请求参数错误')
break break
case 401: case 401:
// message.error('未登录或登录已过期') message.error('未登录或登录已过期')
break break
case 403: case 403:
message.error('没有权限') message.error('没有权限')

View File

@ -28,9 +28,9 @@ export default defineNuxtConfig({
head: { head: {
viewport: 'width=device-width,initial-scale=1', viewport: 'width=device-width,initial-scale=1',
link: [ link: [
{ rel: 'icon', href: '/favicon.ico', sizes: 'any' }, // { rel: 'icon', href: '/favicon.ico', sizes: 'any' },
{ rel: 'icon', type: 'image/svg+xml', href: '/nuxt.svg' }, // { rel: 'icon', type: 'image/svg+xml', href: '/nuxt.svg' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' }, // { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
], ],
meta: [ meta: [
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' },
@ -80,11 +80,12 @@ export default defineNuxtConfig({
compatibilityDate: '2025-01-23', compatibilityDate: '2025-01-23',
nitro: { nitro: {
preset: 'node-server',
devProxy: { devProxy: {
'/api': { '/api': {
// target: 'http://1.13.246.108:8080', // 线上 // target: 'http://1.13.246.108:8080', // 线上
// target: 'http://192.168.2.10:8080', // 代 target: 'http://192.168.2.10:8080', // 代
target: 'http://192.168.2.7:8080', // 嗨 // target: 'http://192.168.2.7:8080', // 嗨
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨 // target: 'https://2d1a399f.r27.cpolar.top', // 嗨
changeOrigin: true, changeOrigin: true,
prependPath: true, prependPath: true,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/favicon1.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/favicon2.ico 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B