邀请码功能

planet
shenhan 2025-03-05 13:37:24 +08:00
parent f2d8f098e6
commit 1717d5abba
18 changed files with 593 additions and 248 deletions

1
app/components.d.ts vendored
View File

@ -26,6 +26,7 @@ declare module 'vue' {
NInputGroup: typeof import('naive-ui')['NInputGroup']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
NQrCode: typeof import('naive-ui')['NQrCode']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']

View File

@ -1,23 +1,23 @@
<script setup lang="ts">
import type { FormInst } from 'naive-ui';
import { ref } from 'vue';
import { uploadImagesInBatches } from '../utils/uploadImg.ts';
const userStore = useUserStore()
const userInfo = userStore.userInfo
const message = useMessage()
const ruleForm = ref({})
function onShowModel() {
ruleForm.value.nickName = userInfo.nickName
ruleForm.value.avatar = userInfo.avatar
ruleForm.value.brief = userInfo.brief
ruleForm.value.userId = userInfo.userId
}
// function onShowModel() {
// ruleForm.value.nickName = userInfo.nickName
// ruleForm.value.avatar = userInfo.avatar
// ruleForm.value.brief = userInfo.brief
// ruleForm.value.userId = userInfo.userId
// }
const rules = ref({
nickName: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 12, message: '长度在 3 到 12 个字符', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' },
],
})
//
@ -52,24 +52,37 @@ async function handlePictureChange(event: Event) {
message.error('图片上传失败')
}
}
const formRef = ref<FormInst | null>(null)
async function saveInfo() {
const res = await request.post('/system/user/updateUserInfo', ruleForm.value)
const data = await userStore.getUserInfo()
onCloseModel()
formRef.value?.validate(async(errors:any) => {
if (!errors) {
const res1 = await request.post('/system/user/updateUserInfo', ruleForm.value)
if(res1.code === 200){
const res = await request.get('/system/user/selectUserById')
if (res.code === 200) {
message.success('修改成功!')
userStore.setUserInfo(res.data)
onCloseModel()
}
}
}
})
}
watch(
() => userStore.userInfo, // userInfo
(newUserInfo) => {
(newUserInfo:any) => {
if (newUserInfo) {
ruleForm.value.nickName = newUserInfo.nickName
ruleForm.value.avatar = newUserInfo.avatar
ruleForm.value.brief = newUserInfo.brief
ruleForm.value.userId = newUserInfo.userId
// ruleForm.value.invitationName = newUserInfo.invitationName
}
},
{ immediate: true }, // ruleForm
{ immediate: true, deep: true }, // ruleForm
)
const isVisible = ref(false)
@ -115,6 +128,15 @@ onMounted(() => {
<n-form-item path="nickName" label="用户名">
<n-input v-model:value="ruleForm.nickName" placeholder="请输入用户名" @keydown.enter.prevent />
</n-form-item>
<div v-if="userInfo.invitationName" class="mb-3">
已经填写: {{ userInfo.invitationName }} 的邀请码
</div>
<!-- <n-form-item v-if="userInfo.invitationName" path="invitationCode">
</n-form-item> -->
<n-form-item v-else path="invitationCode" label="邀请码">
<n-input v-model:value="ruleForm.invitationName" placeholder="请输入邀请码" @keydown.enter.prevent />
</n-form-item>
<n-form-item label="简介" path="textareaValue">
<n-input
v-model:value="ruleForm.brief"

View File

@ -1,7 +1,7 @@
<!-- components/SearchInput.vue -->
<script setup>
import { CloseCircle } from "@vicons/ionicons5";
import { Camera, Search } from "lucide-vue-next";
import { Search } from "lucide-vue-next";
import { computed } from 'vue';
import { useRoute } from "vue-router";
const modalStore = useModalStore();
@ -29,7 +29,6 @@ function handleSearch() {
if (route.path !== "/search") {
const baseUrl = window.location.origin;
const type = searchType.value[route.path]
debugger
window.open(
`${baseUrl}/search?keyword=${keyword.value}&type=${type}`,
"_blank",
@ -79,7 +78,7 @@ watch(searchQuery, (newValue) => {
</n-icon>
</div>
<Camera class="h-5 w-5 text-gray-400 mr-3 cursor-pointer" />
<!-- <Camera class="h-5 w-5 text-gray-400 mr-3 cursor-pointer" /> -->
<Search class="h-5 w-5 text-gray-400 mr-3 cursor-pointer" @click="handleSearch" />
</div>
</template>

View File

@ -116,11 +116,8 @@ function closePublishImg() {
<div>
<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="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>
<div class="my-3">
点击上传文件
<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>
<!-- <div class="text-[#999999] text-xs">
.json/.zip

View File

@ -53,7 +53,7 @@ async function getDictType() {
const [res1, res2, res3, res4] = await Promise.all([
commonApi.dictType({ type: 'model_part_category' }),
commonApi.dictType({ type: 'model_child_category' }),
commonApi.dictType({ type: 'model_category' }),
commonApi.dictType({ type: 'model_type' }),
commonApi.dictType({ type: 'work_flow_functions' }),
])

View File

@ -1,11 +1,12 @@
<script setup lang="ts">
import { commonApi } from "@/api/common";
import { uploadImagesInBatches } from "@/utils/uploadImg.ts";
import { cloneDeep } from 'lodash-es';
import { uploadFileBatches } from "@/utils/uploadImg.ts";
import { cloneDeep } from "lodash-es";
import { Asterisk, Trash } from "lucide-vue-next";
import type { FormInst } from "naive-ui";
import { computed, ref, watch } from "vue";
const message = useMessage()
const message = useMessage();
//
const props = defineProps({
@ -18,16 +19,18 @@ const emit = defineEmits(["update:modelValue", "nextStep", "prevStep"]);
const acceptTypes =
".safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft";
const modelVersionItem = {
delFlag: '0', // 0 2
objectKey:null,
isEncrypt: 0, //0
delFlag: "0", // 0 2
versionName: "", //
modelVersionType: null, //
versionDescription: "", //
filePath: "", //
fileName: "", //
sampleImagePaths:[], // 20,
sampleImagePaths: [], // 20,
triggerWords: "", //
isPublic: 1, //
isOnlineUse:1, //线使
isOnlineUse: 1, //线使
allowFusion: 1, //
isFree: 0, // 0
allowDownloadImage: 1, //
@ -35,8 +38,8 @@ const modelVersionItem = {
allowCommercialUse: 1, //
allowUsage: 1, //
isExclusiveModel: 1, //
hideImageGenInfo:0, //
id:null
hideImageGenInfo: 0, //
id: null,
};
const isPublicList = [
{
@ -88,7 +91,7 @@ const rules = {
},
};
function addVersion() {
const param = cloneDeep(modelVersionItem)
const param = cloneDeep(modelVersionItem);
localForm.value.modelVersionList.unshift(param);
}
const originalBtnList = ref([
@ -144,13 +147,28 @@ async function handleFileChange(event: Event) {
const files = target.files;
if (files && files.length > 0) {
try{
const res = await uploadImagesInBatches(files);
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].url;
localForm.value.modelVersionList[uploadFileIndex.value].fileName = res[0].fileName;
}catch(err){
const { name, size} = files[0] as { name: string, size: number};
try {
// 0 1
const res1 = await request.get(`/file/selectFile?type=model&name=${name}`);
if (res1.code == 200) {
if (res1.data === 1) {
try {
const res = await uploadFileBatches(files);
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].path;
localForm.value.modelVersionList[uploadFileIndex.value].objectKey = res[0].objectKey;
localForm.value.modelVersionList[uploadFileIndex.value].fileName = name;
localForm.value.modelVersionList[uploadFileIndex.value].fileSize = size
} catch (err) {
console.log(err);
}
} else {
message.warning("该模型名称已存在");
}
}
} catch (err) {
console.log(err);
}
}
}
target.value = "";
}
@ -162,7 +180,7 @@ function prevStep() {
const baseModelTypeList = ref([]);
async function getDictType() {
try {
const res = await commonApi.dictType({ type: "mode_type" });
const res = await commonApi.dictType({ type: "mode_version_type" });
if (res.code === 200) {
baseModelTypeList.value = res.data;
}
@ -173,12 +191,11 @@ async function getDictType() {
getDictType();
function computedDelFlag() {
return localForm.value.modelVersionList.filter(item => item.delFlag === '0')
return localForm.value.modelVersionList.filter((item) => item.delFlag === "0");
}
function onDelete(index: number) {
if (computedDelFlag().length === 1)
return
localForm.value.modelVersionList[index].delFlag = '2'
if (computedDelFlag().length === 1) return;
localForm.value.modelVersionList[index].delFlag = "2";
}
</script>
@ -191,8 +208,8 @@ function onDelete(index: number) {
>
<div v-if="item.delFlag === '0'" class="bg-gray-100 p-4 rounded-lg mt-4 relative">
<div class="absolute -right-10 top-4 cursor-pointer">
<Trash class="cursor-pointer" @click="onDelete(index)" />
</div>
<Trash class="cursor-pointer" @click="onDelete(index)" />
</div>
<n-form
:ref="(el) => setFormRef(el, index)"
:label-width="80"
@ -212,8 +229,18 @@ function onDelete(index: number) {
:options="baseModelTypeList"
/>
</n-form-item>
<div class="flex">
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
<div class="flex items-center justify-between">
<div class="flex">
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div>
<n-checkbox
v-model:checked="item.isEncrypt"
:checked-value="1"
:unchecked-value="0"
label="是否加密"
/>
</div>
</div>
<div
v-if="item.fileName"
@ -402,19 +429,19 @@ function onDelete(index: number) {
</div>
</template>
<div class="flex items-center justify-center mt-5">
<div
class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer"
@click="prevStep"
>
上一步
</div>
<div
class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer"
@click="nextStep"
>
下一步
</div>
<div
class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer"
@click="prevStep"
>
上一步
</div>
<div
class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer"
@click="nextStep"
>
下一步
</div>
</div>
</div>
<input
ref="fileInput"

View File

@ -151,7 +151,7 @@ function onPositiveClick() {
上传文件
</div>
<div class="my-3">
点击上传文件
点击上传图片
</div>
<div class="text-[#999999] text-xs">
请勿上传裸露暴力血腥或其他包含非法信息图片

View File

@ -1,11 +1,9 @@
<script setup lang="ts">
// import { uploadFileBatches } from '@/utils/uploadImg.ts';
import { uploadImagesInBatches } from '@/utils/uploadImg.ts';
import { cloneDeep } from 'lodash-es';
import { Asterisk, Trash } from 'lucide-vue-next';
import type { FormInst } from 'naive-ui';
import { computed, ref, watch } from 'vue';
import { uploadFileBatches } from "@/utils/uploadImg.ts";
import { cloneDeep } from "lodash-es";
import { Asterisk, Trash } from "lucide-vue-next";
import type { FormInst } from "naive-ui";
import { computed, ref, watch } from "vue";
//
const props = defineProps({
@ -13,81 +11,86 @@ const props = defineProps({
type: Object,
required: true,
},
})
const emit = defineEmits(['update:modelValue', 'nextStep', 'preStep'])
});
const emit = defineEmits(["update:modelValue", "nextStep", "preStep"]);
const localForm = computed({
get() {
return props.modelValue
return props.modelValue;
},
set(value) {
emit('update:modelValue', value)
emit("update:modelValue", value);
},
})
});
watch(
() => localForm.value,
(newVal) => {
console.log('newVal', newVal)
emit('update:modelValue', newVal)
(newVal:any) => {
console.log("newVal", newVal);
emit("update:modelValue", newVal);
},
{ immediate: true, deep: true },
)
const message = useMessage()
{ immediate: true, deep: true }
);
const message = useMessage();
const acceptTypes = '.json,.zip'
const acceptTypes = ".json,.zip";
defineExpose({
addVersion,
})
});
const modelVersionItem = {
versionName: '',
versionDescription: '', //
filePath: '', //
fileName: '', //
delFlag: '0',
versionName: "",
versionDescription: "", //
filePath: "", //
fileName: "", //
delFlag: "0",
imagePaths: [],
id:null
}
id: null,
};
const rules = {
versionName: {
required: true,
message: '',
trigger: 'blur',
message: "",
trigger: "blur",
},
}
};
function addVersion() {
const param = cloneDeep(modelVersionItem)
localForm.value.workFlowVersionList.unshift(param)
const param = cloneDeep(modelVersionItem);
localForm.value.workFlowVersionList.unshift(param);
}
const formRefs = ref<(FormInst | null)[]>([])
const formRefs = ref<(FormInst | null)[]>([]);
function setFormRef(el: FormInst | null, index: number) {
if (el) {
formRefs.value[index] = el
formRefs.value[index] = el;
}
}
async function nextStep() {
for (let i = 0; i < localForm.value.workFlowVersionList.length; i++) {
if (localForm.value.workFlowVersionList[i].delFlag === '0' && localForm.value.workFlowVersionList[i].fileName === '') {
return message.error('请上传文件')
if (
localForm.value.workFlowVersionList[i].delFlag === "0" &&
localForm.value.workFlowVersionList[i].fileName === ""
) {
return message.error("请上传文件");
}
const regex = /[\u4E00-\u9FA5]/ //
if (localForm.value.workFlowVersionList[i].delFlag === '0' && !regex.test(localForm.value.workFlowVersionList[i].versionDescription)) {
return message.error('请用中文填写版本介绍')
const regex = /[\u4E00-\u9FA5]/; //
if (
localForm.value.workFlowVersionList[i].delFlag === "0" &&
!regex.test(localForm.value.workFlowVersionList[i].versionDescription)
) {
return message.error("请用中文填写版本介绍");
}
}
try {
const promises = formRefs.value
.filter((form): form is FormInst => form !== null)
.map(form => form.validate())
.filter((form:any): form is FormInst => form !== null)
.map((form:any) => form.validate());
await Promise.all(promises)
emit('nextStep')
}
catch (errors) {
console.error('部分表单验证失败:', errors)
await Promise.all(promises);
emit("nextStep");
} catch (errors) {
console.error("部分表单验证失败:", errors);
}
// formRef.value?.validate((errors) => {
// if (!errors) {
@ -99,41 +102,52 @@ async function nextStep() {
// })
}
function preStep() {
emit('preStep')
emit("preStep");
}
//
const uploadFileIndex = ref(0)
const fileInput = ref<HTMLInputElement | null>(null)
const uploadFileIndex = ref(0);
const fileInput = ref<HTMLInputElement | null>(null);
function triggerFileInput(index: number) {
(fileInput.value as HTMLInputElement)?.click()
uploadFileIndex.value = index
(fileInput.value as HTMLInputElement)?.click();
uploadFileIndex.value = index;
}
async function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement
const files = target.files
const target = event.target as HTMLInputElement;
const files = target.files;
if (files && files.length > 0) {
try{
const res = await uploadImagesInBatches(files)
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].url
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = res[0].fileName
}catch(err){
const { name , size} = files[0] as { name: string, size: number};
try {
const res1 = await request.get(`/file/selectFile?type=workflow&name=${name}`);
if (res1.code == 200) {
if (res1.data === 1) {
//0 1
try {
const res = await uploadFileBatches(files);
localForm.value.workFlowVersionList[uploadFileIndex.value].filePath = res[0].path;
localForm.value.workFlowVersionList[uploadFileIndex.value].objectKey = res[0].objectKey;
localForm.value.workFlowVersionList[uploadFileIndex.value].fileName = name
localForm.value.workFlowVersionList[uploadFileIndex.value].fileSize = size
} catch (err) {
console.log(err);
}
} else {
message.error("该工作流名称已存在");
}
}
} catch (err) {
console.log(err);
}
// if(res[0].success){
// }
}
target.value = ''
target.value = "";
}
function computedDelFlag() {
return localForm.value.workFlowVersionList.filter(item => item.delFlag === '0')
return localForm.value.workFlowVersionList.filter((item:any) => item.delFlag === "0");
}
function onDelete(index: number) {
if (computedDelFlag().length === 1)
return
localForm.value.workFlowVersionList[index].delFlag = '2'
if (computedDelFlag().length === 1) return;
localForm.value.workFlowVersionList[index].delFlag = "2";
}
</script>
@ -146,7 +160,7 @@ function onDelete(index: number) {
<Trash class="cursor-pointer" @click="onDelete(index)" />
</div>
<n-form
:ref="(el) => setFormRef(el, index)"
:ref="(el:any) => setFormRef(el, index)"
:label-width="80"
:model="localForm.workFlowVersionList[index]"
:rules="rules"
@ -169,31 +183,38 @@ function onDelete(index: number) {
<div class="flex mt-4">
上传文件 <Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div v-if="item.fileName" class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg">
<div class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center">
<div
v-if="item.fileName"
class="flex justify-between items-center bg-white p-3 mt-2 rounded-lg"
>
<div
class="bg-[#d8e5fd] text-[12px] text-[#3162ff] w-16 h-7 rounded-lg flex justify-center items-center"
>
100%
</div>
<div class="flex-1 flex items-center line-clamp">
{{
item.fileName
}}
{{ item.fileName }}
</div>
<div>
<Trash class="cursor-pointer" @click="item.fileName = '', item.filePath = ''" />
<Trash
class="cursor-pointer"
@click="(item.fileName = ''), (item.filePath = '')"
/>
</div>
</div>
<div v-else>
<div class="upload-content">
<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="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>
<div class="my-3">
点击上传文件
</div>
<div class="text-[#999999] text-xs">
.json/.zip
</div>
<div class="my-3">点击上传文件</div>
<div class="text-[#999999] text-xs">.json/.zip</div>
</div>
</div>
</div>
@ -201,10 +222,16 @@ function onDelete(index: number) {
</div>
</template>
<div class="flex items-center justify-center mt-5">
<div class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer" @click="preStep">
<div
class="flex justify-center items-center mt-5 w-[20%] mx-2 h-10 rounded-lg bg-[#f1f2f7] cursor-pointer"
@click="preStep"
>
上一步
</div>
<div class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
<div
class="flex justify-center items-center mt-5 text-white mx-2 w-[20%] h-10 rounded-lg bg-[#3162ff] cursor-pointer"
@click="nextStep"
>
下一步
</div>
</div>
@ -217,7 +244,7 @@ function onDelete(index: number) {
class="hidden"
:accept="acceptTypes"
@change="handleFileChange"
>
/>
</template>
<style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { nextTick, onMounted } from 'vue'
import { nextTick, onMounted } from 'vue';
definePageMeta({
layout: 'header',
@ -18,6 +18,7 @@ async function getPoints() {
const res = await request.get('/member/getPoints')
if (res.code === 200) {
pointsResult.value = res.data as PointsResult
debugger
nextTick(() => {
activeTab.value = 'beatles'
})
@ -98,7 +99,7 @@ onMounted(() => {
{{ item.consumeTime }}
</div>
<div class="w-[250px]">
每日赠送算力清零
生图
</div>
<div class="flex-1">
-

View File

@ -35,7 +35,6 @@ async function getInfo() {
if (res.code === 200) {
detailsInfo.value = res.data;
detailsInfo.value.styleList = JSON.parse(res.data.styleList);
debugger
// detailsInfo.value.styleList =JSON.parse(res.data.styleList)
// // 1
try {

View File

@ -75,7 +75,7 @@ function onInputSearch(){
/>
<!-- 相机图标 -->
<button class="absolute right-24 p-2 mr-2 text-gray-400 hover:text-gray-600">
<!-- <button class="absolute right-24 p-2 mr-2 text-gray-400 hover:text-gray-600">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
@ -96,7 +96,7 @@ function onInputSearch(){
d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</button>
</button> -->
<!-- 搜索按钮 -->
<button

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Close } from "@vicons/ionicons5";
const message = useMessage()
const message = useMessage();
import { commonApi } from "@/api/common";
import EditUserInfo from "@/components/EditUserInfo.vue";
@ -95,17 +95,18 @@ function initLikesParams() {
const urlList = ref({
mallProduct: {
0: "/model/selectByUserIdModel",
1: "/model/selectByUserIdWorkFlow",
2: "/model/selectByUserIdImage",
0: "/personalCenter/selectByUserIdModel",
1: "/personalCenter/selectByUserIdWorkFlow",
2: "/personalCenter/selectByUserIdImage",
},
like: {
0: "/model/likeModel",
1: "/model/likeWorkFlow",
2: "/model/likeImage",
0: "/personalCenter/likeModel",
1: "/personalCenter/likeWorkFlow",
2: "/personalCenter/likeImage",
},
});
const showInvitationModal = ref(false);
//
const statusOptions = ref([]);
@ -164,16 +165,16 @@ function changeTabs(id: string) {
// //
function changeType(id: string) {
if(id === '2'){
statusOptions.value.forEach(item => {
if(item.dictValue === '2'){
item.disabled = true
if (id === "2") {
statusOptions.value.forEach((item) => {
if (item.dictValue === "2") {
item.disabled = true;
}
});
}else{
statusOptions.value.forEach(item => {
if(item.dictValue === '2'){
item.disabled = false
} else {
statusOptions.value.forEach((item) => {
if (item.dictValue === "2") {
item.disabled = false;
}
});
}
@ -216,8 +217,6 @@ async function changeDate(value: string[]) {
initPageNUm();
}
// //
interface SelectUserInfo {
likeCount: number;
@ -357,17 +356,17 @@ function onClearDate() {
}
//
const isShowFan = ref(false)
const isShowFan = ref(false);
const attentionFinished = ref(false)
const attentionFinished = ref(false);
const attentionList = ref([]);
const attentionListParams = ref({
pageNumber: 1,
pageSize: 15,
});
async function getAttentionList() {
try{
if(attentionFinished.value) return
try {
if (attentionFinished.value) return;
const res = await request.post(`/attention/selectToAttention`, {
...attentionListParams.value,
});
@ -380,10 +379,10 @@ async function getAttentionList() {
total.value = res.data.total; //
//
if ( attentionList.value.length >= total.value) {
if (attentionList.value.length >= total.value) {
attentionFinished.value = true;
}
attentionListParams.value.pageNumber++
attentionListParams.value.pageNumber++;
}
} catch (err) {
attentionList.value = [];
@ -394,15 +393,15 @@ async function getAttentionList() {
getAttentionList();
//
const likeFinished = ref(false)
const likeFinished = ref(false);
const likeList = ref([]);
const likeListParams = ref({
pageNumber: 1,
pageSize: 15,
});
async function getLikeList() {
try{
if(likeFinished.value) return
try {
if (likeFinished.value) return;
const res = await request.post(`/attention/selectAttentionList`, {
...likeListParams.value,
});
@ -415,10 +414,10 @@ async function getLikeList() {
total.value = res.data.total; //
//
if ( likeList.value.length >= total.value) {
if (likeList.value.length >= total.value) {
likeFinished.value = true;
}
likeListParams.value.pageNumber++
likeListParams.value.pageNumber++;
}
} catch (err) {
likeList.value = [];
@ -429,25 +428,178 @@ async function getLikeList() {
getLikeList();
function closefanList() {
isShowFan.value = false
isShowFan.value = false;
}
// /
async function onAttention(item:any){
async function onAttention(item: any) {
try {
const res = await request.get(`/attention/addAttention?userId=${item.userId}`);
if (res.code === 200) {
if(res.data){
message.success('关注成功')
}else{
message.success('取消关注成功')
if (res.data) {
message.success("关注成功");
} else {
message.success("取消关注成功");
}
item.attention = !item.attention
item.attention = !item.attention;
}
} catch (err) {
console.log(err);
}
}
//
const invitationCode = ref("");
async function getInvitation() {
try {
const res = await request.get(`/invitation/getInvitationCode`);
if (res.code === 200) {
invitationCode.value = res.msg;
}
} catch (err) {
console.log(err);
}
}
getInvitation();
//
// async function getInvitationList() {
// }
//
function copyToClipboard(text: string) {
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
const success = document.execCommand("copy");
document.body.removeChild(textarea);
if (success) {
message.success("复制成功!");
} else {
message.success("复制成功!");
}
}
//
function handlePositiveClick() {
copyToClipboard(invitationCode.value);
}
const activeTab = ref('like')
//
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() {
try {
const res = await request.get(`/invitation/earningsDisplay`);
if (res.code === 200) {
invitationList.value = res.data
showInvitationModal.value = true;
}
} catch (err) {
console.log(err);
}
}
const showLike = (type:string) =>{
isShowFan.value= true
activeTab.value = type
}
</script>
<template>
@ -495,6 +647,21 @@ async function onAttention(item:any){
>
去实名
</div>
<div>
<n-popconfirm
class="bg-white ml-2"
positive-text="复制邀请码"
negative-text="查看列表"
:show-icon="false"
@positive-click="handlePositiveClick"
@negative-click="handleNegativeClick"
>
<template #trigger>
<n-button class="ml-2 rounded-lg" type="info" round>获取邀请码</n-button>
</template>
邀请码: {{ invitationCode }}
</n-popconfirm>
</div>
</div>
<!-- User Details -->
@ -509,8 +676,7 @@ async function onAttention(item:any){
<div class="production-state mt-4 flex text-sm text-gray-700">
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
@click="showLike('like')"
>
<span class="production-state-number font-bold">{{
selectUserInfo.bean ? selectUserInfo.bean : 0
@ -519,8 +685,7 @@ async function onAttention(item:any){
</div>
<div
class="production-state-item mr-5 cursor-pointer"
@click="isShowFan = true"
@click="showLike('attention')"
>
<span class="production-state-number font-bold">{{
selectUserInfo.attention ? selectUserInfo.attention : 0
@ -651,67 +816,136 @@ async function onAttention(item:any){
<div v-if="finished" class="text-center text-gray-500"></div>
</div>
<div class="fan-centent" v-if="isShowFan">
<div
class="w-[550px] h-[calc(100vh-100px)] max-h-[700px] m-auto py-0 px-8 pb-[43px] bg-[#fff] rounded-lg relative"
>
<n-icon size="20" class="mr-2 cursor-pointer absolute top-4 right-2" @click="closefanList">
<Close />
</n-icon>
<n-tabs
v-model:value="activeTab"
default-value="like"
justify-content="space-evenly"
type="line"
>
<n-tab-pane name="like" :tab="`粉丝${selectUserInfo.bean || 0}`">
<n-infinite-scroll style="height: calc(100vh - 200px);padding:0 10px" :distance="10" @load="getAttentionList">
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<div
class="w-[550px] h-[calc(100vh-100px)] max-h-[700px] m-auto py-0 px-8 pb-[43px] bg-[#fff] rounded-lg relative"
>
<n-icon
size="20"
class="mr-2 cursor-pointer absolute top-4 right-2"
@click="closefanList"
>
<Close />
</n-icon>
<n-tabs
v-model:value="activeTab"
default-value="like"
justify-content="space-evenly"
type="line"
>
<n-tab-pane name="like" :tab="`粉丝${selectUserInfo.bean || 0}`">
<n-infinite-scroll
style="height: calc(100vh - 200px); padding: 0 10px"
:distance="10"
@load="getAttentionList"
>
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<div
v-for="(item, index) in attentionList"
:key="index"
class="flex justify-between items-center p-2"
>
<div class="flex items-center">
<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 }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
<div
class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer"
@click="onAttention(item)"
>
{{ item.attention ? "已关注" : "未关注" }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
<div
v-if="attentionList.length === 0"
class="w-full text-center text-gray-500 font-bold mt-2"
>
暂无数据
</div>
<!-- </div> -->
</n-infinite-scroll>
</n-tab-pane>
<n-tab-pane name="attention" :tab="`关注${selectUserInfo.attention || 0}`">
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<n-infinite-scroll style="height: calc(100vh - 200px); padding:0 10px" :distance="10" @load="getLikeList">
<div
v-for="(item, index) in likeList"
:key="index"
class="flex justify-between items-center p-2"
>
<div class="flex items-center">
<img :src="item.avatar || ''" alt="" class="w-14 h-14 rounded-full mr-2" />
{{ item.nickName }}
</div>
<div class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer" @click="onAttention(item)">
{{ item.attention ? '已关注' : '未关注' }}
</div>
</div>
<div v-if="attentionList.length === 0" class="w-full text-center text-gray-500 font-bold mt-2">
暂无数据
</div>
<!-- </div> -->
</n-infinite-scroll>
<!-- </div> -->
</n-infinite-scroll>
</n-tab-pane>
</n-tabs>
</div>
</div>
<n-tab-pane name="attention" :tab="`关注${selectUserInfo.attention || 0}`">
<!-- <div class="overflow-y-auto h-[calc(100vh-200px)] px-2"> -->
<n-infinite-scroll
style="height: calc(100vh - 200px); padding: 0 10px"
:distance="10"
@load="getLikeList"
>
<div
v-for="(item, index) in likeList"
:key="index"
class="flex justify-between items-center p-2"
>
<div class="flex items-center">
<img
:src="item.avatar || ''"
alt=""
class="w-14 h-14 rounded-full mr-2"
/>
{{ item.nickName }}
</div>
<div
class="bg-[#f4f5f9] px-4 py-2 rounded-full cursor-pointer"
@click="onAttention(item)"
>
{{ item.attention ? "已关注" : "未关注" }}
</div>
</div>
<div
v-if="attentionList.length === 0"
class="w-full text-center text-gray-500 font-bold mt-2"
>
暂无数据
</div>
<!-- </div> -->
</n-infinite-scroll>
</n-tab-pane>
</n-tabs>
</div>
</div>
<n-modal v-model:show="showInvitationModal">
<n-card
style="width: 600px"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<!-- <template #header-extra>
</template> -->
<div class="py-4 flex justify-between">
<div class="text-xl font-bold">邀请列表</div>
<div class="text-sm text-gray-600">
总收益: {{ invitationList.totalAmount }}
</div>
</div>
<div class="rounded-lg">
<div class="flex w-[100%]">
<div class="w-[180px] flex items-center py-2">头像</div>
<div class="w-[180px] flex items-center py-2">邀请人购买数量</div>
<div class="w-[180px] flex items-center py-2">邀请人名字</div>
</div>
<div class="max-h-[500px] overflow-y-auto">
<div
class="flex w-[100%] hover:bg-[#f3f3f3] px-2"
v-for="(item, index) in invitationList.earningsDisplayList"
:key="index"
>
<div class="w-[180px] flex items-center py-2">
<img class="w-10 h-10 rounded-full" :src="item.user.avatar" alt="" />
</div>
<div class="w-[180px] flex items-center py-2">{{ item.count }}</div>
<div class="w-[180px] flex items-center py-2">{{ item.user.userName }}</div>
</div>
</div>
</div>
</n-card>
</n-modal>
</div>
</template>

View File

@ -4,6 +4,7 @@ import EditVersion from "@/components/publishModel/EditVersion.vue";
import UploadImg from "@/components/publishModel/UploadImg.vue";
import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRoute } from "vue-router";
const message = useMessage();
const route = useRoute();
const { type, id } = route.query;
@ -31,6 +32,9 @@ async function initFormData() {
modelVersionList: [
{
objectKey:null,
id:null,
isEncrypt:0,
delFlag: "0", // 0 2
versionName: "", //
modelVersionType: null, //
@ -97,8 +101,24 @@ const timeLineList = ref([
index: 3,
},
]);
function nextStep() {
currentStep.value += 1;
async function nextStep() {
if(currentStep.value === 1){
const name = formData.value.modelProduct.modelName
try {
const res = await request.get(`/file/selectFile?type=model&name=${name}`);
if (res.code == 200) {
if(res.data === 1){ //0 1
currentStep.value += 1;
}else{
message.warning('该模型名称已存在')
}
}
} catch (err) {
console.log(err);
}
}else{
currentStep.value += 1;
}
}
function prevStep() {
currentStep.value -= 1;

View File

@ -24,6 +24,7 @@ async function initFormData() {
},
workFlowVersionList: [
{
id:null,
versionName: "",
hideGenInfo: 0, //
versionDescription: "", //
@ -70,8 +71,21 @@ const currentStep = ref(1);
function handleAddVersion() {
EditVersionRef.value.addVersion();
}
function nextStep() {
currentStep.value += 1;
async function nextStep() {
// currentStep.value += 1;
if(currentStep.value === 1){
const name = formData.value.workFlow.workflowName
try {
const res = await request.get(`/file/selectFile?type=workflow&name=${name}`);
if (res.code == 200) {
currentStep.value += 1;
}
} catch (err) {
console.log(err);
}
}else{
currentStep.value += 1;
}
}
function preStep() {
currentStep.value -= 1;

View File

@ -24,6 +24,7 @@ export const useUserStore = defineStore('user', () => {
function setUserInfo(info: any) {
userInfo.value = info
debugger
}
async function getUserInfo() {
const res = await request.get('/system/user/selectUserById', {
@ -36,6 +37,7 @@ export const useUserStore = defineStore('user', () => {
}
// 登出
function logout() {
console.log('object-------out');
isLoggedIn.value = false
token.value = ''
userInfo.value = {} as UserInfoType

View File

@ -28,12 +28,14 @@ class RequestHttp {
this.instance.interceptors.request.use(
(config:any) => {
const userStore = useUserStore()
const isToken = (config.headers || {}).isToken === false
if (userStore.token && !isToken) {
config.headers.Authorization = `Bearer ${userStore.token}` // 让每个请求携带自定义token 请根据实际情况自行修改
}
// if (userStore.token && !isToken) {
// config.headers.Authorization = `Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjA1NDk1MmNmLTg2YTgtNDZkNC05OWU0LWUzYzU5ODFjZGE2OSJ9.fifWwKgHIswkqGLqp71BWx-UJjv_qYiPO_XeMYt2HkzLfEoDVVpdHysebp_2XNWdjLi4weRga1GzlUBdW_xebw` // 让每个请求携带自定义token 请根据实际情况自行修改
// }
// 开启 loading
if (config.loading) {
loadingBar.start()
@ -59,7 +61,6 @@ class RequestHttp {
this.handleError(data.code)
// token过期以后需要重新登录
if (data.code === 401) {
debugger
// message.error(data.message || '登录已过期,请重新登录')
// const modalStore = useModalStore()
const modalStore = useModalStore();
@ -67,8 +68,8 @@ class RequestHttp {
const userStore = useUserStore()
try {
// eslint-disable-next-line ts/no-use-before-define
await request.post('/logout')
userStore.logout()
// await request.post('/logout')
// userStore.logout()
// navigateTo('/model-square')
}
catch (error) {

View File

@ -57,8 +57,9 @@ export async function uploadFileBatches(files, batchSize = 3) {
uploadResults.push(res.data)
}
catch (error) {
console.error(`文件上传失败: ${file.name}`, error)
uploadResults.push({ success: false, error })
throw new Error(`上传第 ${i + 1} 个文件失败!`);
// console.error(`文件上传失败: ${file.name}`, error)
// uploadResults.push({ success: false, error })
}
}
return uploadResults

View File

@ -83,8 +83,8 @@ export default defineNuxtConfig({
devProxy: {
'/api': {
// target: 'http://1.13.246.108:8080', // 线上
target: 'http://192.168.2.10:8080', // 代
// target: 'http://192.168.1.69:8080', // 嗨
// target: 'http://192.168.2.10:8080', // 代
target: 'http://192.168.2.7:8080', // 嗨
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨
changeOrigin: true,
prependPath: true,